SoW-2020-0002: Trace Hit Counters sow-2020-0002-rev2
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Mon, 8 Mar 2021 20:59:01 +0000 (15:59 -0500)
committerFrancis Deslauriers <francis.deslauriers@efficios.com>
Fri, 9 Apr 2021 20:58:50 +0000 (16:58 -0400)
Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: Id52749b59969276b5390f4494df48940662d5d8c

182 files changed:
.gitignore
DO_NO_MERGE.txt [new file with mode: 0644]
configure.ac
doc/man/Makefile.am
doc/man/lttng-add-map.1.txt [new file with mode: 0644]
doc/man/lttng-add-trigger.1.txt
doc/man/lttng-disable-map.1.txt [new file with mode: 0644]
doc/man/lttng-enable-map.1.txt [new file with mode: 0644]
doc/man/lttng-list.1.txt
doc/man/lttng-view-map.1.txt [new file with mode: 0644]
include/Makefile.am
include/lttng/action/action.h
include/lttng/action/group-internal.h
include/lttng/action/incr-value-internal.h [new file with mode: 0644]
include/lttng/action/incr-value.h [new file with mode: 0644]
include/lttng/condition/condition.h
include/lttng/condition/evaluation-internal.h
include/lttng/condition/event-rule-internal.h [deleted file]
include/lttng/condition/event-rule.h [deleted file]
include/lttng/condition/on-event-internal.h [new file with mode: 0644]
include/lttng/condition/on-event.h [new file with mode: 0644]
include/lttng/event-rule/event-rule.h
include/lttng/event-rule/kernel-function-internal.h [new file with mode: 0644]
include/lttng/event-rule/kernel-function.h [new file with mode: 0644]
include/lttng/event-rule/kernel-probe-internal.h [new file with mode: 0644]
include/lttng/event-rule/kernel-probe.h [new file with mode: 0644]
include/lttng/event-rule/kprobe-internal.h [deleted file]
include/lttng/event-rule/kprobe.h [deleted file]
include/lttng/event-rule/syscall.h
include/lttng/event-rule/tracepoint-internal.h
include/lttng/event-rule/tracepoint.h
include/lttng/event-rule/uprobe-internal.h [deleted file]
include/lttng/event-rule/uprobe.h [deleted file]
include/lttng/event-rule/userspace-probe-internal.h [new file with mode: 0644]
include/lttng/event-rule/userspace-probe.h [new file with mode: 0644]
include/lttng/kernel-function-internal.h [new file with mode: 0644]
include/lttng/kernel-function.h [new file with mode: 0644]
include/lttng/log-level-rule-internal.h [new file with mode: 0644]
include/lttng/log-level-rule.h [new file with mode: 0644]
include/lttng/lttng-error.h
include/lttng/lttng.h
include/lttng/map-key-internal.h [new file with mode: 0644]
include/lttng/map-key.h [new file with mode: 0644]
include/lttng/map/map-internal.h [new file with mode: 0644]
include/lttng/map/map-query-internal.h [new file with mode: 0644]
include/lttng/map/map-query.h [new file with mode: 0644]
include/lttng/map/map.h [new file with mode: 0644]
include/lttng/trigger/trigger-internal.h
src/bin/lttng-sessiond/Makefile.am
src/bin/lttng-sessiond/action-executor.c
src/bin/lttng-sessiond/agent.c
src/bin/lttng-sessiond/buffer-registry.c
src/bin/lttng-sessiond/buffer-registry.h
src/bin/lttng-sessiond/clear.c
src/bin/lttng-sessiond/client.c
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/cmd.h
src/bin/lttng-sessiond/condition-internal.c
src/bin/lttng-sessiond/condition-internal.h
src/bin/lttng-sessiond/dispatch.c
src/bin/lttng-sessiond/event-notifier-error-accounting.c [new file with mode: 0644]
src/bin/lttng-sessiond/event-notifier-error-accounting.h [new file with mode: 0644]
src/bin/lttng-sessiond/event.c
src/bin/lttng-sessiond/event.h
src/bin/lttng-sessiond/kernel.c
src/bin/lttng-sessiond/kernel.h
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/map.c [new file with mode: 0644]
src/bin/lttng-sessiond/map.h [new file with mode: 0644]
src/bin/lttng-sessiond/modprobe.c
src/bin/lttng-sessiond/notification-thread-commands.c
src/bin/lttng-sessiond/notification-thread-commands.h
src/bin/lttng-sessiond/notification-thread-events.c
src/bin/lttng-sessiond/notification-thread-internal.h
src/bin/lttng-sessiond/notification-thread.c
src/bin/lttng-sessiond/register.c
src/bin/lttng-sessiond/save.c
src/bin/lttng-sessiond/session.h
src/bin/lttng-sessiond/sessiond-config.c
src/bin/lttng-sessiond/sessiond-config.h
src/bin/lttng-sessiond/shm.c [deleted file]
src/bin/lttng-sessiond/shm.h [deleted file]
src/bin/lttng-sessiond/testpoint.h
src/bin/lttng-sessiond/trace-kernel.c
src/bin/lttng-sessiond/trace-kernel.h
src/bin/lttng-sessiond/trace-ust.c
src/bin/lttng-sessiond/trace-ust.h
src/bin/lttng-sessiond/ust-abi-internal.h
src/bin/lttng-sessiond/ust-app.c
src/bin/lttng-sessiond/ust-app.h
src/bin/lttng-sessiond/ust-consumer.c
src/bin/lttng-sessiond/ust-ctl-internal.h
src/bin/lttng-sessiond/ust-registry.c
src/bin/lttng-sessiond/ust-registry.h
src/bin/lttng/Makefile.am
src/bin/lttng/command.h
src/bin/lttng/commands/add_map.c [new file with mode: 0644]
src/bin/lttng/commands/add_trigger.c
src/bin/lttng/commands/disable_map.c [new file with mode: 0644]
src/bin/lttng/commands/enable_map.c [new file with mode: 0644]
src/bin/lttng/commands/list.c
src/bin/lttng/commands/list_triggers.c
src/bin/lttng/commands/view_map.c [new file with mode: 0644]
src/bin/lttng/lttng.c
src/common/Makefile.am
src/common/actions/action.c
src/common/actions/group.c
src/common/actions/incr-value.c [new file with mode: 0644]
src/common/conditions/condition.c
src/common/conditions/event-rule.c [deleted file]
src/common/conditions/on-event.c [new file with mode: 0644]
src/common/config/config-session-abi.h
src/common/config/session-config.c
src/common/config/session.xsd
src/common/error.c
src/common/evaluation.c
src/common/event-rule/event-rule.c
src/common/event-rule/kernel-function.c [new file with mode: 0644]
src/common/event-rule/kernel-probe.c [new file with mode: 0644]
src/common/event-rule/kprobe.c [deleted file]
src/common/event-rule/syscall.c
src/common/event-rule/tracepoint.c
src/common/event-rule/uprobe.c [deleted file]
src/common/event-rule/userspace-probe.c [new file with mode: 0644]
src/common/hashtable/hashtable.c
src/common/index-allocator.c [new file with mode: 0644]
src/common/index-allocator.h [new file with mode: 0644]
src/common/kernel-ctl/kernel-ctl.c
src/common/kernel-ctl/kernel-ctl.h
src/common/kernel-ctl/kernel-ioctl.h
src/common/kernel-function.c [new file with mode: 0644]
src/common/log-level-rule.c [new file with mode: 0644]
src/common/lttng-kernel.h
src/common/map-key/map-key.c [new file with mode: 0644]
src/common/map-query.c [new file with mode: 0644]
src/common/map.c [new file with mode: 0644]
src/common/notification.c
src/common/sessiond-comm/sessiond-comm.h
src/common/shm.c [new file with mode: 0644]
src/common/shm.h [new file with mode: 0644]
src/common/trigger.c
src/common/ust-consumer/ust-consumer.c
src/common/utils.c
src/common/utils.h
src/lib/lttng-ctl/lttng-ctl.c
tests/regression/Makefile.am
tests/regression/kernel/Makefile.am
tests/regression/kernel/test_kernel_function [new file with mode: 0755]
tests/regression/tools/Makefile.am
tests/regression/tools/map/Makefile.am [new file with mode: 0644]
tests/regression/tools/map/map_base_test.sh [new file with mode: 0644]
tests/regression/tools/map/test_map_kernel [new file with mode: 0755]
tests/regression/tools/map/test_map_query.c [new file with mode: 0644]
tests/regression/tools/map/test_map_ust [new file with mode: 0755]
tests/regression/tools/notification/Makefile.am
tests/regression/tools/notification/base_client.c
tests/regression/tools/notification/notification.c
tests/regression/tools/notification/sessiond_testpoints.c [new file with mode: 0644]
tests/regression/tools/notification/test_notification_kernel_capture [new file with mode: 0755]
tests/regression/tools/notification/test_notification_multi_app
tests/regression/tools/notification/test_notification_notifier_discarded_count [new file with mode: 0755]
tests/regression/tools/notification/test_notification_ust_capture [new file with mode: 0755]
tests/regression/tools/save-load/Makefile.am
tests/regression/tools/save-load/load-42-maps.lttng [new file with mode: 0644]
tests/regression/tools/save-load/test_load
tests/regression/tools/save-load/test_save
tests/regression/tools/trigger/start-stop/test_start_stop
tests/regression/tools/trigger/test_add_trigger_cli
tests/regression/tools/trigger/test_list_triggers_cli
tests/regression/tools/trigger/test_remove_trigger_cli
tests/regression/tools/trigger/utils/notification-client.c
tests/unit/Makefile.am
tests/unit/test_action.c [new file with mode: 0644]
tests/unit/test_condition.c
tests/unit/test_event_rule.c
tests/unit/test_log_level_rule.c [new file with mode: 0644]
tests/unit/test_map.c [new file with mode: 0644]
tests/unit/test_map_key.c [new file with mode: 0644]
tests/unit/test_map_query.c [new file with mode: 0644]
tests/unit/test_ust_data.c
tests/utils/testapp/gen-syscall-events/gen-syscall-events.c
tests/utils/utils.sh

index 3c76b61f23eb7da9af088ab118c8d938100bcc7f..5e2b0a189ce9ad2ce41ad73dfbc3a7dbecd2d9af 100644 (file)
@@ -148,6 +148,7 @@ health_check
 /tests/unit/test_buffer_view
 /tests/unit/test_kernel_probe
 /tests/unit/test_event_expr_to_bytecode
+/tests/unit/test_log_level_rule
 /tests/utils/testapp/gen-ust-nevents-str/gen-ust-nevents-str
 /tests/utils/testapp/userspace-probe-elf-binary/userspace-probe-elf-binary
 /tests/utils/testapp/userspace-probe-elf-cxx-binary/userspace-probe-elf-cxx-binary
diff --git a/DO_NO_MERGE.txt b/DO_NO_MERGE.txt
new file mode 100644 (file)
index 0000000..4b2b5fa
--- /dev/null
@@ -0,0 +1,3 @@
+captures
+trigger error counter
+map+thc
index 9a40705af52a21f768032d91e62885f787f9fc27..1edbfadd0d010f7b4ab4ed912ff6d44f5973f1e5 100644 (file)
@@ -247,6 +247,7 @@ LTTNG_PTHREAD_GETNAME_NP
 # Check if clock_gettime, timer_create, timer_settime, and timer_delete are available in lib rt, and if so,
 # add -lrt to LIBS
 AC_CHECK_LIB([rt], [clock_gettime, timer_create, timer_settime, timer_delete])
+AC_CHECK_LIB([m], [floor, log10])
 
 # Checks for dl.
 AC_CHECK_LIB([dl], [dlopen], [
@@ -425,6 +426,7 @@ _AC_DEFINE_AND_SUBST([DEFAULT_ROTATE_PENDING_TIMER], [500000])
 
 # Command short descriptions
 _AC_DEFINE_QUOTED_AND_SUBST([CMD_DESCR_ADD_CONTEXT], [Add context fields to a channel])
+_AC_DEFINE_QUOTED_AND_SUBST([CMD_DESCR_ADD_MAP], [Add map])
 _AC_DEFINE_QUOTED_AND_SUBST([CMD_DESCR_CREATE], [Create a tracing session])
 _AC_DEFINE_QUOTED_AND_SUBST([CMD_DESCR_CLEAR], [Clear a tracing session])
 _AC_DEFINE_QUOTED_AND_SUBST([CMD_DESCR_DESTROY], [Tear down tracing sessions])
@@ -1079,6 +1081,9 @@ AC_SUBST(lttngactionincludedir)
 lttngconditionincludedir="${includedir}/lttng/condition"
 AC_SUBST(lttngconditionincludedir)
 
+lttngmapincludedir="${includedir}/lttng/map"
+AC_SUBST(lttngmapincludedir)
+
 lttngnotificationincludedir="${includedir}/lttng/notification"
 AC_SUBST(lttngnotificationincludedir)
 
@@ -1154,6 +1159,7 @@ AC_CONFIG_FILES([
        tests/regression/tools/notification/Makefile
        tests/regression/tools/rotation/Makefile
        tests/regression/tools/base-path/Makefile
+       tests/regression/tools/map/Makefile
        tests/regression/tools/metadata/Makefile
        tests/regression/tools/tracker/Makefile
        tests/regression/tools/working-directory/Makefile
index 5ae6ffbe30da3d4755deed80d5ccfb9e591414f1..5d5599c4049589d386deba05d24c0369a7d8bf20 100644 (file)
@@ -39,7 +39,11 @@ MAN1_NAMES = \
        lttng-clear \
        lttng-add-trigger \
        lttng-remove-trigger \
-       lttng-list-triggers
+       lttng-list-triggers \
+       lttng-add-map \
+       lttng-enable-map \
+       lttng-disable-map \
+       lttng-view-map
 
 MAN3_NAMES =
 MAN8_NAMES = lttng-sessiond lttng-relayd
diff --git a/doc/man/lttng-add-map.1.txt b/doc/man/lttng-add-map.1.txt
new file mode 100644 (file)
index 0000000..e2661d3
--- /dev/null
@@ -0,0 +1,81 @@
+lttng-add-map(1)
+================
+:revdate: 30 Mars 2021
+
+
+NAME
+----
+lttng-add-map - Create LTTng map
+
+
+SYNOPSIS
+--------
+
+Create a Linux kernel map:
+[verse]
+*lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *add-map* option:--kernel
+      [option:--session='SESSION'] [--bitness='BITNESS']
+      [option:--coalesce-hits]
+      [option:--may-key-count='MAX_KEY_COUNT']
+      'MAP'
+
+Create a user space map:
+[verse]
+*lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *add-map* option:--userspace
+      [option:--session='SESSION'] [--bitness='BITNESS']
+      [(option:--per-pid | option:--per-uid)]
+      [option:--coalesce-hits]
+      [option:--may-key-count='MAX_KEY_COUNT']
+      'MAP'
+
+
+DESCRIPTION
+-----------
+
+The `lttng add-map` command is used to create maps.
+
+A map is key-value data structure used to count events occurences. When
+creating a map, many parameters related to this data structure can be
+fine-tuned.
+
+When 'MAP' does not name an existing map, a map named
+'MAP' is created.
+
+OPTIONS
+-------
+
+option:-k, option:--kernel::
+    Create map in the Linux kernel domain.
+
+option:-u, option:--userspace::
+    Create map in the user space domain.
+
+option:-s 'SESSION', option:--session='SESSION'::
+    Create map in the tracing session named 'SESSION'
+    instead of the current tracing session.
+
+option:--bitness='BITNESS'::
+    Set the counter bucket size to BITNESS bits.
+
+option:--coalesce-hits::
+    Coalesces hits from identical event rules.
+
+option:--per-pid::
+    Keep one event counter per process.
+
+option:--per-uid::
+    Keep one event counter for all processes of a single user.
+
+include::common-cmd-help-options.txt[]
+
+include::common-cmd-footer.txt[]
+
+
+SEE ALSO
+--------
+man:lttng-enable-map(1),
+man:lttng-disable-map(1),
+man:lttng-view-map(1),
+man:lttng-list(1),
+man:lttng-add-trigger(1),
+man:lttng(1)
index 393e8c9204d4a0206426b54ce5efe7de89a489a2..b06e865bff34719d1622231ce36401f257fd0cbe 100644 (file)
@@ -1,6 +1,6 @@
 lttng-add-trigger(1)
 =====================
-:revdate: 17 January 2020
+:revdate: 27 May 2020
 
 
 NAME
@@ -56,6 +56,11 @@ Event rule: `on-event [event rule arguments]`::
     - It is not possible to use filter operands that use values from
       the context.
 
++
+Fields to capture can be specified with the option:--capture option, followed by
+a capture expression. Zero or more captures can be configured. See the
+<<capture-expr, Capture expression>> section below for more information.
+
 [[actions]]
 Actions
 ~~~~~~~
@@ -73,6 +78,11 @@ Notify: *notify*::
     Some details about the condition evaluation are sent along with the
     notification.
 
+Increment value: *incr-value* -s sess-name -m map-name --key KEY_FORMAT::
+    This action causes the tracer to increment the value of a counter
+    in a map. If the map is absent or disabled when the condition is met,
+    nothing is done.
+
 Start session: *start-session* session-name::
     This action causes the LTTng session daemon to start tracing for the
     session with the given name.  If no session with the given name exist
@@ -96,6 +106,74 @@ Snapshot session: *snapshot-session* session-name::
     the given name exist at the time the condition is met, nothing is
     done.
 
+
+[[capture-expr]]
+Capture expression
+~~~~~~~~~~~~~~~~~~
+
+A capture expression can be specified with the option:--capture option when
+creating a new on-event condition. If the capture expression corresponds with an
+event's field when tracing, the runtime dynamic value corresponding to the
+capture expression is captured.
+
+NOTE: Make sure to **single-quote** the capture expression when running
+the command from a shell, as capture expressions typically include
+characters having a special meaning for most shells.
+
+* Supported field types:
+ - integer,
+ - unsigned integer,
+ - floating point value,
+ - fixed-size array of integers,
+ - variable-size array of integers (sequence),
+ - enumeration,
+ - text string,
+ - element of any allowing previous type.
+
+* The dynamic value of an event field is captured by using its name as a C
+  identifier.
++
+The square bracket notation is available, like in the C
+language, to access array/sequence field.
+Only a constant, positive integer number can be used within square
+brackets. If the index is out of bounds, the capture expression
+evaluates to `unavailable`.
++
+An enumeration field's value is an integer.
++
+When the capture's field does not exist, the capture expression
+evaluates to `unavailable`.
++
+Examples: `my_field`, `target_cpu`, `seq[7]`
+
+* The dynamic value of a statically-known context field is captured by
+  prefixing its name with `$ctx.`. See man:lttng-add-context(1) to get a list of
+  available contexts.
++
+When the expression's statically-known context field does not exist,
+the capture expression evaluates to `unavailable`.
++
+Examples: `$ctx.prio`, `$ctx.preemptible`,
+`$ctx.perf:cpu:stalled-cycles-frontend`.
++
+NOTE: The statically-known context field does NOT need to be added using the
+man:lttng-add-context(1) command. The statically-known context fields are
+always available in the context of triggers.
+
+* The dynamic value of an application-specific context field is captured by
+  prefixing its name with `$app.` (follows the format used to add such a context
+  field with the man:lttng-add-context(1) command).
++
+When the expression's application-specific context field does not exist,
+the capture expression evaluates to `unavailable`.
++
+Example: `$app.server:cur_user`.
++
+NOTE: The application-specific context field does NOT need to be added using the
+man:lttng-add-context(1) command. The application-specific context fields fields
+are always available in the context of triggers.
+
+
 OPTIONS
 -------
 
diff --git a/doc/man/lttng-disable-map.1.txt b/doc/man/lttng-disable-map.1.txt
new file mode 100644 (file)
index 0000000..a46a2c4
--- /dev/null
@@ -0,0 +1,51 @@
+lttng-disable-map(1)
+====================
+:revdate: 30 Mars 2021
+
+
+NAME
+----
+lttng-disable-map - Disable LTTng map
+
+
+SYNOPSIS
+--------
+
+Disable an existing map:
+
+[verse]
+*lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *disable-map* (option:--userspace | option:--kernel)
+      [option:--session='SESSION'] 'MAP'
+
+
+DESCRIPTION
+-----------
+
+The `lttng disable-map` command is used to disable existing maps. Disabling a
+map prevents any further modification of the content of the map by the tracers
+until it's enabled again using `lttng-enable-map(1)`. Even when disabled, the
+content of the map is available via the `lttng-view-map(1)` command.
+
+OPTIONS
+-------
+option:-k, option:--kernel::
+    Disable map in the Linux kernel domain.
+
+option:-u, option:--userspace::
+    Disable map in the user space domain.
+
+option:-s 'SESSION', option:--session='SESSION'::
+    Disable map in the tracing session named 'SESSION'
+    instead of the current tracing session.
+
+include::common-cmd-help-options.txt[]
+
+include::common-cmd-footer.txt[]
+
+
+SEE ALSO
+--------
+man:lttng-add-map(1),
+man:lttng-enable-map(1),
+man:lttng-view-map(1),
+man:lttng(1)
diff --git a/doc/man/lttng-enable-map.1.txt b/doc/man/lttng-enable-map.1.txt
new file mode 100644 (file)
index 0000000..7b56911
--- /dev/null
@@ -0,0 +1,48 @@
+lttng-enable-map(1)
+===================
+:revdate: 30 Mars 2021
+
+
+NAME
+----
+lttng-enable-map - Enable LTTng map
+
+
+SYNOPSIS
+--------
+
+Enable an existing map:
+
+[verse]
+*lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *enable-map* (option:--userspace | option:--kernel)
+      [option:--session='SESSION'] 'MAP'
+
+
+DESCRIPTION
+-----------
+
+The `lttng enable-map` command is used to enable existing maps.
+
+OPTIONS
+-------
+option:-k, option:--kernel::
+    Enable map in the Linux kernel domain.
+
+option:-u, option:--userspace::
+    Enable map in the user space domain.
+
+option:-s 'SESSION', option:--session='SESSION'::
+    Enable map in the tracing session named 'SESSION'
+    instead of the current tracing session.
+
+include::common-cmd-help-options.txt[]
+
+include::common-cmd-footer.txt[]
+
+
+SEE ALSO
+--------
+man:lttng-add-map(1),
+man:lttng-disable-map(1),
+man:lttng-view-map(1),
+man:lttng(1)
index 0cb19fe4825cd8f0582c3d0110243f6bb2379b88..cbb25137f29b08908390d93099abd23665f6654b 100644 (file)
@@ -5,7 +5,7 @@ lttng-list(1)
 
 NAME
 ----
-lttng-list - List LTTng tracing sessions, domains, channels, and events
+lttng-list - List LTTng tracing sessions, domains, channels, maps, and events
 
 
 SYNOPSIS
@@ -26,10 +26,10 @@ List tracing session's domains:
 [verse]
 *lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *list* option:--domain 'SESSION'
 
-List tracing session's channels and event rules:
+List tracing session's channels, maps, and event rules:
 
 [verse]
-*lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *list* [option:--channel='CHANNEL'] 'SESSION'
+*lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *list* [option:--channel='CHANNEL'] [option:--map='MAP'] 'SESSION'
 
 
 DESCRIPTION
@@ -52,7 +52,7 @@ listed event sources.
 Providing a tracing session name 'SESSION' targets a specific tracing
 session. If the option:--domain option is used, domains containing at
 least one channel in the selected tracing session are listed. Otherwise,
-all the domains, channels, and event rules of the selected tracing
+all the domains, channels, maps, and event rules of the selected tracing
 session are listed along with its details (trace path, for example),
 except when the option:--channel option is used to isolate a specific
 channel by name.
@@ -84,6 +84,9 @@ Target
 option:-c 'CHANNEL', option:--channel='CHANNEL'::
     Only list the details of the channel named 'CHANNEL'.
 
+option:-m 'MAP', option:--map='MAP'::
+    Only list the details of the map named 'MAP'.
+
 
 Listing
 ~~~~~~~
diff --git a/doc/man/lttng-view-map.1.txt b/doc/man/lttng-view-map.1.txt
new file mode 100644 (file)
index 0000000..de7e40e
--- /dev/null
@@ -0,0 +1,58 @@
+lttng-view-map(1)
+=================
+:revdate: 30 Mars 2021
+
+
+NAME
+----
+lttng-view-map - View LTTng map
+
+
+SYNOPSIS
+--------
+
+View the content of a map:
+
+[verse]
+*lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *view-map* [(option:--userspace | option:--kernel)]
+      [option:--session='SESSION'] [option:--key='KEY'] 'MAP'
+
+
+DESCRIPTION
+-----------
+
+The `lttng view-map` command is used to view the content of maps.
+This command prints all the key value pairs contained in this map.
+
+On LTTng-UST maps created with the `--per-pid` option, the content of the map
+of every running applications and the aggregated per-pid map. The aggregated
+per-pid map contains the per-key-value pair sum of the maps of applications
+that exited since the start of the session.
+
+
+OPTIONS
+-------
+option:-k, option:--kernel::
+    View map in the Linux kernel domain.
+
+option:-u, option:--userspace::
+    View map in the user space domain.
+
+option:-s 'SESSION', option:--session='SESSION'::
+    View map in the tracing session named 'SESSION'
+    instead of the current tracing session.
+
+option:--key='KEY'::
+    Only show entries for KEY.
+
+include::common-cmd-help-options.txt[]
+
+include::common-cmd-footer.txt[]
+
+
+SEE ALSO
+--------
+man:lttng-add-map(1),
+man:lttng-enable-map(1),
+man:lttng-disable-map(1),
+man:lttng(1)
index b75602b270ab6773677eb24c34d2db397c802bdf..9405907c29fcc12e25cbc4c233e696871791cbae 100644 (file)
@@ -97,34 +97,40 @@ CLEANFILES = version.i.tmp
 DISTCLEANFILES = version.i
 
 lttnginclude_HEADERS = \
-       lttng/health.h \
-       lttng/lttng.h \
-       lttng/constant.h \
        lttng/channel.h \
+       lttng/clear-handle.h \
+       lttng/clear.h \
+       lttng/constant.h \
+       lttng/destruction-handle.h \
        lttng/domain.h \
-       lttng/event.h \
+       lttng/endpoint.h \
        lttng/event-expr.h \
        lttng/event-field-value.h \
+       lttng/event.h \
        lttng/handle.h \
-       lttng/session.h \
-       lttng/lttng-error.h \
-       lttng/snapshot.h \
-       lttng/save.h \
+       lttng/health.h \
+       lttng/kernel-function.h \
+       lttng/kernel-probe.h \
        lttng/load.h \
-       lttng/endpoint.h \
-       lttng/rotation.h \
        lttng/location.h \
-       lttng/userspace-probe.h \
+       lttng/log-level-rule.h \
+       lttng/map/map.h \
+       lttng/map/map-query.h \
+       lttng/map-key.h \
+       lttng/lttng-error.h \
+       lttng/lttng.h \
+       lttng/rotation.h \
+       lttng/save.h \
        lttng/session-descriptor.h \
-       lttng/destruction-handle.h \
-       lttng/clear.h \
-       lttng/clear-handle.h \
+       lttng/session.h \
+       lttng/snapshot.h \
        lttng/tracker.h \
-       lttng/kernel-probe.h
+       lttng/userspace-probe.h
 
 lttngactioninclude_HEADERS= \
        lttng/action/action.h \
        lttng/action/group.h \
+       lttng/action/incr-value.h \
        lttng/action/notify.h \
        lttng/action/rotate-session.h \
        lttng/action/snapshot-session.h \
@@ -134,7 +140,7 @@ lttngactioninclude_HEADERS= \
 lttngconditioninclude_HEADERS= \
        lttng/condition/condition.h \
        lttng/condition/buffer-usage.h \
-       lttng/condition/event-rule.h \
+       lttng/condition/on-event.h \
        lttng/condition/session-consumed-size.h \
        lttng/condition/session-rotation.h \
        lttng/condition/evaluation.h
@@ -143,54 +149,66 @@ lttngnotificationinclude_HEADERS= \
        lttng/notification/channel.h \
        lttng/notification/notification.h
 
+lttngmapinclude_HEADERS= \
+       lttng/map/map.h \
+       lttng/map/map-query.h
+
 lttngtriggerinclude_HEADERS= \
        lttng/trigger/trigger.h
 
 lttngeventruleinclude_HEADERS= \
        lttng/event-rule/event-rule.h \
-       lttng/event-rule/kprobe.h \
+       lttng/event-rule/kernel-function.h \
+       lttng/event-rule/kernel-probe.h \
        lttng/event-rule/syscall.h \
-       lttng/event-rule/uprobe.h \
+       lttng/event-rule/userspace-probe.h \
        lttng/event-rule/tracepoint.h
 
 noinst_HEADERS = \
-       lttng/snapshot-internal.h \
-       lttng/health-internal.h \
-       lttng/save-internal.h \
-       lttng/load-internal.h \
        lttng/action/action-internal.h \
        lttng/action/group-internal.h \
+       lttng/action/incr-value-internal.h \
        lttng/action/notify-internal.h \
        lttng/action/rotate-session-internal.h \
        lttng/action/snapshot-session-internal.h \
        lttng/action/start-session-internal.h \
        lttng/action/stop-session-internal.h \
-       lttng/condition/condition-internal.h \
+       lttng/channel-internal.h \
        lttng/condition/buffer-usage-internal.h \
-       lttng/condition/event-rule-internal.h \
-       lttng/condition/session-consumed-size-internal.h \
+       lttng/condition/condition-internal.h \
        lttng/condition/evaluation-internal.h \
+       lttng/condition/on-event-internal.h \
+       lttng/condition/session-consumed-size-internal.h \
        lttng/condition/session-rotation-internal.h \
-       lttng/notification/notification-internal.h \
-       lttng/trigger/trigger-internal.h \
-       lttng/endpoint-internal.h \
-       lttng/notification/channel-internal.h \
-       lttng/channel-internal.h \
        lttng/domain-internal.h \
-       lttng/event-internal.h \
+       lttng/endpoint-internal.h \
        lttng/event-expr-internal.h \
        lttng/event-field-value-internal.h \
-       lttng/rotate-internal.h \
-       lttng/ref-internal.h \
-       lttng/location-internal.h \
-       lttng/userspace-probe-internal.h \
-       lttng/session-internal.h \
-       lttng/session-descriptor-internal.h \
-       lttng/kernel-probe-internal.h \
+       lttng/event-internal.h \
        lttng/event-rule/event-rule-internal.h \
-       lttng/event-rule/kprobe-internal.h \
+       lttng/event-rule/kernel-function-internal.h \
+       lttng/event-rule/kernel-probe-internal.h \
        lttng/event-rule/syscall-internal.h \
-       lttng/event-rule/uprobe-internal.h \
        lttng/event-rule/tracepoint-internal.h \
+       lttng/event-rule/userspace-probe-internal.h \
+       lttng/health-internal.h \
+       lttng/kernel-function-internal.h \
+       lttng/kernel-probe-internal.h \
+       lttng/load-internal.h \
+       lttng/location-internal.h \
+       lttng/log-level-rule-internal.h \
+       lttng/map/map-internal.h \
+       lttng/map/map-query-internal.h \
+       lttng/map-key-internal.h \
+       lttng/notification/channel-internal.h \
+       lttng/notification/notification-internal.h \
+       lttng/ref-internal.h \
+       lttng/rotate-internal.h \
+       lttng/save-internal.h \
+       lttng/session-descriptor-internal.h \
+       lttng/session-internal.h \
+       lttng/snapshot-internal.h \
+       lttng/trigger/trigger-internal.h \
+       lttng/userspace-probe-internal.h \
        version.h \
        version.i
index be7e397d0629e6f94091ac4a0eccaf1061366d2b..ad451f219fbaf5db7255d953069807be7ef75fe6 100644 (file)
@@ -22,6 +22,7 @@ enum lttng_action_type {
        LTTNG_ACTION_TYPE_ROTATE_SESSION = 3,
        LTTNG_ACTION_TYPE_SNAPSHOT_SESSION = 4,
        LTTNG_ACTION_TYPE_GROUP = 5,
+       LTTNG_ACTION_TYPE_INCREMENT_VALUE = 6,
 };
 
 enum lttng_action_status {
index cddee55ed99cff01acb81e7e746bc556bd7d424d..d587ef8c92104de8b71cdbd41788574cfd824e39 100644 (file)
@@ -26,4 +26,9 @@ extern ssize_t lttng_action_group_create_from_payload(
                struct lttng_payload_view *view,
                struct lttng_action **group);
 
+LTTNG_HIDDEN
+extern struct lttng_action *lttng_action_group_get_mutable_at_index(
+               struct lttng_action *group,
+               unsigned int index);
+
 #endif /* LTTNG_ACTION_GROUP_INTERNAL_H */
diff --git a/include/lttng/action/incr-value-internal.h b/include/lttng/action/incr-value-internal.h
new file mode 100644 (file)
index 0000000..c98105e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_ACTION_INCR_VALUE_INTERNAL_H
+#define LTTNG_ACTION_INCR_VALUE_INTERNAL_H
+
+#include <inttypes.h>
+
+#include <common/macros.h>
+
+struct lttng_action;
+struct lttng_payload_view;
+struct lttng_map_key;
+
+/*
+ * Create a "incr-value" action from a payload view.
+ *
+ * On success, return the number of bytes consumed from `view`, and the created
+ * action in `*action`. On failure, return -1.
+ */
+LTTNG_HIDDEN
+extern ssize_t lttng_action_incr_value_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_action **action);
+
+LTTNG_HIDDEN
+enum lttng_action_status lttng_action_incr_value_borrow_key_mutable(
+               const struct lttng_action *action, struct lttng_map_key **key);
+
+LTTNG_HIDDEN
+enum lttng_action_status lttng_action_incr_value_set_tracer_token(
+               struct lttng_action *action, uint64_t token);
+
+LTTNG_HIDDEN
+uint64_t lttng_action_incr_value_get_tracer_token(
+               const struct lttng_action *action);
+
+#endif /* LTTNG_ACTION_INCR_VALUE_INTERNAL_H */
diff --git a/include/lttng/action/incr-value.h b/include/lttng/action/incr-value.h
new file mode 100644 (file)
index 0000000..40f1e71
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_ACTION_INCR_VALUE_H
+#define LTTNG_ACTION_INCR_VALUE_H
+
+#include <lttng/action/action.h>
+#include <lttng/map-key.h>
+
+struct lttng_action;
+struct lttng_map_key;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Create a newly allocated incr-value action object.
+ *
+ * Returns a new action on success, NULL on failure. This action must be
+ * destroyed using lttng_action_destroy().
+ */
+extern struct lttng_action *lttng_action_incr_value_create(void);
+
+/*
+ * Set the session name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_INCREMENT_VALUE.
+ */
+extern enum lttng_action_status lttng_action_incr_value_set_session_name(
+               struct lttng_action *action, const char *session_name);
+
+/*
+ * Get the session name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_INCREMENT_VALUE.
+ */
+extern enum lttng_action_status lttng_action_incr_value_get_session_name(
+               const struct lttng_action *action, const char **session_name);
+
+/*
+ * Set the map name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_INCREMENT_VALUE.
+ */
+extern enum lttng_action_status lttng_action_incr_value_set_map_name(
+               struct lttng_action *action, const char *map_name);
+
+/*
+ * Get the map name of an lttng_action object of type
+ * LTTNG_ACTION_TYPE_INCREMENT_VALUE.
+ */
+extern enum lttng_action_status lttng_action_incr_value_get_map_name(
+               const struct lttng_action *action, const char **map_name);
+
+/*
+ * Set key allocation policy for an lttng_action object type
+ * LTTNG_ACTION_TYPE_INCREMENT_VALUE.
+ *
+ * The caller retains ownership of the passed lttng_map_key.
+ */
+extern enum lttng_action_status
+lttng_action_incr_value_set_key(struct lttng_action *action,
+               struct lttng_map_key *key);
+
+/*
+ * Get key allocation policy for an lttng_action object type
+ * LTTNG_ACTION_TYPE_INCREMENT_VALUE.
+ */
+extern enum lttng_action_status
+lttng_action_incr_value_get_key(const struct lttng_action *action,
+               const struct lttng_map_key **key);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_ACTION_INCR_VALUE_H */
index 78a206df3180fd929d3c0b4225ac4f1810cf117f..97be5923daaa02eb5c0b601eb83bf55308a04b09 100644 (file)
@@ -21,7 +21,7 @@ enum lttng_condition_type {
        LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW = 102,
        LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING = 103,
        LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED = 104,
-       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT = 105,
+       LTTNG_CONDITION_TYPE_ON_EVENT = 105,
 };
 
 enum lttng_condition_status {
@@ -30,6 +30,7 @@ enum lttng_condition_status {
        LTTNG_CONDITION_STATUS_UNKNOWN = -2,
        LTTNG_CONDITION_STATUS_INVALID = -3,
        LTTNG_CONDITION_STATUS_UNSET = -4,
+       LTTNG_CONDITION_STATUS_UNSUPPORTED = -4,
 };
 
 /*
index 15ae4af4d05d7205c434e8772f88c3acd4b06406..eaef721fb40b7030930f3fa18dd4cc50b2750d30 100644 (file)
@@ -9,6 +9,7 @@
 #define LTTNG_EVALUATION_INTERNAL_H
 
 #include <lttng/condition/evaluation.h>
+#include <lttng/condition/condition.h>
 #include <common/macros.h>
 #include <stdbool.h>
 #include <sys/types.h>
@@ -38,7 +39,9 @@ void lttng_evaluation_init(struct lttng_evaluation *evaluation,
                enum lttng_condition_type type);
 
 LTTNG_HIDDEN
-ssize_t lttng_evaluation_create_from_payload(struct lttng_payload_view *view,
+ssize_t lttng_evaluation_create_from_payload(
+               const struct lttng_condition *condition,
+               struct lttng_payload_view *view,
                struct lttng_evaluation **evaluation);
 
 LTTNG_HIDDEN
diff --git a/include/lttng/condition/event-rule-internal.h b/include/lttng/condition/event-rule-internal.h
deleted file mode 100644 (file)
index 0f2f3fb..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#ifndef LTTNG_CONDITION_EVENT_RULE_INTERNAL_H
-#define LTTNG_CONDITION_EVENT_RULE_INTERNAL_H
-
-#include <lttng/condition/condition-internal.h>
-#include <common/buffer-view.h>
-#include <common/macros.h>
-#include <lttng/condition/evaluation-internal.h>
-#include <common/dynamic-array.h>
-
-struct lttng_capture_descriptor {
-       struct lttng_event_expr *event_expression;
-       struct lttng_bytecode *bytecode;
-};
-
-struct lttng_condition_event_rule {
-       struct lttng_condition parent;
-       struct lttng_event_rule *rule;
-
-       /* Array of `struct lttng_capture_descriptor *`. */
-       struct lttng_dynamic_pointer_array capture_descriptors;
-};
-
-struct lttng_evaluation_event_rule {
-       struct lttng_evaluation parent;
-       char *name;
-};
-
-struct lttng_evaluation_event_rule_comm {
-       /* Includes the null terminator. */
-       uint32_t trigger_name_length;
-       /* Trigger name. */
-       char payload[];
-} LTTNG_PACKED;
-
-LTTNG_HIDDEN
-ssize_t lttng_condition_event_rule_create_from_payload(
-               struct lttng_payload_view *view,
-               struct lttng_condition **condition);
-
-LTTNG_HIDDEN
-enum lttng_condition_status
-lttng_condition_event_rule_borrow_rule_mutable(
-               const struct lttng_condition *condition,
-               struct lttng_event_rule **rule);
-
-LTTNG_HIDDEN
-struct lttng_evaluation *lttng_evaluation_event_rule_create(
-               const char* trigger_name);
-
-LTTNG_HIDDEN
-ssize_t lttng_evaluation_event_rule_create_from_payload(
-               struct lttng_payload_view *view,
-               struct lttng_evaluation **_evaluation);
-
-LTTNG_HIDDEN
-enum lttng_error_code
-lttng_condition_event_rule_generate_capture_descriptor_bytecode(
-               struct lttng_condition *condition);
-
-LTTNG_HIDDEN
-const struct lttng_bytecode *
-lttng_condition_event_rule_get_capture_bytecode_at_index(
-               const struct lttng_condition *condition, unsigned int index);
-
-#endif /* LTTNG_CONDITION_EVENT_RULE_INTERNAL_H */
diff --git a/include/lttng/condition/event-rule.h b/include/lttng/condition/event-rule.h
deleted file mode 100644 (file)
index 91fce32..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#ifndef LTTNG_CONDITION_EVENT_RULE_H
-#define LTTNG_CONDITION_EVENT_RULE_H
-
-#include <lttng/event-rule/event-rule.h>
-#include <lttng/condition/condition.h>
-#include <lttng/condition/evaluation.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct lttng_event_expr;
-
-/**
- * Event rule conditions allows an action to be taken whenever an event matching
- * the event rule is hit by the tracers.
- *
- * An event rule condition can also specify a payload to be captured at runtime.
- * This is done via the capture descriptor.
- *
- * Note: the dynamic runtime capture of payload is only available for the
- *       trigger notification subsystem.
- */
-
-/*
- * Create a newly allocated event rule condition.
- *
- * Returns a new condition on success, NULL on failure. This condition must be
- * destroyed using lttng_condition_destroy().
- */
-extern struct lttng_condition *lttng_condition_event_rule_create(
-               struct lttng_event_rule *rule);
-
-/*
- * Get the rule property of a event rule condition.
- *
- * The caller does not assume the ownership of the returned rule. The
- * rule shall only be used for the duration of the condition's
- * lifetime.
- *
- * Returns LTTNG_CONDITION_STATUS_OK and a pointer to the condition's rule
- * on success, LTTNG_CONDITION_STATUS_INVALID if an invalid
- * parameter is passed. */
-extern enum lttng_condition_status lttng_condition_event_rule_get_rule(
-                const struct lttng_condition *condition,
-               const struct lttng_event_rule **rule);
-
-/**
- * lttng_evaluation_event_rule_hit are specialised lttng_evaluations which
- * allow users to query a number of properties resulting from the evaluation
- * of a condition which evaluated to true.
- *
- * The evaluation of a event rule hit yields two different results:
- *    TEMPORARY - The name of the triggers associated with the condition.
- *    TODO - The captured event payload if any
- */
-
-/*
- * Get the trigger name property of a event rule hit evaluation.
- *
- * Returns LTTNG_EVALUATION_STATUS_OK on success and a trigger name
- * or LTTNG_EVALUATION_STATUS_INVALID if
- * an invalid parameter is passed.
- */
-extern enum lttng_evaluation_status
-lttng_evaluation_event_rule_get_trigger_name(
-               const struct lttng_evaluation *evaluation,
-               const char **name);
-
-/*
- * Appends (transfering the ownership) the capture descriptor `expr` to
- * the event rule condition `condition`.
- *
- * Returns:
- *
- * `LTTNG_CONDITION_STATUS_OK`:
- *     Success.
- *
- * `LTTNG_CONDITION_STATUS_ERROR`:
- *     Memory error.
- *
- * `LTTNG_CONDITION_STATUS_INVALID`:
- *     * `condition` is `NULL`.
- *     * The type of `condition` is not
- *       `LTTNG_CONDITION_TYPE_EVENT_RULE_HIT`.
- *     * `expr` is `NULL`.
- *     * `expr` is not a locator expression, that is, its type is not
- *       one of:
- *
- *       * `LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD`
- *       * `LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD`
- *       * `LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD`
- *       * `LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT`
- */
-extern enum lttng_condition_status
-lttng_condition_event_rule_append_capture_descriptor(
-               struct lttng_condition *condition,
-               struct lttng_event_expr *expr);
-
-/*
- * Sets `*count` to the number of capture descriptors in the event rule
- * condition `condition`.
- *
- * Returns:
- *
- * `LTTNG_CONDITION_STATUS_OK`:
- *     Success.
- *
- * `LTTNG_CONDITION_STATUS_INVALID`:
- *     * `condition` is `NULL`.
- *     * The type of `condition` is not
- *       `LTTNG_CONDITION_TYPE_EVENT_RULE_HIT`.
- *     * `count` is `NULL`.
- */
-extern enum lttng_condition_status
-lttng_condition_event_rule_get_capture_descriptor_count(
-               const struct lttng_condition *condition, unsigned int *count);
-
-/*
- * Returns the capture descriptor (borrowed) of the event rule condition
- * `condition` at the index `index`, or `NULL` if:
- *
- * * `condition` is `NULL`.
- * * The type of `condition` is not
- *   `LTTNG_CONDITION_TYPE_EVENT_RULE_HIT`.
- * * `index` is greater than or equal to the number of capture
- *   descriptors in `condition` (as returned by
- *   lttng_condition_event_rule_get_capture_descriptor_count()).
- */
-extern const struct lttng_event_expr *
-lttng_condition_event_rule_get_capture_descriptor_at_index(
-               const struct lttng_condition *condition, unsigned int index);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LTTNG_CONDITION_EVENT_RULE_H */
diff --git a/include/lttng/condition/on-event-internal.h b/include/lttng/condition/on-event-internal.h
new file mode 100644 (file)
index 0000000..e19b502
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_CONDITION_ON_EVENT_INTERNAL_H
+#define LTTNG_CONDITION_ON_EVENT_INTERNAL_H
+
+#include <lttng/condition/condition-internal.h>
+#include <common/buffer-view.h>
+#include <common/macros.h>
+#include <common/optional.h>
+#include <lttng/condition/evaluation-internal.h>
+#include <common/dynamic-array.h>
+#include <lttng/event-field-value.h>
+
+struct lttng_capture_descriptor {
+       struct lttng_event_expr *event_expression;
+       struct lttng_bytecode *bytecode;
+};
+
+struct lttng_condition_on_event {
+       struct lttng_condition parent;
+       struct lttng_event_rule *rule;
+
+       LTTNG_OPTIONAL(uint64_t) error_count;
+       /*
+        * Internal use only.
+        * Error accounting counter index.
+        */
+       LTTNG_OPTIONAL(uint64_t) error_counter_index;
+
+       /* Array of `struct lttng_capture_descriptor *`. */
+       struct lttng_dynamic_pointer_array capture_descriptors;
+};
+
+struct lttng_evaluation_event_rule {
+       struct lttng_evaluation parent;
+       char *name;
+
+       /* MessagePack-encoded captured event field values. */
+       struct lttng_dynamic_buffer capture_payload;
+
+       /*
+        * The content of this array event field value is the decoded
+        * version of `capture_payload` above.
+        *
+        * This is a cache: it's not serialized/deserialized in
+        * communications from/to the library and the session daemon.
+        */
+       struct lttng_event_field_value *captured_values;
+};
+
+struct lttng_evaluation_event_rule_comm {
+       /* Includes the null terminator. */
+       uint32_t trigger_name_length;
+       /* Trigger name. */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_on_event_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_condition **condition);
+
+LTTNG_HIDDEN
+enum lttng_condition_status
+lttng_condition_on_event_borrow_rule_mutable(
+               const struct lttng_condition *condition,
+               struct lttng_event_rule **rule);
+
+LTTNG_HIDDEN
+void lttng_condition_on_event_set_error_counter_index(
+               struct lttng_condition *condition, uint64_t error_counter_index);
+
+LTTNG_HIDDEN
+uint64_t lttng_condition_on_event_get_error_counter_index(
+               const struct lttng_condition *condition);
+
+LTTNG_HIDDEN
+uint64_t lttng_condition_on_event_get_error_count(
+               const struct lttng_condition *condition);
+
+LTTNG_HIDDEN
+void lttng_condition_on_event_set_error_count(struct lttng_condition *condition,
+               uint64_t error_count);
+
+LTTNG_HIDDEN
+struct lttng_evaluation *lttng_evaluation_event_rule_create(
+               const struct lttng_condition_on_event *condition,
+               const char* trigger_name,
+               const char *capture_payload, size_t capture_payload_size,
+               bool decode_capture_payload);
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_event_rule_create_from_payload(
+               const struct lttng_condition_on_event *condition,
+               struct lttng_payload_view *view,
+               struct lttng_evaluation **_evaluation);
+
+LTTNG_HIDDEN
+enum lttng_error_code
+lttng_condition_on_event_generate_capture_descriptor_bytecode(
+               struct lttng_condition *condition);
+
+LTTNG_HIDDEN
+const struct lttng_bytecode *
+lttng_condition_on_event_get_capture_bytecode_at_index(
+               const struct lttng_condition *condition, unsigned int index);
+
+#endif /* LTTNG_CONDITION_ON_EVENT_INTERNAL_H */
diff --git a/include/lttng/condition/on-event.h b/include/lttng/condition/on-event.h
new file mode 100644 (file)
index 0000000..ca10781
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_CONDITION_ON_EVENT_H
+#define LTTNG_CONDITION_ON_EVENT_H
+
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/condition/condition.h>
+#include <lttng/condition/evaluation.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_event_expr;
+struct lttng_event_field_value;
+
+/**
+ * Event rule conditions allows an action to be taken whenever an event matching
+ * the event rule is hit by the tracers.
+ *
+ * An event rule condition can also specify a payload to be captured at runtime.
+ * This is done via the capture descriptor.
+ *
+ * Note: the dynamic runtime capture of payload is only available for the
+ *       trigger notification subsystem.
+ */
+
+/*
+ * Create a newly allocated event rule condition.
+ *
+ * Returns a new condition on success, NULL on failure. This condition must be
+ * destroyed using lttng_condition_destroy().
+ */
+extern struct lttng_condition *lttng_condition_on_event_create(
+               struct lttng_event_rule *rule);
+
+/*
+ * Get the rule property of a event rule condition.
+ *
+ * The caller does not assume the ownership of the returned rule. The
+ * rule shall only be used for the duration of the condition's
+ * lifetime.
+ *
+ * Returns LTTNG_CONDITION_STATUS_OK and a pointer to the condition's rule
+ * on success, LTTNG_CONDITION_STATUS_INVALID if an invalid
+ * parameter is passed. */
+extern enum lttng_condition_status lttng_condition_on_event_get_rule(
+               const struct lttng_condition *condition,
+               const struct lttng_event_rule **rule);
+
+/**
+ * lttng_evaluation_event_rule_hit are specialised lttng_evaluations which
+ * allow users to query a number of properties resulting from the evaluation
+ * of a condition which evaluated to true.
+ *
+ * The evaluation of a event rule hit yields two different results:
+ *    TEMPORARY - The name of the triggers associated with the condition.
+ *    TODO - The captured event payload if any
+ */
+
+/*
+ * Get the trigger name property of a event rule hit evaluation.
+ *
+ * Returns LTTNG_EVALUATION_STATUS_OK on success and a trigger name
+ * or LTTNG_EVALUATION_STATUS_INVALID if
+ * an invalid parameter is passed.
+ */
+extern enum lttng_evaluation_status
+lttng_evaluation_event_rule_get_trigger_name(
+               const struct lttng_evaluation *evaluation,
+               const char **name);
+
+/*
+ * Sets `*field_val` to the array event field value of the event rule
+ * condition evaluation `evaluation` which contains its captured values.
+ *
+ * Returns:
+ *
+ * `LTTNG_EVALUATION_STATUS_OK`:
+ *     Success.
+ *
+ *     `*field_val` is an array event field value with a length of at
+ *     least one.
+ *
+ * `LTTNG_EVALUATION_STATUS_INVALID`:
+ *     * `evaluation` is `NULL`.
+ *     * The type of the condition of `evaluation` is not
+ *       `LTTNG_CONDITION_TYPE_ON_EVENT`.
+ *     * The condition of `evaluation` has no capture descriptors.
+ *     * `field_val` is `NULL`.
+ */
+extern enum lttng_evaluation_status
+lttng_evaluation_get_captured_values(
+               const struct lttng_evaluation *evaluation,
+               const struct lttng_event_field_value **field_val);
+
+/*
+ * Appends (transfering the ownership) the capture descriptor `expr` to
+ * the event rule condition `condition`.
+ *
+ * Returns:
+ *
+ * `LTTNG_CONDITION_STATUS_OK`:
+ *     Success.
+ *
+ * `LTTNG_CONDITION_STATUS_ERROR`:
+ *     Memory error.
+ *
+ * `LTTNG_CONDITION_STATUS_INVALID`:
+ *     * `condition` is `NULL`.
+ *     * The type of `condition` is not
+ *       `LTTNG_CONDITION_TYPE_ON_EVENT`.
+ *     * `expr` is `NULL`.
+ *     * `expr` is not a locator expression, that is, its type is not
+ *       one of:
+ *
+ *       * `LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD`
+ *       * `LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD`
+ *       * `LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD`
+ *       * `LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT`
+ * `LTTNG_CONDITION_STATUS_UNSUPPORTED`:
+ *     * The associated event-rule does not support runtime capture.
+ */
+extern enum lttng_condition_status
+lttng_condition_on_event_append_capture_descriptor(
+               struct lttng_condition *condition,
+               struct lttng_event_expr *expr);
+
+/*
+ * Sets `*count` to the number of capture descriptors in the event rule
+ * condition `condition`.
+ *
+ * Returns:
+ *
+ * `LTTNG_CONDITION_STATUS_OK`:
+ *     Success.
+ *
+ * `LTTNG_CONDITION_STATUS_INVALID`:
+ *     * `condition` is `NULL`.
+ *     * The type of `condition` is not
+ *       `LTTNG_CONDITION_TYPE_ON_EVENT`.
+ *     * `count` is `NULL`.
+ */
+extern enum lttng_condition_status
+lttng_condition_on_event_get_capture_descriptor_count(
+               const struct lttng_condition *condition, unsigned int *count);
+
+/*
+ * Returns the capture descriptor (borrowed) of the event rule condition
+ * `condition` at the index `index`, or `NULL` if:
+ *
+ * * `condition` is `NULL`.
+ * * The type of `condition` is not
+ *   `LTTNG_CONDITION_TYPE_ON_EVENT`.
+ * * `index` is greater than or equal to the number of capture
+ *   descriptors in `condition` (as returned by
+ *   lttng_condition_on_event_get_capture_descriptor_count()).
+ */
+extern const struct lttng_event_expr *
+lttng_condition_on_event_get_capture_descriptor_at_index(
+               const struct lttng_condition *condition, unsigned int index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_CONDITION_ON_EVENT_H */
index e097dd488eb38e5fcec809b5f6af1df128903ce1..eec673e007f579b140fcee2899e8be4301a6193b 100644 (file)
@@ -18,9 +18,9 @@ enum lttng_event_rule_type {
        LTTNG_EVENT_RULE_TYPE_UNKNOWN = -1,
        LTTNG_EVENT_RULE_TYPE_TRACEPOINT = 0,
        LTTNG_EVENT_RULE_TYPE_SYSCALL = 1,
-       LTTNG_EVENT_RULE_TYPE_KPROBE = 2,
-       LTTNG_EVENT_RULE_TYPE_KRETPROBE = 3,
-       LTTNG_EVENT_RULE_TYPE_UPROBE = 4,
+       LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE = 2,
+       LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION = 3,
+       LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE = 4,
 };
 
 enum lttng_event_rule_status {
diff --git a/include/lttng/event-rule/kernel-function-internal.h b/include/lttng/event-rule/kernel-function-internal.h
new file mode 100644 (file)
index 0000000..e7a3c38
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_EVENT_RULE_KERNEL_FUNCTION_INTERNAL_H
+#define LTTNG_EVENT_RULE_KERNEL_FUNCTION_INTERNAL_H
+
+#include <common/payload-view.h>
+#include <common/macros.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/kernel-function.h>
+
+struct lttng_event_rule_kernel_function {
+       struct lttng_event_rule parent;
+       char *name;
+       struct lttng_kernel_function_location *location;
+};
+
+struct lttng_event_rule_kernel_function_comm {
+       /* Includes terminator `\0`. */
+       uint32_t name_len;
+       uint32_t location_len;
+       /*
+        * Payload is composed of, in that order:
+        *   - name (null terminated),
+        *   - kernel function location object.
+        */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_kernel_function_create_from_payload(
+               struct lttng_payload_view *payload,
+               struct lttng_event_rule **rule);
+
+#endif /* LTTNG_EVENT_RULE_KERNEL_FUNCTION_INTERNAL_H */
diff --git a/include/lttng/event-rule/kernel-function.h b/include/lttng/event-rule/kernel-function.h
new file mode 100644 (file)
index 0000000..aaa3f75
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_EVENT_RULE_KERNEL_FUNCTION_H
+#define LTTNG_EVENT_RULE_KERNEL_FUNCTION_H
+
+#include <lttng/event-rule/event-rule.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_kernel_function_location;
+
+/*
+ * Create a newly allocated kernel function event rule.
+ *
+ * The location is copied internally.
+ *
+ * Returns a new event rule on success, NULL on failure. The returned event rule
+ * must be destroyed using lttng_event_rule_destroy().
+ */
+extern struct lttng_event_rule *lttng_event_rule_kernel_function_create(
+               const struct lttng_kernel_function_location *location);
+
+/*
+ * Get the kernel function location of a kernel function event rule.
+ *
+ * The caller does not assume the ownership of the returned location.
+ * The location shall only be used for the duration of the event
+ * rule's lifetime, or before a different location is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's location
+ * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is
+ * passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a location was not set prior to
+ * this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kernel_function_get_location(
+               const struct lttng_event_rule *rule,
+               const struct lttng_kernel_function_location **location);
+
+/*
+ * Set the name of a kernel function event rule.
+ *
+ * The name is copied internally.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kernel_function_set_event_name(
+               struct lttng_event_rule *rule, const char *name);
+
+/*
+ * Get the name of a kernel function event rule.
+ *
+ * The caller does not assume the ownership of the returned name.
+ * The name shall only only be used for the duration of the event
+ * rule's lifetime, or before a different name is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's name on
+ * success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is passed,
+ * or LTTNG_EVENT_RULE_STATUS_UNSET if a name was not set prior to this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kernel_function_get_event_name(
+               const struct lttng_event_rule *rule, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_EVENT_RULE_KERNEL_FUNCTION_H */
diff --git a/include/lttng/event-rule/kernel-probe-internal.h b/include/lttng/event-rule/kernel-probe-internal.h
new file mode 100644 (file)
index 0000000..50c02d8
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_EVENT_RULE_KERNEL_PROBE_INTERNAL_H
+#define LTTNG_EVENT_RULE_KERNEL_PROBE_INTERNAL_H
+
+#include <common/payload-view.h>
+#include <common/macros.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/kernel-probe.h>
+
+struct lttng_event_rule_kernel_probe {
+       struct lttng_event_rule parent;
+       char *name;
+       struct lttng_kernel_probe_location *location;
+};
+
+struct lttng_event_rule_kernel_probe_comm {
+       /* Includes terminator `\0`. */
+       uint32_t name_len;
+       uint32_t location_len;
+       /*
+        * Payload is composed of, in that order:
+        *   - name (null terminated),
+        *   - kernel probe location object.
+        */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_kernel_probe_create_from_payload(
+               struct lttng_payload_view *payload,
+               struct lttng_event_rule **rule);
+
+#endif /* LTTNG_EVENT_RULE_KERNEL_PROBE_INTERNAL_H */
diff --git a/include/lttng/event-rule/kernel-probe.h b/include/lttng/event-rule/kernel-probe.h
new file mode 100644 (file)
index 0000000..4efd4d3
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_EVENT_RULE_KERNEL_PROBE_H
+#define LTTNG_EVENT_RULE_KERNEL_PROBE_H
+
+#include <lttng/event-rule/event-rule.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_kernel_probe_location;
+
+/*
+ * Create a newly allocated kprobe event rule.
+ *
+ * The location is copied internally.
+ *
+ * Returns a new event rule on success, NULL on failure. The returned event rule
+ * must be destroyed using lttng_event_rule_destroy().
+ */
+extern struct lttng_event_rule *lttng_event_rule_kernel_probe_create(
+               const struct lttng_kernel_probe_location *location);
+
+/*
+ * Get the kernel probe location of a kprobe event rule.
+ *
+ * The caller does not assume the ownership of the returned location.
+ * The location shall only be used for the duration of the event
+ * rule's lifetime, or before a different location is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's location
+ * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is
+ * passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a location was not set prior to
+ * this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kernel_probe_get_location(
+               const struct lttng_event_rule *rule,
+               const struct lttng_kernel_probe_location **location);
+
+/*
+ * Set the name of a kprobe event rule.
+ *
+ * The name is copied internally.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kernel_probe_set_event_name(
+               struct lttng_event_rule *rule, const char *name);
+
+/*
+ * Get the name of a kprobe event rule.
+ *
+ * The caller does not assume the ownership of the returned name.
+ * The name shall only only be used for the duration of the event
+ * rule's lifetime, or before a different name is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's name on
+ * success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is passed,
+ * or LTTNG_EVENT_RULE_STATUS_UNSET if a name was not set prior to this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_kernel_probe_get_event_name(
+               const struct lttng_event_rule *rule, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_EVENT_RULE_KERNEL_PROBE_H */
diff --git a/include/lttng/event-rule/kprobe-internal.h b/include/lttng/event-rule/kprobe-internal.h
deleted file mode 100644 (file)
index 7d2ecc8..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#ifndef LTTNG_EVENT_RULE_KPROBE_INTERNAL_H
-#define LTTNG_EVENT_RULE_KPROBE_INTERNAL_H
-
-#include <common/payload-view.h>
-#include <common/macros.h>
-#include <lttng/event-rule/event-rule-internal.h>
-#include <lttng/event-rule/kprobe.h>
-
-struct lttng_event_rule_kprobe {
-       struct lttng_event_rule parent;
-       char *name;
-       struct lttng_kernel_probe_location *location;
-};
-
-struct lttng_event_rule_kprobe_comm {
-       /* Includes terminator `\0`. */
-       uint32_t name_len;
-       uint32_t location_len;
-       /*
-        * Payload is composed of, in that order:
-        *   - name (null terminated),
-        *   - kernel probe location object.
-        */
-       char payload[];
-} LTTNG_PACKED;
-
-LTTNG_HIDDEN
-ssize_t lttng_event_rule_kprobe_create_from_payload(
-               struct lttng_payload_view *payload,
-               struct lttng_event_rule **rule);
-
-#endif /* LTTNG_EVENT_RULE_KPROBE_INTERNAL_H */
diff --git a/include/lttng/event-rule/kprobe.h b/include/lttng/event-rule/kprobe.h
deleted file mode 100644 (file)
index e3d7563..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#ifndef LTTNG_EVENT_RULE_KPROBE_H
-#define LTTNG_EVENT_RULE_KPROBE_H
-
-#include <lttng/event-rule/event-rule.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct lttng_kernel_probe_location;
-
-/*
- * Create a newly allocated kprobe event rule.
- *
- * Returns a new event rule on success, NULL on failure. The returned event rule
- * must be destroyed using lttng_event_rule_destroy().
- */
-extern struct lttng_event_rule *lttng_event_rule_kprobe_create(void);
-
-/*
- * Set the kernel probe location of a kprobe event rule.
- *
- * The location is copied internally.
- *
- * Returns LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
- * if invalid parameters are passed.
- */
-extern enum lttng_event_rule_status lttng_event_rule_kprobe_set_location(
-               struct lttng_event_rule *rule,
-               const struct lttng_kernel_probe_location *location);
-
-/*
- * Get the kernel probe location of a kprobe event rule.
- *
- * The caller does not assume the ownership of the returned location.
- * The location shall only be used for the duration of the event
- * rule's lifetime, or before a different location is set.
- *
- * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's location
- * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is
- * passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a location was not set prior to
- * this call.
- */
-extern enum lttng_event_rule_status lttng_event_rule_kprobe_get_location(
-               const struct lttng_event_rule *rule,
-               const struct lttng_kernel_probe_location **location);
-
-/*
- * Set the name of a kprobe event rule.
- *
- * The name is copied internally.
- *
- * Returns LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
- * if invalid parameters are passed.
- */
-extern enum lttng_event_rule_status lttng_event_rule_kprobe_set_name(
-               struct lttng_event_rule *rule, const char *name);
-
-/*
- * Get the name of a kprobe event rule.
- *
- * The caller does not assume the ownership of the returned name.
- * The name shall only only be used for the duration of the event
- * rule's lifetime, or before a different name is set.
- *
- * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's name on
- * success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is passed,
- * or LTTNG_EVENT_RULE_STATUS_UNSET if a name was not set prior to this call.
- */
-extern enum lttng_event_rule_status lttng_event_rule_kprobe_get_name(
-               const struct lttng_event_rule *rule, const char **name);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LTTNG_EVENT_RULE_KPROBE_H */
index baf8432c142597295ee05936edb2f97ffd9837c1..c581b809cf18a5a67993c11043e748525424aa1a 100644 (file)
@@ -17,6 +17,8 @@ extern "C" {
 /*
  * Create a newly allocated syscall event rule.
  *
+ * The default pattern is '*'.
+ *
  * Returns a new event rule on success, NULL on failure. This event rule must be
  * destroyed using lttng_event_rule_destroy().
  */
index 227fe6de92aa1f885e9cdf1160f2c577aabe0211..6c4d438d5d02f63b599be29979d85db1eb60ae6a 100644 (file)
 
 #include <common/payload-view.h>
 #include <common/macros.h>
+#include <common/optional.h>
 #include <lttng/domain.h>
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/event-rule/tracepoint.h>
 #include <lttng/event.h>
+#include <lttng/log-level-rule-internal.h>
 
 struct lttng_event_rule_tracepoint {
        struct lttng_event_rule parent;
@@ -27,11 +29,8 @@ struct lttng_event_rule_tracepoint {
        /* Filter. */
        char *filter_expression;
 
-       /* Loglevel. */
-       struct {
-               enum lttng_loglevel_type type;
-               int value;
-       } loglevel;
+       /* Log level. */
+       struct lttng_log_level_rule *log_level_rule;
 
        /* Exclusions. */
        struct lttng_dynamic_pointer_array exclusions;
@@ -46,19 +45,19 @@ struct lttng_event_rule_tracepoint {
 struct lttng_event_rule_tracepoint_comm {
        /* enum lttng_domain_type. */
        int8_t domain_type;
-       /* enum lttng_event_logleven_type. */
-       int8_t loglevel_type;
-       int32_t loglevel_value;
        /* Includes terminator `\0`. */
        uint32_t pattern_len;
        /* Includes terminator `\0`. */
        uint32_t filter_expression_len;
+       /*  enum lttng_log_level_rule_comm + payload if any */
+       uint32_t log_level_rule_len;
        uint32_t exclusions_count;
        uint32_t exclusions_len;
        /*
         * Payload is composed of, in that order:
         *   - pattern (null terminated),
         *   - filter expression (null terminated),
+        *   - log level rule serialized object,
         *   - exclusions (32 bit length + null terminated string).
         */
        char payload[];
index e24b0fbe103e986ba7551c094c38d604d606ca6e..62c1db38dbc5ec4f37ad496c8d8bef63084325d7 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <lttng/domain.h>
 #include <lttng/event-rule/event-rule.h>
+#include <lttng/log-level-rule.h>
 #include <lttng/event.h>
 
 #ifdef __cplusplus
@@ -19,6 +20,8 @@ extern "C" {
 /*
  * Create a newly allocated tracepoint event rule.
  *
+ * The default pattern is '*'.
+ *
  * Returns a new event rule on success, NULL on failure. This event rule must be
  * destroyed using lttng_event_rule_destroy().
  */
@@ -90,58 +93,31 @@ extern enum lttng_event_rule_status lttng_event_rule_tracepoint_get_filter(
                const struct lttng_event_rule *rule, const char **expression);
 
 /*
- * Set the single log level of a tracepoint event rule.
- *
- * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
- * if invalid parameters are passed.
- */
-extern enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level(
-               struct lttng_event_rule *rule, int level);
-
-/*
- * Set the log level range lower bound of a tracepoint event rule.
+ * Set the log level rule of a tracepoint event rule.
  *
  * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
  * if invalid parameters are passed.
  */
 extern enum lttng_event_rule_status
-lttng_event_rule_tracepoint_set_log_level_range_lower_bound(
-               struct lttng_event_rule *rule, int level);
+lttng_event_rule_tracepoint_set_log_level_rule(struct lttng_event_rule *rule,
+               const struct lttng_log_level_rule *log_level_rule);
 
 /*
- * Set the log level to all of a tracepoint event rule.
+ * Get the log level rule of a tracepoint event rule.
  *
- * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
- * if invalid parameters are passed.
- */
-extern enum lttng_event_rule_status
-lttng_event_rule_tracepoint_set_log_level_all(struct lttng_event_rule *rule);
-
-/*
- * Get the log level type of a tracepoint event rule.
+ * The caller does not assume the ownership of the returned log level rule. The
+ * log level rule shall only only be used for the duration of the event rule's
+ * lifetime, or before a different log level rule is set.
  *
- * Returns LTTNG_EVENT_RULE_STATUS_OK and sets the log level type output
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and sets the log level rule output
  * parameter on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter
- * is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a log level was not set prior
+ * is passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a log level rule was not set prior
  * to this call.
  */
 extern enum lttng_event_rule_status
-lttng_event_rule_tracepoint_get_log_level_type(
+lttng_event_rule_tracepoint_get_log_level_rule(
                const struct lttng_event_rule *rule,
-               enum lttng_loglevel_type *type);
-
-/*
- * Get the log level of a tracepoint event rule.
- *
- * For range log level , the lower bound log level is returned.
- *
- * Returns LTTNG_EVENT_RULE_STATUS_OK and sets the log level output parameter
- * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is
- * passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a log level was not set prior to
- * this call.
- */
-extern enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level(
-               const struct lttng_event_rule *rule, int *level);
+               const struct lttng_log_level_rule **log_level_rule);
 
 /*
  * Add an exclusion to the set of exclusion of an event rule.
diff --git a/include/lttng/event-rule/uprobe-internal.h b/include/lttng/event-rule/uprobe-internal.h
deleted file mode 100644 (file)
index 6d4b106..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#ifndef LTTNG_EVENT_RULE_UPROBE_INTERNAL_H
-#define LTTNG_EVENT_RULE_UPROBE_INTERNAL_H
-
-#include <common/payload-view.h>
-#include <common/macros.h>
-#include <lttng/event-rule/event-rule-internal.h>
-#include <lttng/event-rule/uprobe.h>
-
-struct lttng_event_rule_uprobe {
-       struct lttng_event_rule parent;
-       char *name;
-       struct lttng_userspace_probe_location *location;
-};
-
-struct lttng_event_rule_uprobe_comm {
-       /* Includes terminator `\0`. */
-       uint32_t name_len;
-       /* Includes terminator `\0`. */
-       uint32_t location_len;
-       /*
-        * Payload is composed of, in that order:
-        *   - name (null terminated),
-        *   - user space probe location object.
-        */
-       char payload[];
-} LTTNG_PACKED;
-
-LTTNG_HIDDEN
-ssize_t lttng_event_rule_uprobe_create_from_payload(
-               struct lttng_payload_view *view,
-               struct lttng_event_rule **rule);
-
-LTTNG_HIDDEN
-struct lttng_userspace_probe_location *
-lttng_event_rule_uprobe_get_location_mutable(
-               const struct lttng_event_rule *rule);
-
-#endif /* LTTNG_EVENT_RULE_UPROBE_INTERNAL_H */
diff --git a/include/lttng/event-rule/uprobe.h b/include/lttng/event-rule/uprobe.h
deleted file mode 100644 (file)
index 12aa013..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#ifndef LTTNG_EVENT_RULE_UPROBE_H
-#define LTTNG_EVENT_RULE_UPROBE_H
-
-#include <lttng/event-rule/event-rule.h>
-#include <lttng/userspace-probe.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Create a newly allocated uprobe event rule.
- *
- * 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_uprobe_create(void);
-
-/*
- * Set the location of a uprobe event rule.
- *
- * The location is copied internally.
- *
- * Returns LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
- * if invalid parameters are passed.
- */
-extern enum lttng_event_rule_status lttng_event_rule_uprobe_set_location(
-               struct lttng_event_rule *rule,
-               const struct lttng_userspace_probe_location *location);
-
-/*
- * Get the location of a uprobe event rule.
- *
- * The caller does not assume the ownership of the returned location.
- * The location shall only be used for the duration of the event
- * rule's lifetime, or before a different location is set.
- *
- * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's location
- * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is
- * passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a location was not set prior to
- * this call.
- */
-extern enum lttng_event_rule_status lttng_event_rule_uprobe_get_location(
-               const struct lttng_event_rule *rule,
-               const struct lttng_userspace_probe_location **location);
-
-/*
- * Set the name of a uprobe event rule.
- *
- * The name is copied internally.
- *
- * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
- * if invalid parameters are passed.
- */
-extern enum lttng_event_rule_status lttng_event_rule_uprobe_set_name(
-               struct lttng_event_rule *rule, const char *name);
-
-/*
- * Get the name of a uprobe event rule.
- *
- * The caller does not assume the ownership of the returned name.
- * The name shall only only be used for the duration of the event
- * rule's lifetime, or before a different name is set.
- *
- * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's name on
- * success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is passed,
- * or LTTNG_EVENT_RULE_STATUS_UNSET if a name was not set prior to this call.
- */
-extern enum lttng_event_rule_status lttng_event_rule_uprobe_get_name(
-               const struct lttng_event_rule *rule, const char **name);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LTTNG_EVENT_RULE_UPROBE_H */
diff --git a/include/lttng/event-rule/userspace-probe-internal.h b/include/lttng/event-rule/userspace-probe-internal.h
new file mode 100644 (file)
index 0000000..8ba5b2b
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_EVENT_RULE_USERSPACE_PROBE_INTERNAL_H
+#define LTTNG_EVENT_RULE_USERSPACE_PROBE_INTERNAL_H
+
+#include <common/payload-view.h>
+#include <common/macros.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/userspace-probe.h>
+
+struct lttng_event_rule_userspace_probe {
+       struct lttng_event_rule parent;
+       char *name;
+       struct lttng_userspace_probe_location *location;
+};
+
+struct lttng_event_rule_userspace_probe_comm {
+       /* Includes terminator `\0`. */
+       uint32_t name_len;
+       /* Includes terminator `\0`. */
+       uint32_t location_len;
+       /*
+        * Payload is composed of, in that order:
+        *   - name (null terminated),
+        *   - user space probe location object.
+        */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_userspace_probe_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_event_rule **rule);
+
+LTTNG_HIDDEN
+struct lttng_userspace_probe_location *
+lttng_event_rule_userspace_probe_get_location_mutable(
+               const struct lttng_event_rule *rule);
+
+#endif /* LTTNG_EVENT_RULE_USERSPACE_PROBE_INTERNAL_H */
diff --git a/include/lttng/event-rule/userspace-probe.h b/include/lttng/event-rule/userspace-probe.h
new file mode 100644 (file)
index 0000000..88bc2f4
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_EVENT_RULE_USERSPACE_PROBE_H
+#define LTTNG_EVENT_RULE_USERSPACE_PROBE_H
+
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/userspace-probe.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Create a newly allocated uprobe event rule.
+ *
+ * The location is copied internally.
+ *
+ * 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_userspace_probe_create(
+               const struct lttng_userspace_probe_location *location);
+
+/*
+ * Get the location of a uprobe event rule.
+ *
+ * The caller does not assume the ownership of the returned location.
+ * The location shall only be used for the duration of the event
+ * rule's lifetime, or before a different location is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's location
+ * on success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is
+ * passed, or LTTNG_EVENT_RULE_STATUS_UNSET if a location was not set prior to
+ * this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_userspace_probe_get_location(
+               const struct lttng_event_rule *rule,
+               const struct lttng_userspace_probe_location **location);
+
+/*
+ * Set the name of a uprobe event rule.
+ *
+ * The name is copied internally.
+ *
+ * Return LTTNG_EVENT_RULE_STATUS_OK on success, LTTNG_EVENT_RULE_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_userspace_probe_set_event_name(
+               struct lttng_event_rule *rule, const char *name);
+
+/*
+ * Get the name of a uprobe event rule.
+ *
+ * The caller does not assume the ownership of the returned name.
+ * The name shall only only be used for the duration of the event
+ * rule's lifetime, or before a different name is set.
+ *
+ * Returns LTTNG_EVENT_RULE_STATUS_OK and a pointer to the event rule's name on
+ * success, LTTNG_EVENT_RULE_STATUS_INVALID if an invalid parameter is passed,
+ * or LTTNG_EVENT_RULE_STATUS_UNSET if a name was not set prior to this call.
+ */
+extern enum lttng_event_rule_status lttng_event_rule_userspace_probe_get_event_name(
+               const struct lttng_event_rule *rule, const char **name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_EVENT_RULE_USERSPACE_PROBE_H */
diff --git a/include/lttng/kernel-function-internal.h b/include/lttng/kernel-function-internal.h
new file mode 100644 (file)
index 0000000..f0b412a
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_KERNEL_FUNCTION_INTERNAL_H
+#define LTTNG_KERNEL_FUNCTION_INTERNAL_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <common/fd-handle.h>
+#include <common/macros.h>
+#include <lttng/kernel-function.h>
+
+struct lttng_payload;
+struct lttng_payload_view;
+struct lttng_dynamic_buffer;
+
+typedef bool (*kernel_function_location_equal_cb)(
+               const struct lttng_kernel_function_location *a,
+               const struct lttng_kernel_function_location *b);
+typedef int (*kernel_function_location_serialize_cb)(
+               const struct lttng_kernel_function_location *kernel_function_location,
+               struct lttng_payload *payload);
+typedef bool (*kernel_function_location_equal_cb)(
+               const struct lttng_kernel_function_location *a,
+               const struct lttng_kernel_function_location *b);
+typedef ssize_t (*kernel_function_location_create_from_payload_cb)(
+               struct lttng_payload_view *view,
+               struct lttng_kernel_function_location **kernel_function_location);
+typedef unsigned long (*kernel_function_location_hash_cb)(
+               const struct lttng_kernel_function_location *location);
+
+struct lttng_kernel_function_location_comm {
+       /* enum lttng_kernel_function_location_type */
+       int8_t type;
+       /*
+        * Payload is composed of, in that order,
+        *   - type-specific payload
+        */
+       char payload[];
+} LTTNG_PACKED;
+
+struct lttng_kernel_function_location_symbol_comm {
+       /* Includes the trailing \0. */
+       uint32_t symbol_len;
+       /* The offset from the symbol. */
+       uint64_t offset;
+       /*
+        * Payload is composed of, in that order,
+        *   - symbol name (with trailing \0).
+        */
+       char payload[];
+} LTTNG_PACKED;
+
+struct lttng_kernel_function_location_address_comm {
+       uint64_t address;
+} LTTNG_PACKED;
+
+/* Common ancestor of all kernel function locations. */
+struct lttng_kernel_function_location {
+       enum lttng_kernel_function_location_type type;
+       kernel_function_location_equal_cb equal;
+       kernel_function_location_serialize_cb serialize;
+       kernel_function_location_hash_cb hash;
+};
+
+struct lttng_kernel_function_location_symbol {
+       struct lttng_kernel_function_location parent;
+       char *symbol_name;
+       uint64_t offset;
+};
+
+struct lttng_kernel_function_location_address {
+       struct lttng_kernel_function_location parent;
+       uint64_t address;
+};
+
+LTTNG_HIDDEN
+int lttng_kernel_function_location_serialize(
+               const struct lttng_kernel_function_location *location,
+               struct lttng_payload *payload);
+
+LTTNG_HIDDEN
+ssize_t lttng_kernel_function_location_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_kernel_function_location **function_location);
+
+LTTNG_HIDDEN
+bool lttng_kernel_function_location_is_equal(
+               const struct lttng_kernel_function_location *a,
+               const struct lttng_kernel_function_location *b);
+
+LTTNG_HIDDEN
+struct lttng_kernel_function_location *lttng_kernel_function_location_copy(
+               const struct lttng_kernel_function_location *location);
+
+LTTNG_HIDDEN
+unsigned long lttng_kernel_function_location_hash(
+               const struct lttng_kernel_function_location *location);
+
+#endif /* LTTNG_KERNEL_FUNCTION_INTERNAL_H */
diff --git a/include/lttng/kernel-function.h b/include/lttng/kernel-function.h
new file mode 100644 (file)
index 0000000..f05083f
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_KERNEL_FUNCTION_H
+#define LTTNG_KERNEL_FUNCTION_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_kernel_function_location;
+
+enum lttng_kernel_function_location_status {
+       LTTNG_KERNEL_FUNCTION_LOCATION_STATUS_OK        = 0,
+       /* Invalid parameters provided. */
+       LTTNG_KERNEL_FUNCTION_LOCATION_STATUS_INVALID   = -1,
+};
+
+enum lttng_kernel_function_location_type {
+       LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_UNKNOWN         = -1,
+       /* Location derived from a symbol and an offset. */
+       LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_SYMBOL_OFFSET   = 0,
+       /* Location derived from an address. */
+       LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_ADDRESS         = 1,
+};
+
+/*
+ * Get the type of the kernel function location.
+ */
+extern enum lttng_kernel_function_location_type
+lttng_kernel_function_location_get_type(
+               const struct lttng_kernel_function_location *location);
+
+/*
+ * Destroy the kernel function location.
+ */
+extern void lttng_kernel_function_location_destroy(
+               struct lttng_kernel_function_location *location);
+
+/*
+ * Create a symbol derived function location.
+ * On failure, NULL is returned.
+ */
+extern struct lttng_kernel_function_location *
+lttng_kernel_function_location_symbol_create(const char *symbol_name,
+               uint64_t offset);
+
+/*
+ * Get the symbol name of a symbol derived function location.
+ */
+extern const char *lttng_kernel_function_location_symbol_get_name(
+               const struct lttng_kernel_function_location *location);
+
+/*
+ * Get the offset of a symbol derived location.
+ */
+extern enum lttng_kernel_function_location_status
+lttng_kernel_function_location_symbol_get_offset(
+               const struct lttng_kernel_function_location *location,
+               uint64_t *offset);
+
+/*
+ * Create an address derived function location.
+ * On failure, NULL is returned.
+ */
+extern struct lttng_kernel_function_location *
+lttng_kernel_function_location_address_create(uint64_t address);
+
+/*
+ * Get the address of an address derived function location.
+ */
+extern enum lttng_kernel_function_location_status
+lttng_kernel_function_location_address_get_address(
+               const struct lttng_kernel_function_location *location,
+               uint64_t *offset);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_KERNEL_FUNCTION_H */
diff --git a/include/lttng/log-level-rule-internal.h b/include/lttng/log-level-rule-internal.h
new file mode 100644 (file)
index 0000000..9c5d1f2
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_LOG_LEVEL_RULE_INTERNAL_H
+#define LTTNG_LOG_LEVEL_RULE_INTERNAL_H
+
+#include <stdint.h>
+
+#include <common/buffer-view.h>
+#include <common/dynamic-array.h>
+#include <common/macros.h>
+#include <common/payload-view.h>
+#include <common/payload.h>
+#include <lttng/event.h>
+#include <lttng/log-level-rule.h>
+
+/*
+ * For now only a single backing struct is used for both type of log level
+ * rule (exactly, as_severe) since both only have a "level" as property.
+ */
+struct lttng_log_level_rule {
+       enum lttng_log_level_rule_type type;
+
+       /* Property */
+       int level;
+};
+
+struct lttng_log_level_rule_comm {
+       /* enum lttng_log_level_rule_type */
+       int8_t type;
+       int32_t level;
+};
+
+LTTNG_HIDDEN
+ssize_t lttng_log_level_rule_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_log_level_rule **rule);
+
+LTTNG_HIDDEN
+int lttng_log_level_rule_serialize(const struct lttng_log_level_rule *rule,
+               struct lttng_payload *payload);
+
+LTTNG_HIDDEN
+bool lttng_log_level_rule_is_equal(const struct lttng_log_level_rule *a,
+               const struct lttng_log_level_rule *b);
+
+LTTNG_HIDDEN
+struct lttng_log_level_rule *lttng_log_level_rule_copy(
+               const struct lttng_log_level_rule *source);
+
+LTTNG_HIDDEN
+void lttng_log_level_rule_to_loglevel(
+               const struct lttng_log_level_rule *log_level_rule,
+               enum lttng_loglevel_type *loglevel_type,
+               int *loglevel_value);
+LTTNG_HIDDEN
+unsigned long lttng_log_level_rule_hash(
+               const struct lttng_log_level_rule *log_level_rule);
+
+#endif /* LTTNG_LOG_LEVEL_RULE_INTERNAL_H */
diff --git a/include/lttng/log-level-rule.h b/include/lttng/log-level-rule.h
new file mode 100644 (file)
index 0000000..d993163
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_LOG_LEVEL_RULE_H
+#define LTTNG_LOG_LEVEL_RULE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_log_level_rule;
+
+enum lttng_log_level_rule_type {
+       LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN = -1,
+       LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY = 0,
+       LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS = 1,
+};
+
+enum lttng_log_level_rule_status {
+       LTTNG_LOG_LEVEL_RULE_STATUS_OK = 0,
+       LTTNG_LOG_LEVEL_RULE_STATUS_ERROR = -1,
+       LTTNG_LOG_LEVEL_RULE_STATUS_INVALID = -3,
+};
+
+/*
+ * Get the type of a log level rule.
+ *
+ * Returns the type of a log level rule on success,
+ * LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN on error.
+ */
+extern enum lttng_log_level_rule_type lttng_log_level_rule_get_type(
+               const struct lttng_log_level_rule *rule);
+
+/*
+ * Create a newly allocated log level rule where a log level must match exactly
+ * the rule to be considered.
+ *
+ * Returns a new log level rule on success, NULL on failure. This log level rule must be
+ * destroyed using lttng_log_level_rule_destroy().
+ */
+extern struct lttng_log_level_rule *lttng_log_level_rule_exactly_create(
+               int level);
+
+/*
+ * Get the level property of a log level exactly rule.
+ *
+ * Returns LTTNG_LOG_LEVEL_RULE_STATUS and set the passed level pointer value
+ * on success, LTTNG_LOG_LEVEL_RULE_STATUS if an invalid
+ * parameter is passed.
+ */
+extern enum lttng_log_level_rule_status lttng_log_level_rule_exactly_get_level(
+               const struct lttng_log_level_rule *rule, int *level);
+
+/*
+ * Create a newly allocated log level rule where a log level must be at least as
+ * severe as the rule to be considered.
+ *
+ * Returns a new log level rule on success, NULL on failure. This log level rule
+ * must be destroyed using lttng_log_level_rule_destroy().
+ */
+extern struct lttng_log_level_rule *
+lttng_log_level_rule_at_least_as_severe_as_create(int level);
+
+/*
+ * Get the level property of a log level at least as severe rule.
+ *
+ * Returns LTTNG_LOG_LEVEL_RULE_STATUS and set the passed level pointer value
+ * on success, LTTNG_LOG_LEVEL_RULE_STATUS if an invalid
+ * parameter is passed.
+ */
+extern enum lttng_log_level_rule_status
+lttng_log_level_rule_at_least_as_severe_as_get_level(
+               const struct lttng_log_level_rule *rule, int *level);
+
+/*
+ * Destroy (release) a log level rule object.
+ */
+extern void lttng_log_level_rule_destroy(struct lttng_log_level_rule *log_level_rule);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_LOG_LEVEL_RULE_H */
index 606d8b0b28a0c0a29b4bed5cf15c8ca899388f6f..38b03550f8cff6e071a66f867e0ffa9a3794a610 100644 (file)
@@ -176,6 +176,20 @@ enum lttng_error_code {
        LTTNG_ERR_PROCESS_ATTR_TRACKER_INVALID_TRACKING_POLICY = 163, /* Operation does not apply to the process attribute tracker's tracking policy */
        LTTNG_ERR_EVENT_NOTIFIER_GROUP_NOTIFICATION_FD = 164, /* Error initializing event notifier group notification file descriptor */
        LTTNG_ERR_INVALID_CAPTURE_EXPRESSION = 165, /* Invalid capture expression. */
+       LTTNG_ERR_EVENT_NOTIFIER_REGISTRATION = 166, /* Error registering event notifier to the tracer. */
+       LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING = 167, /* Error initializing event notifier error accounting. */
+       LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING_FULL = 168, /* Error event notifier error accounting full. */
+       LTTNG_ERR_INVALID_MAP = 169, /* Invalid map provided. */
+       LTTNG_ERR_MAP_NOT_FOUND = 170, /* Map by name not found. */
+       LTTNG_ERR_UST_MAP_ENABLE_FAIL  = 171,  /* UST enable map failed */
+       LTTNG_ERR_UST_MAP_DISABLE_FAIL  = 172,  /* UST disable map failed */
+       LTTNG_ERR_UST_MAP_NOT_FOUND     = 173,  /* UST map not found */
+       LTTNG_ERR_UST_MAP_EXIST         = 174,  /* UST map already exist */
+       LTTNG_ERR_KERNEL_MAP_ENABLE_FAIL  = 175,  /* Kernel enable map failed */
+       LTTNG_ERR_KERNEL_MAP_DISABLE_FAIL  = 176,  /* Kernel disable map failed */
+       LTTNG_ERR_KERNEL_MAP_NOT_FOUND     = 177,  /* Kernel map not found */
+       LTTNG_ERR_KERNEL_MAP_EXIST         = 178,  /* Kernel map already exist */
+       LTTNG_ERR_MAP_VALUES_LIST_FAIL = 179,  /* Listing map values failed */
 
        /* MUST be last element of the manually-assigned section of the enum */
        LTTNG_ERR_NR,
index c665d3c9bcaabb40737d47cceaae841ff04abfdf..86db9945a277b68af3807e08ba161f1e75811362 100644 (file)
@@ -18,6 +18,7 @@
 /* Include every LTTng ABI/API available. */
 #include <lttng/action/action.h>
 #include <lttng/action/group.h>
+#include <lttng/action/incr-value.h>
 #include <lttng/action/notify.h>
 #include <lttng/action/rotate-session.h>
 #include <lttng/action/snapshot-session.h>
@@ -29,7 +30,7 @@
 #include <lttng/condition/buffer-usage.h>
 #include <lttng/condition/condition.h>
 #include <lttng/condition/evaluation.h>
-#include <lttng/condition/event-rule.h>
+#include <lttng/condition/on-event.h>
 #include <lttng/condition/session-consumed-size.h>
 #include <lttng/condition/session-rotation.h>
 #include <lttng/constant.h>
 #include <lttng/event-expr.h>
 #include <lttng/event-field-value.h>
 #include <lttng/event-rule/event-rule.h>
-#include <lttng/event-rule/kprobe.h>
+#include <lttng/event-rule/kernel-probe.h>
 #include <lttng/event-rule/syscall.h>
 #include <lttng/event-rule/tracepoint.h>
-#include <lttng/event-rule/uprobe.h>
+#include <lttng/event-rule/userspace-probe.h>
 #include <lttng/handle.h>
 #include <lttng/health.h>
 #include <lttng/kernel-probe.h>
 #include <lttng/load.h>
 #include <lttng/location.h>
+#include <lttng/map/map.h>
 #include <lttng/lttng-error.h>
+#include <lttng/log-level-rule.h>
 #include <lttng/notification/channel.h>
 #include <lttng/notification/notification.h>
 #include <lttng/rotation.h>
diff --git a/include/lttng/map-key-internal.h b/include/lttng/map-key-internal.h
new file mode 100644 (file)
index 0000000..84c2580
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+#ifndef LTTNG_MAP_KEY_INTERNAL_H
+#define LTTNG_MAP_KEY_INTERNAL_H
+
+#include <common/dynamic-array.h>
+#include <common/macros.h>
+#include <stdbool.h>
+#include <urcu/ref.h>
+
+#include <lttng/map-key.h>
+
+struct lttng_payload;
+struct lttng_payload_view;
+struct lttng_map_key_token;
+
+typedef bool (*map_key_token_equal_cb)(const struct lttng_map_key_token *a,
+               const struct lttng_map_key_token *b);
+
+enum lttng_map_key_token_type {
+       LTTNG_MAP_KEY_TOKEN_TYPE_STRING,
+       LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE,
+};
+
+struct lttng_map_key_token {
+       enum lttng_map_key_token_type type;
+       map_key_token_equal_cb equal;
+};
+
+struct lttng_map_key_token_comm {
+       uint8_t type;
+};
+
+struct lttng_map_key_token_string {
+       struct lttng_map_key_token parent;
+       char *string;
+};
+
+struct lttng_map_key_token_string_comm {
+       uint8_t parent_type;
+
+       /* Includes null terminator. */
+       uint32_t string_len;
+
+       char payload[];
+};
+
+struct lttng_map_key_token_variable {
+       struct lttng_map_key_token parent;
+       enum lttng_map_key_token_variable_type type;
+};
+
+struct lttng_map_key_token_variable_comm {
+       uint8_t parent_type;
+       uint8_t var_type;
+};
+
+struct lttng_map_key {
+       /* Reference counting is only exposed to internal users*/
+       struct urcu_ref ref;
+       /* Array of `struct lttng_map_key_token` */
+       struct lttng_dynamic_pointer_array tokens;
+};
+
+struct lttng_map_key_comm {
+       uint32_t token_count;
+       /* Array of `struct lttng_map_key_token` */
+       char payload[];
+};
+
+LTTNG_HIDDEN
+void lttng_map_key_get(struct lttng_map_key *key);
+
+LTTNG_HIDDEN
+void lttng_map_key_put(struct lttng_map_key *key);
+
+LTTNG_HIDDEN
+ssize_t lttng_map_key_create_from_payload(struct lttng_payload_view *view,
+               struct lttng_map_key **key);
+
+LTTNG_HIDDEN
+int lttng_map_key_serialize(const struct lttng_map_key *key,
+               struct lttng_payload *payload);
+
+LTTNG_HIDDEN
+enum lttng_map_key_status lttng_map_key_get_token_count(
+               const struct lttng_map_key *key, unsigned int *count);
+
+LTTNG_HIDDEN
+const struct lttng_map_key_token *lttng_map_key_get_token_at_index(
+               const struct lttng_map_key *key, unsigned int index);
+
+LTTNG_HIDDEN
+enum lttng_map_key_token_variable_type lttng_map_key_token_variable_get_type(
+               const struct lttng_map_key_token_variable *token);
+
+LTTNG_HIDDEN
+const char *lttng_map_key_token_string_get_string(
+               const struct lttng_map_key_token_string *token);
+
+LTTNG_HIDDEN
+bool lttng_map_key_is_equal(
+               const struct lttng_map_key *a, const struct lttng_map_key *b);
+
+LTTNG_HIDDEN
+void lttng_map_key_get(struct lttng_map_key *key);
+
+LTTNG_HIDDEN
+void lttng_map_key_put(struct lttng_map_key *key);
+
+LTTNG_HIDDEN
+struct lttng_map_key *lttng_map_key_parse_from_string(const char *key_str);
+
+#endif /* LTTNG_MAP_KEY_INTERNAL_H */
diff --git a/include/lttng/map-key.h b/include/lttng/map-key.h
new file mode 100644 (file)
index 0000000..be56948
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_MAP_KEY_H
+#define LTTNG_MAP_KEY_H
+
+struct lttng_map_key;
+
+enum lttng_map_key_status {
+       LTTNG_MAP_KEY_STATUS_ERROR = -2,
+       LTTNG_MAP_KEY_STATUS_INVALID = -1,
+       LTTNG_MAP_KEY_STATUS_OK = 0,
+};
+
+enum lttng_map_key_token_variable_type {
+       LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME,
+       LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME,
+};
+
+struct lttng_map_key *lttng_map_key_create(void);
+
+enum lttng_map_key_status lttng_map_key_append_token_variable(
+               struct lttng_map_key *key,
+               enum lttng_map_key_token_variable_type var_type);
+
+enum lttng_map_key_status lttng_map_key_append_token_string(
+               struct lttng_map_key *key, const char *string);
+
+void lttng_map_key_destroy(struct lttng_map_key *key);
+
+#endif /* LTTNG_MAP_KEY_H */
diff --git a/include/lttng/map/map-internal.h b/include/lttng/map/map-internal.h
new file mode 100644 (file)
index 0000000..45aae76
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_MAP_INTERNAL_H
+#define LTTNG_MAP_INTERNAL_H
+
+#include <common/macros.h>
+#include <common/optional.h>
+#include <common/payload.h>
+#include <common/payload-view.h>
+#include <urcu/ref.h>
+
+#include "map.h"
+
+struct lttng_payload;
+struct lttng_payload_view;
+
+struct lttng_map {
+       /* Reference counting is only exposed to internal users. */
+       struct urcu_ref ref;
+
+       char *name;
+       LTTNG_OPTIONAL(bool) is_enabled;
+       enum lttng_map_bitness bitness;
+       enum lttng_map_boundary_policy boundary_policy;
+       enum lttng_domain_type domain;
+       enum lttng_buffer_type buffer_type;
+       bool coalesce_hits;
+       unsigned int dimension_count;
+       uint64_t *dimension_sizes;
+};
+
+struct lttng_map_list {
+       struct lttng_dynamic_pointer_array array;
+};
+
+struct lttng_map_key_value_pair {
+       char *key;
+       int64_t value;
+       bool has_overflowed;
+       bool has_underflowed;
+};
+
+struct lttng_map_key_value_pair_list {
+       enum lttng_map_key_value_pair_list_type type;
+       uint64_t id; /* pid_t or uid_t */
+       uint64_t cpu;
+       bool summed_all_cpus;
+       struct lttng_dynamic_pointer_array array;
+};
+
+struct lttng_map_content {
+       enum lttng_buffer_type type;
+       struct lttng_dynamic_pointer_array array;
+};
+
+struct lttng_map_comm {
+       uint32_t name_length /* Includes '\0' */;
+       uint32_t length;
+       uint8_t is_enabled;
+       uint8_t bitness;
+       uint8_t boundary_policy;
+       uint8_t domain;
+       uint8_t buffer_type;
+       uint8_t coalesce_hits;;
+       uint64_t dimension_count;
+
+       /* length excludes its own length. */
+       /* A name and dimension sizes follow. */
+       char payload[];
+} LTTNG_PACKED;
+
+struct lttng_map_list_comm {
+       uint32_t count;
+       /* Count * lttng_map_comm structure */
+       char payload[];
+} LTTNG_PACKED;
+
+struct lttng_map_key_value_pair_comm {
+       uint32_t key_length /* Includes '\0' */;
+       int64_t value;
+       uint8_t has_overflowed;
+       uint8_t has_underflowed;
+} LTTNG_PACKED;
+
+struct lttng_map_key_value_pair_list_comm {
+       uint32_t count;
+       uint8_t type; /* enum lttng_map_key_value_pair_list_type */
+       uint64_t id; /* pid_t or uid_t */
+       uint64_t cpu;
+       uint8_t summed_all_cpus;
+       /* Count * lttng_map_key_value_pair_comm structure */
+       char payload[];
+} LTTNG_PACKED;
+
+struct lttng_map_content_comm {
+       uint32_t count;
+       uint8_t type; /* enum lttng_buffer_type */
+       /* Count * lttng_map_key_value_pair_list structure */
+       char payload[];
+};
+
+LTTNG_HIDDEN
+ssize_t lttng_map_create_from_payload(struct lttng_payload_view *view,
+               struct lttng_map **map);
+
+LTTNG_HIDDEN
+int lttng_map_serialize(const struct lttng_map *map,
+               struct lttng_payload *payload);
+
+LTTNG_HIDDEN
+void lttng_map_get(struct lttng_map *map);
+
+LTTNG_HIDDEN
+void lttng_map_put(struct lttng_map *map);
+
+LTTNG_HIDDEN
+void lttng_map_set_is_enabled(struct lttng_map *map, bool enabled);
+
+/*
+ * Allocate a new list of maps.
+ * The returned object must be freed via lttng_map_list_destroy.
+ */
+LTTNG_HIDDEN
+struct lttng_map_list *lttng_map_list_create(void);
+
+/*
+ * Add a map to the maps set.
+ *
+ * A reference to the added map is acquired on behalf of the map set
+ * on success.
+ */
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_list_add(struct lttng_map_list *map_list,
+               struct lttng_map *map);
+
+LTTNG_HIDDEN
+ssize_t lttng_map_list_create_from_payload(struct lttng_payload_view *view,
+               struct lttng_map_list **map_list);
+
+/*
+ * Serialize a map list to an lttng_payload object.
+ * Return LTTNG_OK on success, negative lttng error code on error.
+ */
+LTTNG_HIDDEN
+int lttng_map_list_serialize(const struct lttng_map_list *map_list,
+               struct lttng_payload *payload);
+
+LTTNG_HIDDEN
+struct lttng_map_key_value_pair *lttng_map_key_value_pair_create(
+               const char *key, int64_t value);
+
+LTTNG_HIDDEN
+void lttng_map_key_value_pair_set_has_overflowed(
+               struct lttng_map_key_value_pair *key_value);
+
+LTTNG_HIDDEN
+void lttng_map_key_value_pair_set_has_underflowed(
+               struct lttng_map_key_value_pair *key_value);
+
+LTTNG_HIDDEN
+ssize_t lttng_map_key_value_pair_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_map_key_value_pair **key_value);
+
+LTTNG_HIDDEN
+int lttng_map_key_value_pair_serialize(
+               const struct lttng_map_key_value_pair *key_value,
+               struct lttng_payload *payload);
+
+LTTNG_HIDDEN
+void lttng_map_key_value_pair_destroy(
+               struct lttng_map_key_value_pair *key_value);
+
+LTTNG_HIDDEN
+struct lttng_map_key_value_pair_list *lttng_map_key_value_pair_list_create(
+               enum lttng_map_key_value_pair_list_type type,
+               bool summed_all_cpus);
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_key_value_pair_list_set_identifier(
+               struct lttng_map_key_value_pair_list *kv_pair_list,
+               uint64_t identifier);
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_key_value_pair_list_set_cpu(
+               struct lttng_map_key_value_pair_list *kv_pair_list,
+               uint64_t cpu);
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_key_value_pair_list_append_key_value(
+               struct lttng_map_key_value_pair_list *key_values,
+               struct lttng_map_key_value_pair *key_value);
+
+LTTNG_HIDDEN
+ssize_t lttng_map_key_value_pair_list_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_map_key_value_pair_list **key_values);
+
+LTTNG_HIDDEN
+int lttng_map_key_value_pair_list_serialize(
+               const struct lttng_map_key_value_pair_list *key_values,
+               struct lttng_payload *payload);
+
+LTTNG_HIDDEN
+struct lttng_map_content *lttng_map_content_create(
+               enum lttng_buffer_type type);
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_content_append_key_value_list(
+               struct lttng_map_content *map_content,
+               struct lttng_map_key_value_pair_list *kv_list);
+
+LTTNG_HIDDEN
+ssize_t lttng_map_content_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_map_content **map_content);
+
+LTTNG_HIDDEN
+int lttng_map_content_serialize(
+               const struct lttng_map_content *map_content,
+               struct lttng_payload *payload);
+
+#endif /* LTTNG_MAP_INTERNAL_H */
diff --git a/include/lttng/map/map-query-internal.h b/include/lttng/map/map-query-internal.h
new file mode 100644 (file)
index 0000000..47c7e5f
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_MAP_QUERY_INTERNAL_H
+#define LTTNG_MAP_QUERY_INTERNAL_H
+
+#include <stdint.h>
+
+#include <common/payload.h>
+#include <common/payload-view.h>
+
+#include <lttng/lttng.h>
+#include <lttng/map/map-query.h>
+
+struct lttng_map_query {
+       enum lttng_map_query_config_cpu config_cpu;
+       enum lttng_map_query_config_buffer config_buffer;
+       enum lttng_map_query_config_app_bitness config_bitness;
+
+       /*
+        * Aggregate the values of all selected CPUs in a single table.
+        */
+       bool sum_by_cpu;
+
+       /*
+        * Aggregate the values of all selected bitness in a single table.
+        */
+       bool sum_by_app_bitness;
+
+       /*
+        * Aggregate the values of all selected uid or pid in a single table.
+        */
+       bool sum_by_uid;
+       bool sum_by_pid;
+
+       char *key_filter;
+       struct lttng_dynamic_array cpu_array;
+       struct lttng_dynamic_array uid_array;
+       struct lttng_dynamic_array pid_array;
+};
+
+struct lttng_map_query_comm {
+       uint32_t key_filter_length; /* Include '\0' */
+
+       uint8_t config_cpu;
+       uint8_t config_buffer;
+       uint8_t config_app_bitness;
+
+       uint8_t sum_by_cpu;
+       uint8_t sum_by_app_bitness;
+       uint8_t sum_by_uid;
+       uint8_t sum_by_pid;
+
+       uint32_t cpu_count;
+       uint32_t uid_count;
+       uint32_t pid_count;
+       /*
+        * key_filter +
+        * (cpu_count * int) + (uid_count * uid_t) + (pid_count * pid_t)
+        */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+enum lttng_map_query_config_cpu lttng_map_query_get_config_cpu(
+               const struct lttng_map_query *query);
+
+LTTNG_HIDDEN
+enum lttng_map_query_config_buffer lttng_map_query_get_config_buffer(
+               const struct lttng_map_query *query);
+
+LTTNG_HIDDEN
+enum lttng_map_query_config_app_bitness lttng_map_query_get_config_app_bitness(
+               const struct lttng_map_query *query);
+
+LTTNG_HIDDEN
+bool lttng_map_query_get_config_sum_by_cpu(
+               const struct lttng_map_query *query);
+
+LTTNG_HIDDEN
+bool lttng_map_query_get_config_sum_by_pid(
+               const struct lttng_map_query *query);
+
+LTTNG_HIDDEN
+bool lttng_map_query_get_config_sum_by_uid(
+               const struct lttng_map_query *query);
+
+// Not supported yet.
+LTTNG_HIDDEN
+enum lttng_map_query_status lttng_map_query_set_sum_by_app_bitness(
+               struct lttng_map_query *query, bool sum_by_app_bitness);
+
+// Not supported yet.
+LTTNG_HIDDEN
+enum lttng_map_query_status lttng_map_query_set_sum_by_uid(
+               struct lttng_map_query *query, bool sum_by_uid);
+
+LTTNG_HIDDEN
+bool lttng_map_query_get_config_sum_by_app_bitness(
+               const struct lttng_map_query *query);
+
+LTTNG_HIDDEN
+enum lttng_map_query_status lttng_map_query_get_cpu_count(
+               const struct lttng_map_query *query, unsigned int *count);
+
+LTTNG_HIDDEN
+enum lttng_map_query_status lttng_map_query_get_uid_count(
+               const struct lttng_map_query *query, unsigned int *count);
+
+LTTNG_HIDDEN
+enum lttng_map_query_status lttng_map_query_get_pid_count(
+               const struct lttng_map_query *query, unsigned int *count);
+
+LTTNG_HIDDEN
+enum lttng_map_query_status lttng_map_query_get_cpu_at_index(
+               const struct lttng_map_query *query, unsigned int index,
+               int *cpu);
+
+LTTNG_HIDDEN
+enum lttng_map_query_status lttng_map_query_get_uid_at_index(
+               const struct lttng_map_query *query, unsigned int index,
+               uid_t *uid);
+
+LTTNG_HIDDEN
+enum lttng_map_query_status lttng_map_query_get_pid_at_index(
+               const struct lttng_map_query *query, unsigned int index,
+               pid_t *pid);
+
+LTTNG_HIDDEN
+enum lttng_map_query_status lttng_map_query_get_key_filter(
+               const struct lttng_map_query *query, const char **key_filter);
+
+LTTNG_HIDDEN
+ssize_t lttng_map_query_create_from_payload(struct lttng_payload_view *view,
+               struct lttng_map_query **query);
+
+LTTNG_HIDDEN
+int lttng_map_query_serialize(const struct lttng_map_query *query,
+               struct lttng_payload *payload);
+
+LTTNG_HIDDEN
+void lttng_map_query_destroy(struct lttng_map_query *query);
+
+#endif /* LTTNG_MAP_QUERY_INTERNAL_H */
diff --git a/include/lttng/map/map-query.h b/include/lttng/map/map-query.h
new file mode 100644 (file)
index 0000000..8f80844
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_MAP_QUERY_H
+#define LTTNG_MAP_QUERY_H
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#include <lttng/domain.h>
+#include <lttng/handle.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum lttng_map_query_status {
+       LTTNG_MAP_QUERY_STATUS_OK = 0,
+       LTTNG_MAP_QUERY_STATUS_ERROR = -1,
+       LTTNG_MAP_QUERY_STATUS_INVALID = -2,
+       LTTNG_MAP_QUERY_STATUS_NONE = -3,
+};
+
+/*
+ * Query the values of all CPUs or just some.
+ */
+enum lttng_map_query_config_cpu {
+       LTTNG_MAP_QUERY_CONFIG_CPU_ALL,
+       LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET,
+};
+
+/*
+ * Query the values of all uid (or pid) or just some.
+ */
+enum lttng_map_query_config_buffer {
+       LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_ALL,
+       LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET,
+       LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_ALL,
+       LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_SUBSET,
+       LTTNG_MAP_QUERY_CONFIG_BUFFER_KERNEL_GLOBAL,
+};
+
+/*
+ * Query the values of all bitness or just some.
+ */
+enum lttng_map_query_config_app_bitness {
+       LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_32, /*Not supported yet*/
+       LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_64, /*Not supported yet*/
+       LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_ALL,
+       LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_KERNEL,
+};
+
+struct lttng_map_query;
+
+/*
+ *
+ */
+extern struct lttng_map_query *lttng_map_query_create(
+               enum lttng_map_query_config_cpu cpu,
+               enum lttng_map_query_config_buffer buffer,
+               enum lttng_map_query_config_app_bitness bitness);
+
+extern enum lttng_map_query_status lttng_map_query_set_sum_by_cpu(
+               struct lttng_map_query *query, bool sum_by_cpu);
+
+extern enum lttng_map_query_status lttng_map_query_set_sum_by_pid(
+               struct lttng_map_query *query, bool sum_by_pid);
+
+extern enum lttng_map_query_status lttng_map_query_add_cpu(
+               struct lttng_map_query *query, int cpu_id);
+
+extern enum lttng_map_query_status lttng_map_query_add_uid(
+               struct lttng_map_query *query, uid_t uid);
+
+extern enum lttng_map_query_status lttng_map_query_add_pid(
+               struct lttng_map_query *query, pid_t pid);
+
+extern enum lttng_map_query_status lttng_map_query_add_key_filter(
+               struct lttng_map_query *query, const char *key_filter);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_MAP_QUERY_H */
diff --git a/include/lttng/map/map.h b/include/lttng/map/map.h
new file mode 100644 (file)
index 0000000..292e39e
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_MAP_H
+#define LTTNG_MAP_H
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#include <lttng/domain.h>
+#include <lttng/handle.h>
+
+#include <lttng/map/map-query.h>
+
+struct lttng_map;
+struct lttng_map_list;
+
+struct lttng_map_key_value_pair;
+/* A list of key value pair. */
+struct lttng_map_key_value_pair_list;
+/* A list of key value pair list. */
+struct lttng_map_content;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum lttng_map_status {
+       LTTNG_MAP_STATUS_OK = 0,
+       LTTNG_MAP_STATUS_ERROR = -1,
+       LTTNG_MAP_STATUS_INVALID = -2,
+       LTTNG_MAP_STATUS_UNSET = -3,
+};
+
+enum lttng_map_bitness {
+       LTTNG_MAP_BITNESS_32BITS = 32,
+       LTTNG_MAP_BITNESS_64BITS = 64,
+};
+
+enum lttng_map_boundary_policy {
+       LTTNG_MAP_BOUNDARY_POLICY_OVERFLOW,
+};
+
+enum lttng_map_key_value_pair_list_type {
+       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_KERNEL,
+       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID,
+       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID,
+       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID_AGGREGATED,
+};
+
+/*
+ *
+ * Return LTTNG_MAP_STATUS_OK on success, LTTNG_MAP_STATUS_INVALID if invalid
+ * parameters are passed.
+ */
+extern enum lttng_map_status lttng_map_create(const char *name,
+               unsigned int dimension_count,
+               uint64_t *dimension_sizes,
+               enum lttng_domain_type domain,
+               enum lttng_buffer_type buffer_type,
+               enum lttng_map_bitness bitness,
+               enum lttng_map_boundary_policy boundary_policy,
+               bool coalesce_hits,
+               struct lttng_map **map);
+
+extern enum lttng_map_status lttng_map_get_name(
+               const struct lttng_map *map, const char **name);
+
+extern enum lttng_map_status lttng_map_set_name(
+               struct lttng_map *map, const char *name);
+
+/*
+ * Get the number of dimensions.
+ *
+ */
+extern unsigned int lttng_map_get_dimension_count(
+               const struct lttng_map *map);
+
+/*
+ * Get the number of elements for the provided dimension.
+ *
+ * Return LTTNG_MAP_STATUS_OK on success, LTTNG_MAP_STATUS_INVALID if invalid
+ * parameters are passed.
+ *
+ */
+extern enum lttng_map_status lttng_map_get_dimension_length(
+               const struct lttng_map *map, unsigned int dimension,
+               uint64_t *dimension_length);
+
+extern int lttng_map_get_is_enabled(const struct lttng_map *map);
+
+extern enum lttng_map_bitness lttng_map_get_bitness(
+               const struct lttng_map *map);
+
+extern enum lttng_domain_type lttng_map_get_domain(
+               const struct lttng_map *map);
+
+extern enum lttng_buffer_type lttng_map_get_buffer_type(
+               const struct lttng_map *map);
+
+extern enum lttng_map_boundary_policy lttng_map_get_boundary_policy(
+               const struct lttng_map *map);
+
+extern bool lttng_map_get_coalesce_hits(
+               const struct lttng_map *map);
+
+extern void lttng_map_destroy(struct lttng_map *map);
+
+extern enum lttng_error_code lttng_add_map(struct lttng_handle *handle,
+               struct lttng_map *map);
+
+extern enum lttng_error_code lttng_enable_map(struct lttng_handle *handle,
+               const char *map_name);
+
+extern enum lttng_error_code lttng_disable_map(struct lttng_handle *handle,
+               const char *map_name);
+
+
+/*
+ * Get a map from the list at a given index.
+ *
+ * Note that the map list maintains the ownership of the returned map.
+ * It must not be destroyed by the user, nor should a reference to it be held
+ * beyond the lifetime of the map list.
+ *
+ * Returns a map, or NULL on error.
+ */
+extern const struct lttng_map *lttng_map_list_get_at_index(
+               const struct lttng_map_list *map_list, unsigned int index);
+
+/*
+ * Get the number of map in a map list.
+ */
+
+extern enum lttng_map_status lttng_map_list_get_count(
+               const struct lttng_map_list *map_list, unsigned int *count);
+
+/*
+ * Destroy a map list.
+ */
+extern void lttng_map_list_destroy(struct lttng_map_list *map_list);
+
+extern enum lttng_error_code lttng_list_maps(struct lttng_handle *handle,
+               struct lttng_map_list **map_list);
+
+/*
+ * FIXME: frdeso proper explanation
+ * lttng_map_content 1 to N lttng_map_key_value_pair_list
+ * lttng_map_key_value_pair_list 1 to N lttng_map_key_value_pair
+ */
+
+/*
+ * Get the key of a key-value.
+ *
+ * The caller does not assume the ownership of the returned key.
+ * The key shall only be used for the duration of the key-value's lifetime.
+ *
+ * Returns LTTNG_MAP_STATUS_OK and a pointer to the key-value's key on success,
+ * LTTNG_MAP_STATUS_INVALID if an invalid parameter is passed, or
+ */
+extern enum lttng_map_status lttng_map_key_value_pair_get_key(
+               const struct lttng_map_key_value_pair *kv_pair, const char **key);
+
+extern bool lttng_map_key_value_pair_get_has_overflowed(
+               const struct lttng_map_key_value_pair *key_value);
+
+extern bool lttng_map_key_value_pair_get_has_underflowed(
+               const struct lttng_map_key_value_pair *key_value);
+/*
+ * Get the value of a key-value.
+ *
+ * The caller does not assume the ownership of the returned value.
+ * The value shall only be used for the duration of the key-value's lifetime.
+ *
+ * Returns LTTNG_MAP_STATUS_OK and a pointer to the key-value's value on success,
+ * LTTNG_MAP_STATUS_INVALID if an invalid parameter is passed.
+ */
+extern enum lttng_map_status lttng_map_key_value_pair_get_value(
+               const struct lttng_map_key_value_pair *kv_pair, int64_t *value);
+
+extern enum lttng_map_status lttng_map_content_get_count(
+               const struct lttng_map_content *map_content,
+               unsigned int *count);
+
+extern const struct lttng_map_key_value_pair_list *lttng_map_content_get_at_index(
+               const struct lttng_map_content *map_content,
+               unsigned int index);
+/*
+ * List all key-value pairs for the given session and map.
+ *
+ * On success, a newly-allocated key-value list is returned.
+ *
+ * The key-value list must be destroyed by the caller (see
+ * lttng_map_key_value_pair_list_destroy()).
+ *
+ * Returns LTTNG_OK on success, else a suitable LTTng error code.
+ */
+extern enum lttng_error_code lttng_list_map_content(
+               struct lttng_handle *handle, const struct lttng_map *map,
+               const struct lttng_map_query *map_query,
+               struct lttng_map_content **map_content);
+
+extern enum lttng_buffer_type lttng_map_content_get_buffer_type(
+                       const struct lttng_map_content *map_content);
+
+extern void lttng_map_content_destroy(
+               struct lttng_map_content *map_content);
+/*
+ * Get a key-value from the list at a given index.
+ *
+ * Note that the key value list maintains the ownership of the returned key
+ * value.
+ * It must not be destroyed by the user, nor should a reference to it be held
+ * beyond the lifetime of the key value list.
+ *
+ * Returns a key-value, or NULL on error.
+ */
+extern const struct lttng_map_key_value_pair *lttng_map_key_value_pair_list_get_at_index(
+               const struct lttng_map_key_value_pair_list *kv_pair_list,
+               unsigned int index);
+
+/*
+ * Get the number of key value pair in a key-value list.
+ *
+ * Return LTTNG_MAP_STATUS_OK on success,
+ * LTTNG_MAP_STATUS_INVALID when invalid parameters are passed.
+ */
+extern enum lttng_map_status lttng_map_key_value_pair_list_get_count(
+               const struct lttng_map_key_value_pair_list *kv_pair_list,
+               unsigned int *count);
+
+extern enum lttng_map_key_value_pair_list_type lttng_map_key_value_pair_list_get_type(
+               const struct lttng_map_key_value_pair_list *kv_pair_list);
+
+extern uint64_t lttng_map_key_value_pair_list_get_identifer(
+               const struct lttng_map_key_value_pair_list *kv_pair_list);
+
+extern uint64_t lttng_map_key_value_pair_list_get_cpu(
+               const struct lttng_map_key_value_pair_list *kv_pair_list);
+
+extern bool lttng_map_key_value_pair_list_get_summed_all_cpu(
+               const struct lttng_map_key_value_pair_list *kv_pair_list);
+
+/*
+ * Destroy a map_key_value set.
+ */
+extern void lttng_map_key_value_pair_list_destroy(
+               struct lttng_map_key_value_pair_list *kv_pair_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_MAP_H */
index 21c269befd14b78b26c2aaa3496ed6600d43cf1a..59fe771aa32ef196ef3e89af5c87466dadf5cf21 100644 (file)
@@ -196,4 +196,13 @@ enum lttng_error_code lttng_trigger_generate_bytecode(
 LTTNG_HIDDEN
 struct lttng_trigger *lttng_trigger_copy(const struct lttng_trigger *trigger);
 
+/*
+ * A given trigger needs a tracer notifier if
+ *  it has an event-rule condition,
+ *  AND
+ *  it has one or more sessiond-execution action.
+ */
+LTTNG_HIDDEN
+bool lttng_trigger_needs_tracer_notifier(const struct lttng_trigger *trigger);
+
 #endif /* LTTNG_TRIGGER_INTERNAL_H */
index 1d3741c6129e550c0edc45da929f07e066b703c2..67b96b1dcb37ab8a5eca430d9d27be85a72092b6 100644 (file)
@@ -20,7 +20,7 @@ lttng_sessiond_SOURCES = utils.c utils.h \
                        context.c context.h \
                        channel.c channel.h \
                        event.c event.h \
-                       shm.c shm.h \
+                       map.c map.h \
                        consumer.c consumer.h \
                        session.c session.h \
                        modprobe.c modprobe.h kern-modules.h \
@@ -56,8 +56,11 @@ lttng_sessiond_SOURCES = utils.c utils.h \
                        manage-consumer.c manage-consumer.h \
                        clear.c clear.h \
                        tracker.c tracker.h \
+                       event-notifier-error-accounting.c event-notifier-error-accounting.h \
                        action-executor.c action-executor.h
 
+lttng_sessiond_LDFLAGS = -rdynamic
+
 if HAVE_LIBLTTNG_UST_CTL
 lttng_sessiond_SOURCES += trace-ust.c ust-registry.c ust-app.c \
                        ust-consumer.c ust-consumer.h notify-apps.c \
index 8f8bae406c8994db1577f8ce455bb71163784cb6..4e6de8907066ecd97aa3472c0cf7174e81ede584 100644 (file)
 #include <common/optional.h>
 #include <lttng/action/action-internal.h>
 #include <lttng/action/group.h>
+#include <lttng/action/notify-internal.h>
 #include <lttng/action/notify.h>
 #include <lttng/action/rotate-session.h>
 #include <lttng/action/snapshot-session.h>
 #include <lttng/action/start-session.h>
 #include <lttng/action/stop-session.h>
 #include <lttng/condition/evaluation.h>
-#include <lttng/condition/event-rule-internal.h>
+#include <lttng/condition/on-event-internal.h>
 #include <lttng/lttng-error.h>
 #include <lttng/trigger/trigger-internal.h>
 #include <pthread.h>
@@ -66,6 +67,9 @@ typedef int (*action_executor_handler)(struct action_executor *executor,
 static int action_executor_notify_handler(struct action_executor *executor,
                const struct action_work_item *,
                const struct lttng_action *);
+static int action_executor_incr_value_handler(struct action_executor *executor,
+               const struct action_work_item *,
+               const struct lttng_action *);
 static int action_executor_start_session_handler(struct action_executor *executor,
                const struct action_work_item *,
                const struct lttng_action *);
@@ -87,6 +91,7 @@ static int action_executor_generic_handler(struct action_executor *executor,
 
 static const action_executor_handler action_executors[] = {
        [LTTNG_ACTION_TYPE_NOTIFY] = action_executor_notify_handler,
+       [LTTNG_ACTION_TYPE_INCREMENT_VALUE] = action_executor_incr_value_handler,
        [LTTNG_ACTION_TYPE_START_SESSION] = action_executor_start_session_handler,
        [LTTNG_ACTION_TYPE_STOP_SESSION] = action_executor_stop_session_handler,
        [LTTNG_ACTION_TYPE_ROTATE_SESSION] = action_executor_rotate_session_handler,
@@ -94,14 +99,6 @@ static const action_executor_handler action_executors[] = {
        [LTTNG_ACTION_TYPE_GROUP] = action_executor_group_handler,
 };
 
-static const char *action_type_names[] = {
-       [LTTNG_ACTION_TYPE_NOTIFY] = "Notify",
-       [LTTNG_ACTION_TYPE_START_SESSION] = "Start session",
-       [LTTNG_ACTION_TYPE_STOP_SESSION] = "Stop session",
-       [LTTNG_ACTION_TYPE_ROTATE_SESSION] = "Rotate session",
-       [LTTNG_ACTION_TYPE_SNAPSHOT_SESSION] = "Snapshot session",
-       [LTTNG_ACTION_TYPE_GROUP] = "Group",
-};
 
 static const char *get_action_name(const struct lttng_action *action)
 {
@@ -109,7 +106,7 @@ static const char *get_action_name(const struct lttng_action *action)
 
        assert(action_type != LTTNG_ACTION_TYPE_UNKNOWN);
 
-       return action_type_names[action_type];
+       return lttng_action_type_string(action_type);
 }
 
 /* Check if this trigger allowed to interect with a given session. */
@@ -205,6 +202,14 @@ static int action_executor_notify_handler(struct action_executor *executor,
                        client_handle_transmission_status, executor);
 }
 
+static int action_executor_incr_value_handler(struct action_executor *executor,
+               const struct action_work_item *work_item,
+               const struct lttng_action *action)
+{
+       /* This action is executed by the tracer. */
+       return 0;
+}
+
 static int action_executor_start_session_handler(struct action_executor *executor,
                const struct action_work_item *work_item,
                const struct lttng_action *action)
@@ -237,7 +242,6 @@ static int action_executor_start_session_handler(struct action_executor *executo
        if (!is_trigger_allowed_for_session(work_item->trigger, session)) {
                goto error_dispose_session;
        }
-
        cmd_ret = cmd_start_trace(session);
        switch (cmd_ret) {
        case LTTNG_OK:
index 283d5b0353e16d2832b9a37fce71b9c66ea12cd3..cbd81c57622a05cfa2a1f5a9375579a9169c9551 100644 (file)
@@ -15,8 +15,9 @@
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/event-rule/tracepoint.h>
 #include <lttng/condition/condition.h>
-#include <lttng/condition/event-rule.h>
+#include <lttng/condition/on-event.h>
 #include <lttng/domain-internal.h>
+#include <lttng/log-level-rule-internal.h>
 
 #include <common/common.h>
 #include <common/sessiond-comm/agent.h>
@@ -1243,6 +1244,7 @@ struct agent_event *agent_find_event_by_trigger(
        const struct lttng_event_rule *rule;
        const char *name;
        const char *filter_expression;
+       const struct lttng_log_level_rule *log_level_rule;
        /* Unused when loglevel_type is 'ALL'. */
        int loglevel_value = 0;
        enum lttng_loglevel_type loglevel_type;
@@ -1253,9 +1255,9 @@ struct agent_event *agent_find_event_by_trigger(
        condition = lttng_trigger_get_const_condition(trigger);
 
        assert(lttng_condition_get_type(condition) ==
-                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+                       LTTNG_CONDITION_TYPE_ON_EVENT);
 
-       c_status = lttng_condition_event_rule_get_rule(condition, &rule);
+       c_status = lttng_condition_on_event_get_rule(condition, &rule);
        assert(c_status == LTTNG_CONDITION_STATUS_OK);
 
        assert(lttng_event_rule_get_type(rule) ==
@@ -1272,14 +1274,19 @@ struct agent_event *agent_find_event_by_trigger(
        /* Get the internal filter expression. */
        filter_expression = lttng_event_rule_get_filter(rule);
 
-       er_status = lttng_event_rule_tracepoint_get_log_level_type(
-                       rule, &loglevel_type);
-       assert(er_status == LTTNG_EVENT_RULE_STATUS_OK);
-
-       if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
-               er_status = lttng_event_rule_tracepoint_get_log_level(
-                               rule, &loglevel_value);
-               assert(er_status == LTTNG_EVENT_RULE_STATUS_OK);
+       /* Map log_level_rule to loglevel.
+        * TODO: There is a possibility of extracting this to the log_level_rule
+        * internal api since multiple callsite do the same.
+        */
+       er_status = lttng_event_rule_tracepoint_get_log_level_rule(
+                       rule, &log_level_rule);
+       if (er_status == LTTNG_EVENT_RULE_STATUS_UNSET) {
+               loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
+               loglevel_value = 0;
+       } else if (er_status == LTTNG_EVENT_RULE_STATUS_OK) {
+               lttng_log_level_rule_to_loglevel(log_level_rule, &loglevel_type, &loglevel_value);
+       } else {
+               abort();
        }
 
        return agent_find_event(name, loglevel_type, loglevel_value,
index 32fcbfb5f9ad55276444057e1aa389bd277f8356..34574e391bc6848f940504355f81868461d7ccd2 100644 (file)
@@ -136,6 +136,14 @@ int buffer_reg_uid_create(uint64_t session_id, uint32_t bits_per_long, uid_t uid
                goto error_session;
        }
 
+       reg->registry->maps = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+       if (!reg->registry->maps) {
+               lttng_ht_destroy(reg->registry->channels);
+               ret = -ENOMEM;
+               goto error_session;
+       }
+
+
        cds_lfht_node_init(&reg->node.node);
        *regp = reg;
 
@@ -262,6 +270,13 @@ int buffer_reg_pid_create(uint64_t session_id, struct buffer_reg_pid **regp,
                goto error_session;
        }
 
+       reg->registry->maps = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+       if (!reg->registry->maps) {
+               lttng_ht_destroy(reg->registry->channels);
+               ret = -ENOMEM;
+               goto error_session;
+       }
+
        lttng_ht_node_init_u64(&reg->node, reg->session_id);
        *regp = reg;
 
@@ -385,6 +400,36 @@ int buffer_reg_channel_create(uint64_t key, struct buffer_reg_channel **regp)
        return 0;
 }
 
+/*
+ * Allocate and initialize a buffer registry map with the given key. Set
+ * regp with the object pointer.
+ *
+ * Return 0 on success or else a negative value keeping regp untouched.
+ */
+int buffer_reg_map_create(uint64_t key, struct buffer_reg_map **regp)
+{
+       struct buffer_reg_map *reg;
+
+       assert(regp);
+
+       DBG3("Buffer registry map create with key: %" PRIu64, key);
+
+       reg = zmalloc(sizeof(*reg));
+       if (!reg) {
+               PERROR("zmalloc buffer registry map");
+               return -ENOMEM;
+       }
+
+       reg->key = key;
+       CDS_INIT_LIST_HEAD(&reg->counters);
+       pthread_mutex_init(&reg->counter_list_lock, NULL);
+
+       lttng_ht_node_init_u64(&reg->node, key);
+       *regp = reg;
+
+       return 0;
+}
+
 /*
  * Allocate and initialize a buffer registry stream. Set regp with the object
  * pointer.
@@ -410,6 +455,31 @@ int buffer_reg_stream_create(struct buffer_reg_stream **regp)
        return 0;
 }
 
+/*
+ * Allocate and initialize a buffer registry map_counter. Set regp with the object
+ * pointer.
+ *
+ * Return 0 on success or else a negative value keeping regp untouched.
+ */
+int buffer_reg_map_counter_create(struct buffer_reg_map_counter **regp)
+{
+       struct buffer_reg_map_counter *reg;
+
+       assert(regp);
+
+       DBG3("Buffer registry creating map_counter");
+
+       reg = zmalloc(sizeof(*reg));
+       if (!reg) {
+               PERROR("zmalloc buffer registry map_counter");
+               return -ENOMEM;
+       }
+
+       *regp = reg;
+
+       return 0;
+}
+
 /*
  * Add stream to the list in the channel.
  */
@@ -425,6 +495,21 @@ void buffer_reg_stream_add(struct buffer_reg_stream *stream,
        pthread_mutex_unlock(&channel->stream_list_lock);
 }
 
+/*
+ * Add map_counter to the list in the map.
+ */
+void buffer_reg_map_counter_add(struct buffer_reg_map_counter *map_counter,
+               struct buffer_reg_map *map)
+{
+       assert(map_counter);
+       assert(map);
+
+       pthread_mutex_lock(&map->counter_list_lock);
+       cds_list_add_tail(&map_counter->lnode, &map->counters);
+       map->counter_count++;
+       pthread_mutex_unlock(&map->counter_list_lock);
+}
+
 /*
  * Add a buffer registry channel object to the given session.
  */
@@ -439,6 +524,20 @@ void buffer_reg_channel_add(struct buffer_reg_session *session,
        rcu_read_unlock();
 }
 
+/*
+ * Add a buffer registry map object to the given session.
+ */
+void buffer_reg_map_add(struct buffer_reg_session *session,
+               struct buffer_reg_map *map)
+{
+       assert(session);
+       assert(map);
+
+       rcu_read_lock();
+       lttng_ht_add_unique_u64(session->maps, &map->node);
+       rcu_read_unlock();
+}
+
 /*
  * Find a buffer registry channel object with the given key. RCU read side lock
  * MUST be acquired and hold on until the object reference is not needed
@@ -476,6 +575,43 @@ end:
        return chan;
 }
 
+/*
+ * Find a buffer registry map object with the given key. RCU read side lock
+ * MUST be acquired and hold on until the object reference is not needed
+ * anymore.
+ *
+ * Return the object pointer or NULL on error.
+ */
+struct buffer_reg_map *buffer_reg_map_find(uint64_t key,
+               struct buffer_reg_uid *reg)
+{
+       struct lttng_ht_node_u64 *node;
+       struct lttng_ht_iter iter;
+       struct buffer_reg_map *map = NULL;
+       struct lttng_ht *ht;
+
+       assert(reg);
+
+       switch (reg->domain) {
+       case LTTNG_DOMAIN_UST:
+               ht = reg->registry->maps;
+               break;
+       default:
+               assert(0);
+               goto end;
+       }
+
+       lttng_ht_lookup(ht, &key, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if (!node) {
+               goto end;
+       }
+       map = caa_container_of(node, struct buffer_reg_map, node);
+
+end:
+       return map;
+}
+
 /*
  * Destroy a buffer registry stream with the given domain.
  */
@@ -511,6 +647,41 @@ void buffer_reg_stream_destroy(struct buffer_reg_stream *regp,
        return;
 }
 
+/*
+ * Destroy a buffer registry map_counter with the given domain.
+ */
+void buffer_reg_map_counter_destroy(struct buffer_reg_map_counter *regp,
+               enum lttng_domain_type domain)
+{
+       if (!regp) {
+               return;
+       }
+
+       DBG3("Buffer registry map counter destroy with handle %d",
+                       regp->obj.ust->handle);
+
+       switch (domain) {
+       case LTTNG_DOMAIN_UST:
+       {
+               int ret;
+
+               ret = ust_app_release_object(NULL, regp->obj.ust);
+               if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("Buffer reg map counter release obj handle %d failed with ret %d",
+                                       regp->obj.ust->handle, ret);
+               }
+               free(regp->obj.ust);
+               lttng_fd_put(LTTNG_FD_APPS, 2);
+               break;
+       }
+       default:
+               assert(0);
+       }
+
+       free(regp);
+       return;
+}
+
 /*
  * Remove buffer registry channel object from the session hash table. RCU read
  * side lock MUST be acquired before calling this.
@@ -529,6 +700,24 @@ void buffer_reg_channel_remove(struct buffer_reg_session *session,
        assert(!ret);
 }
 
+/*
+ * Remove buffer registry map object from the session hash table. RCU read
+ * side lock MUST be acquired before calling this.
+ */
+void buffer_reg_map_remove(struct buffer_reg_session *session,
+               struct buffer_reg_map *regp)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+
+       assert(session);
+       assert(regp);
+
+       iter.iter.node = &regp->node.node;
+       ret = lttng_ht_del(session->maps, &iter);
+       assert(!ret);
+}
+
 /*
  * Destroy a buffer registry channel with the given domain.
  */
@@ -572,6 +761,49 @@ void buffer_reg_channel_destroy(struct buffer_reg_channel *regp,
        return;
 }
 
+/*
+ * Destroy a buffer registry map with the given domain.
+ */
+void buffer_reg_map_destroy(struct buffer_reg_map *regp,
+               enum lttng_domain_type domain)
+{
+       if (!regp) {
+               return;
+       }
+
+       DBG3("Buffer registry map destroy with key %" PRIu32, regp->key);
+
+       switch (domain) {
+       case LTTNG_DOMAIN_UST:
+       {
+               int ret;
+               struct buffer_reg_map_counter *map_counter_reg, *tmp;
+               /* Wipe counter */
+               cds_list_for_each_entry_safe(map_counter_reg, tmp, &regp->counters, lnode) {
+                       cds_list_del(&map_counter_reg->lnode);
+                       regp->counter_count--;
+                       buffer_reg_map_counter_destroy(map_counter_reg, domain);
+               }
+
+               if (regp->obj.ust) {
+                       ret = ust_app_release_object(NULL, regp->obj.ust);
+                       if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                               ERR("Buffer reg map release obj handle %d failed with ret %d",
+                                               regp->obj.ust->handle, ret);
+                       }
+                       free(regp->obj.ust);
+               }
+               lttng_fd_put(LTTNG_FD_APPS, 1);
+               break;
+       }
+       default:
+               assert(0);
+       }
+
+       free(regp);
+       return;
+}
+
 /*
  * Destroy a buffer registry session with the given domain.
  *
@@ -583,6 +815,7 @@ static void buffer_reg_session_destroy(struct buffer_reg_session *regp,
        int ret;
        struct lttng_ht_iter iter;
        struct buffer_reg_channel *reg_chan;
+       struct buffer_reg_map *reg_map;
 
        DBG3("Buffer registry session destroy");
 
@@ -594,9 +827,16 @@ static void buffer_reg_session_destroy(struct buffer_reg_session *regp,
                assert(!ret);
                buffer_reg_channel_destroy(reg_chan, domain);
        }
+       cds_lfht_for_each_entry(regp->maps->ht, &iter.iter, reg_map,
+                       node.node) {
+               ret = lttng_ht_del(regp->maps, &iter);
+               assert(!ret);
+               buffer_reg_map_destroy(reg_map, domain);
+       }
        rcu_read_unlock();
 
        ht_cleanup_push(regp->channels);
+       ht_cleanup_push(regp->maps);
 
        switch (domain) {
        case LTTNG_DOMAIN_UST:
index 0812414e5b4f260253f10f58d5dad2cbf4035e43..00be7b65ef66fac15862e7538e5a14d3fe9c37cc 100644 (file)
@@ -26,6 +26,14 @@ struct buffer_reg_stream {
        } obj;
 };
 
+struct buffer_reg_map_counter {
+       struct cds_list_head lnode;
+       union {
+               /* Original object data that MUST be copied over. */
+               struct lttng_ust_object_data *ust;
+       } obj;
+};
+
 struct buffer_reg_channel {
        /* This key is the same as a tracing channel key. */
        uint32_t key;
@@ -49,6 +57,25 @@ struct buffer_reg_channel {
        } obj;
 };
 
+struct buffer_reg_map {
+       /* This key is the same as a tracing map key. */
+       uint32_t key;
+       /* Per cpu counter registry object of this map registry. */
+       struct cds_list_head counters;
+       /* Total number of stream in the list. */
+       uint64_t counter_count;
+       /* Used to ensure mutual exclusion to the counter's list. */
+       pthread_mutex_t counter_list_lock;
+       /* Node for hash table usage. */
+       struct lttng_ht_node_u64 node;
+       union {
+               /* Original object data that MUST be copied over. */
+               struct lttng_ust_object_data *ust;
+       } obj;
+
+       struct ustctl_daemon_counter *daemon_counter;
+};
+
 struct buffer_reg_session {
        /* Registry per domain. */
        union {
@@ -57,6 +84,8 @@ struct buffer_reg_session {
 
        /* Contains buffer registry channel indexed by tracing channel key. */
        struct lttng_ht *channels;
+       /* Contains buffer registry map indexed by tracing map key. */
+       struct lttng_ht *maps;
 };
 
 /*
@@ -130,6 +159,17 @@ void buffer_reg_channel_remove(struct buffer_reg_session *session,
 void buffer_reg_channel_destroy(struct buffer_reg_channel *regp,
                enum lttng_domain_type domain);
 
+/* Map */
+int buffer_reg_map_create(uint64_t key, struct buffer_reg_map **regp);
+void buffer_reg_map_add(struct buffer_reg_session *session,
+               struct buffer_reg_map *map);
+struct buffer_reg_map *buffer_reg_map_find(uint64_t key,
+               struct buffer_reg_uid *reg);
+void buffer_reg_map_remove(struct buffer_reg_session *session,
+               struct buffer_reg_map *regp);
+void buffer_reg_map_destroy(struct buffer_reg_map *regp,
+               enum lttng_domain_type domain);
+
 /* Stream */
 int buffer_reg_stream_create(struct buffer_reg_stream **regp);
 void buffer_reg_stream_add(struct buffer_reg_stream *stream,
@@ -137,6 +177,13 @@ void buffer_reg_stream_add(struct buffer_reg_stream *stream,
 void buffer_reg_stream_destroy(struct buffer_reg_stream *regp,
                enum lttng_domain_type domain);
 
+/* Map counter */
+int buffer_reg_map_counter_create(struct buffer_reg_map_counter **regp);
+void buffer_reg_map_counter_add(struct buffer_reg_map_counter *map_counter,
+               struct buffer_reg_map *map);
+void buffer_reg_map_counter_destroy(struct buffer_reg_map_counter *regp,
+               enum lttng_domain_type domain);
+
 /* Global registry. */
 void buffer_reg_destroy_registries(void);
 
index 3ae70ea2fa5fd462d38e816a9328c58aaebc8081..3a08a119a686d2bffc6a849e0b346e1456d174a1 100644 (file)
@@ -188,7 +188,6 @@ int cmd_clear_session(struct ltt_session *session, int *sock_fd)
                /* Flag session that trace should start automatically */
                if (usess) {
                        int int_ret = ust_app_start_trace_all(usess);
-
                        if (int_ret < 0) {
                                ret = LTTNG_ERR_UST_START_FAIL;
                                goto end;
index 770a2ee4464f0b6962b9bd731095823b1feb9021..ba6d08cbda6a28c78196eb7a502dce45de9a61e7 100644 (file)
@@ -24,6 +24,9 @@
 #include <common/unix.h>
 #include <common/utils.h>
 #include <lttng/event-internal.h>
+#include <lttng/map/map.h>
+#include <lttng/map/map-internal.h>
+#include <lttng/map/map-query-internal.h>
 #include <lttng/session-descriptor-internal.h>
 #include <lttng/session-internal.h>
 #include <lttng/userspace-probe-internal.h>
@@ -767,6 +770,106 @@ end:
        return ret_code;
 }
 
+static enum lttng_error_code receive_lttng_map(int sock,
+               int *sock_error,
+               uint32_t map_len,
+               struct lttng_map **_map)
+{
+       int ret;
+       ssize_t sock_recv_len;
+       enum lttng_error_code ret_code;
+       struct lttng_payload map_payload;
+       struct lttng_map *map = NULL;
+
+       lttng_payload_init(&map_payload);
+       ret = lttng_dynamic_buffer_set_size(
+                       &map_payload.buffer, map_len);
+       if (ret) {
+               ret_code = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       sock_recv_len = lttcomm_recv_unix_sock(
+                       sock, map_payload.buffer.data, map_len);
+       if (sock_recv_len < 0 || sock_recv_len != map_len) {
+               ERR("Failed to receive map in command payload");
+               *sock_error = 1;
+               ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+               goto end;
+       }
+
+       /* Deserialize map. */
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &map_payload, 0, -1);
+
+               if (lttng_map_create_from_payload(&view, &map) !=
+                               map_len) {
+                       ERR("Invalid map received as part of command payload");
+                       ret_code = LTTNG_ERR_INVALID_TRIGGER;
+                       lttng_map_put(map);
+                       goto end;
+               }
+       }
+
+       *_map = map;
+       ret_code = LTTNG_OK;
+
+end:
+       return ret_code;
+}
+
+static enum lttng_error_code receive_lttng_map_query(int sock,
+               int *sock_error,
+               uint32_t map_query_len,
+               struct lttng_map_query **_map_query)
+{
+       int ret;
+       ssize_t sock_recv_len;
+       enum lttng_error_code ret_code;
+       struct lttng_payload map_query_payload;
+       struct lttng_map_query *map_query = NULL;
+
+       lttng_payload_init(&map_query_payload);
+       ret = lttng_dynamic_buffer_set_size(
+                       &map_query_payload.buffer, map_query_len);
+       if (ret) {
+               ret_code = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       sock_recv_len = lttcomm_recv_unix_sock(
+                       sock, map_query_payload.buffer.data, map_query_len);
+       if (sock_recv_len < 0 || sock_recv_len != map_query_len) {
+               ERR("Failed to receive map query in command payload");
+               *sock_error = 1;
+               ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+               goto end;
+       }
+
+       /* Deserialize map query. */
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &map_query_payload, 0, -1);
+
+               if (lttng_map_query_create_from_payload(&view, &map_query) !=
+                               map_query_len) {
+                       ERR("Invalid map query received as part of command payload");
+                       ret_code = LTTNG_ERR_INVALID_TRIGGER;
+                       lttng_map_query_destroy(map_query);
+                       goto end;
+               }
+       }
+
+       *_map_query = map_query;
+       ret_code = LTTNG_OK;
+
+end:
+       return ret_code;
+}
+
 /*
  * Version of setup_lttng_msg() without command header.
  */
@@ -876,6 +979,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
        case LTTNG_SESSION_LIST_ROTATION_SCHEDULES:
        case LTTNG_CLEAR_SESSION:
        case LTTNG_LIST_TRIGGERS:
+       case LTTNG_LIST_MAP_VALUES:
                need_domain = false;
                break;
        default:
@@ -886,6 +990,10 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
        switch (cmd_ctx->lsm.cmd_type) {
        case LTTNG_REGISTER_TRIGGER:
        case LTTNG_UNREGISTER_TRIGGER:
+       case LTTNG_ADD_MAP:
+       case LTTNG_ENABLE_MAP:
+       case LTTNG_DISABLE_MAP:
+       case LTTNG_LIST_MAP_VALUES:
                need_consumerd = false;
                break;
        default:
@@ -986,6 +1094,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
        switch (cmd_ctx->lsm.cmd_type) {
        case LTTNG_DISABLE_CHANNEL:
        case LTTNG_DISABLE_EVENT:
+       case LTTNG_DISABLE_MAP:
                switch (cmd_ctx->lsm.domain.type) {
                case LTTNG_DOMAIN_KERNEL:
                        if (!cmd_ctx->session->kernel_session) {
@@ -1354,6 +1463,23 @@ error_add_context:
                                kernel_poll_pipe[1]);
                break;
        }
+       case LTTNG_ADD_MAP:
+       {
+               ret = cmd_add_map(cmd_ctx, *sock);
+
+               break;
+       }
+       case LTTNG_ENABLE_MAP:
+               ret = cmd_enable_map(cmd_ctx->session, cmd_ctx->lsm.domain.type,
+                               cmd_ctx->lsm.u.enable_map.map_name);
+               break;
+       case LTTNG_DISABLE_MAP:
+       {
+               ret = cmd_disable_map(cmd_ctx->session, cmd_ctx->lsm.domain.type,
+                               cmd_ctx->lsm.u.disable_map.map_name);
+
+               break;
+       }
        case LTTNG_PROCESS_ATTR_TRACKER_ADD_INCLUDE_VALUE:
        case LTTNG_PROCESS_ATTR_TRACKER_REMOVE_INCLUDE_VALUE:
        {
@@ -1892,6 +2018,45 @@ error_add_context:
                ret = LTTNG_OK;
                break;
        }
+       case LTTNG_LIST_MAPS:
+       {
+               struct lttng_map_list *return_map_list = NULL;
+               size_t original_payload_size;
+               size_t payload_size;
+
+               ret = setup_empty_lttng_msg(cmd_ctx);
+               if (ret) {
+                       ret = LTTNG_ERR_NOMEM;
+                       goto setup_error;
+               }
+
+               original_payload_size = cmd_ctx->reply_payload.buffer.size;
+
+               ret = cmd_list_maps(cmd_ctx->lsm.domain.type, cmd_ctx->session,
+                               &return_map_list);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+
+               assert(return_map_list);
+               ret = lttng_map_list_serialize(return_map_list,
+                               &cmd_ctx->reply_payload);
+               lttng_map_list_destroy(return_map_list);
+               if (ret) {
+                       ERR("Failed to serialize map_list in reply to `%s` command",
+                                       lttcomm_sessiond_command_str(cmd_ctx->lsm.cmd_type));
+                       ret = LTTNG_ERR_NOMEM;
+                       goto error;
+               }
+
+               payload_size = cmd_ctx->reply_payload.buffer.size -
+                       original_payload_size;
+
+               update_lttng_msg(cmd_ctx, 0, payload_size);
+
+               ret = LTTNG_OK;
+               break;
+       }
        case LTTNG_LIST_EVENTS:
        {
                ssize_t list_ret;
@@ -2343,6 +2508,60 @@ error_add_context:
                ret = LTTNG_OK;
                break;
        }
+       case LTTNG_LIST_MAP_VALUES:
+       {
+               struct lttng_map_content *return_map_content = NULL;
+               struct lttng_map *payload_map = NULL;
+               struct lttng_map_query *payload_map_query = NULL;
+               size_t original_reply_payload_size;
+               size_t reply_payload_size;
+
+               ret = setup_empty_lttng_msg(cmd_ctx);
+               if (ret) {
+                       ret = LTTNG_ERR_NOMEM;
+                       goto setup_error;
+               }
+
+               original_reply_payload_size = cmd_ctx->reply_payload.buffer.size;
+
+               ret = receive_lttng_map(*sock, sock_error,
+                               cmd_ctx->lsm.u.list_map_values.map_length,
+                               &payload_map);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+
+               ret = receive_lttng_map_query(*sock, sock_error,
+                               cmd_ctx->lsm.u.list_map_values.query_length,
+                               &payload_map_query);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+
+               ret = cmd_list_map_values(cmd_ctx->lsm.session.name,
+                               payload_map, payload_map_query,
+                               &return_map_content);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+               assert(return_map_content);
+               ret = lttng_map_content_serialize(return_map_content,
+                               &cmd_ctx->reply_payload);
+               lttng_map_content_destroy(return_map_content);
+               if (ret) {
+                       ERR("Failed to serialize key-value pair list in reply to `list map values` command");
+                       ret = LTTNG_ERR_NOMEM;
+                       goto error;
+               }
+
+               reply_payload_size = cmd_ctx->reply_payload.buffer.size -
+                       original_reply_payload_size;
+
+               update_lttng_msg(cmd_ctx, 0, reply_payload_size);
+
+               ret = LTTNG_OK;
+               break;
+       }
        default:
                ret = LTTNG_ERR_UND;
                break;
index a2af8882f289397b55f889f6f6995566b02aa3f6..67ac9fd7bd7c2cfe3313c57ecdf54d624f383e00 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <common/defaults.h>
 #include <common/common.h>
+#include <common/error.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <common/relayd/relayd.h>
 #include <common/utils.h>
 #include <lttng/trigger/trigger-internal.h>
 #include <lttng/condition/condition.h>
 #include <lttng/condition/condition-internal.h>
-#include <lttng/condition/event-rule.h>
-#include <lttng/condition/event-rule-internal.h>
+#include <lttng/condition/on-event.h>
+#include <lttng/condition/on-event-internal.h>
 #include <lttng/event-rule/event-rule.h>
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/action/action.h>
+#include <lttng/action/action-internal.h>
+#include <lttng/action/group-internal.h>
+#include <lttng/action/incr-value-internal.h>
 #include <lttng/channel.h>
 #include <lttng/channel-internal.h>
+#include "lttng/domain.h"
+#include "lttng/map/map.h"
+#include <lttng/map/map-internal.h>
 #include <lttng/rotate-internal.h>
 #include <lttng/location-internal.h>
 #include <lttng/session-internal.h>
 #include "lttng-syscall.h"
 #include "agent.h"
 #include "buffer-registry.h"
+#include "map.h"
 #include "notification-thread.h"
 #include "notification-thread-commands.h"
 #include "rotate.h"
 #include "rotation-thread.h"
 #include "timer.h"
 #include "agent-thread.h"
+#include "session.h"
 #include "tracker.h"
 
 #include "cmd.h"
@@ -288,6 +297,340 @@ end:
        return ret;
 }
 
+enum tracer_executed_action_state {
+       TRACER_EXECUTED_ACTION_STATE_REGISTER,
+       TRACER_EXECUTED_ACTION_STATE_UNREGISTER
+};
+
+static
+enum lttng_error_code sync_incr_value_action_ust(
+               struct ltt_session *session,
+               const struct lttng_condition *condition,
+               const char *map_name,
+               uint64_t tracer_token,
+               struct lttng_map_key *key,
+               enum tracer_executed_action_state state)
+{
+       enum lttng_error_code ret_code;
+       const struct lttng_event_rule *event_rule;
+       enum lttng_condition_status cond_status;
+       enum lttng_event_rule_status er_status;
+       struct ltt_ust_session *usess = session->ust_session;
+       const char *pattern;
+       struct ltt_ust_map *map;
+       char *filter_expression;
+       struct lttng_bytecode *filter;
+       struct lttng_event_exclusion *exclusion;
+       enum lttng_event_rule_generate_exclusions_status
+                       generate_exclusion_status;
+
+       DBG("Syncing UST incr-value action for session '%s', map '%s'",
+                       session->name, map_name);
+       if (!usess) {
+               DBG("No UST session");
+               ret_code = LTTNG_OK;
+               goto end;
+       }
+
+       assert(usess->domain_global.maps);
+
+       map = trace_ust_find_map_by_name(usess->domain_global.maps, map_name);
+       if (!map) {
+               DBG("UST map \"%s\" not found", map_name);
+               ret_code = LTTNG_OK;
+               goto end;
+       }
+
+       cond_status = lttng_condition_on_event_get_rule(condition, &event_rule);
+       if (cond_status != LTTNG_CONDITION_STATUS_OK) {
+               ERR("Error getting on-event condition event-rule");
+               ret_code = LTTNG_ERR_INVALID_MAP;
+               goto end;
+       }
+
+       er_status = lttng_event_rule_tracepoint_get_pattern(event_rule, &pattern);
+       if (er_status != LTTNG_EVENT_RULE_STATUS_OK) {
+               /* At this point, this is a fatal error. */
+               abort();
+       }
+
+       /*
+        * FIXME: frdeso, reuse the event notifier functions and approach to
+        * create the event.
+        */
+       filter_expression = (char *) lttng_event_rule_get_filter(event_rule);
+       filter = (struct lttng_bytecode *)lttng_event_rule_get_filter_bytecode(
+                       event_rule);
+       generate_exclusion_status = lttng_event_rule_generate_exclusions(
+                       event_rule, &exclusion);
+       if (generate_exclusion_status == LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_ERROR) {
+               ERR("Error generating the exclusion");
+               ret_code = LTTNG_ERR_EXCLUSION_INVAL;
+               goto end;
+       }
+
+       switch (state) {
+       case TRACER_EXECUTED_ACTION_STATE_REGISTER:
+               ret_code = map_event_ust_enable_tracepoint(usess,
+                               map, tracer_token, (char *) pattern, key,
+                               LTTNG_EVENT_TRACEPOINT, LTTNG_EVENT_LOGLEVEL_ALL,
+                               0, filter_expression, filter, exclusion, false);
+               if (ret_code == LTTNG_ERR_UST_EVENT_ENABLED) {
+                       ret_code = LTTNG_OK;
+               } else if (ret_code != LTTNG_OK) {
+                       ERR("Enabling UST map event");
+                       goto end;
+               }
+               break;
+       case TRACER_EXECUTED_ACTION_STATE_UNREGISTER:
+               ret_code = map_event_ust_disable_tracepoint(usess,
+                               map, tracer_token, (char *) pattern, key,
+                               LTTNG_EVENT_TRACEPOINT, LTTNG_EVENT_LOGLEVEL_ALL,
+                               0, filter_expression, filter, exclusion, false);
+               if (ret_code == LTTNG_ERR_UST_EVENT_ENABLED) {
+                       ret_code = LTTNG_OK;
+               } else if (ret_code != LTTNG_OK) {
+                       ERR("Enabling UST map event");
+                       goto end;
+               }
+               break;
+       default:
+               abort();
+       }
+
+       ret_code = LTTNG_OK;
+
+end:
+       return ret_code;
+}
+
+static
+enum lttng_error_code sync_incr_value_action_kernel(
+               struct ltt_session *session,
+               const struct lttng_credentials *creds,
+               const struct lttng_condition *condition,
+               const char *map_name,
+               uint64_t tracer_token,
+               struct lttng_map_key *key,
+               enum tracer_executed_action_state state)
+{
+       enum lttng_error_code ret_code;
+       const struct lttng_event_rule *event_rule;
+       enum lttng_condition_status cond_status;
+       struct ltt_kernel_map *kmap;
+       struct ltt_kernel_session *ksess = session->kernel_session;
+
+       DBG("Syncing kernel incr-value action for session '%s', map '%s'",
+                       session->name, map_name);
+
+       if (!ksess) {
+               DBG("No kernel session");
+               ret_code = LTTNG_OK;
+               goto end;
+       }
+
+       kmap = trace_kernel_get_map_by_name(map_name, ksess);
+       if (!kmap) {
+               DBG("Kernel map \"%s\" not found", map_name);
+               ret_code = LTTNG_OK;
+               goto end;
+       }
+
+       cond_status = lttng_condition_on_event_get_rule(condition, &event_rule);
+       if (cond_status != LTTNG_CONDITION_STATUS_OK) {
+               ret_code = LTTNG_ERR_INVALID_MAP;
+               ERR("Error getting on-event condition event-rule");
+               goto end;
+       }
+
+       switch (state) {
+       case TRACER_EXECUTED_ACTION_STATE_REGISTER:
+               ret_code = map_event_kernel_enable_event(kmap, creds, tracer_token,
+                               event_rule, key);
+               if(ret_code != LTTNG_OK) {
+                       ERR("Error enabling event counter to the kernel tracer");
+                       goto end;
+               }
+               break;
+       case TRACER_EXECUTED_ACTION_STATE_UNREGISTER:
+               ret_code = map_event_kernel_disable_event(kmap, tracer_token);
+               if(ret_code != LTTNG_OK) {
+                       ERR("Error disabling event counter to the kernel tracer");
+                       goto end;
+               }
+               break;
+       }
+
+end:
+       return ret_code;
+}
+
+static
+enum lttng_error_code sync_incr_value_action(
+               const struct lttng_credentials *creds,
+               const struct lttng_condition *condition,
+               const struct lttng_action *action,
+               enum tracer_executed_action_state state)
+{
+       enum lttng_error_code ret;
+       const char *session_name, *map_name;
+       enum lttng_action_status action_status;
+       enum lttng_condition_status cond_status;
+       const struct lttng_event_rule *event_rule;
+       struct ltt_session *session = NULL;
+       struct lttng_map_key *key;
+       uint64_t action_tracer_token;
+
+       action_status = lttng_action_incr_value_get_map_name(action,
+                       &map_name);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Map name not set for incr-value action");
+               ret = LTTNG_ERR_INVALID_MAP;
+               goto end;
+       }
+
+       action_status = lttng_action_incr_value_get_session_name(action,
+                       &session_name);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Session name not set for incr-value action");
+               ret = LTTNG_ERR_INVALID_MAP;
+               goto end;
+       }
+
+       action_status = lttng_action_incr_value_borrow_key_mutable(action, &key);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Key not set for incr-value action");
+               ret = LTTNG_ERR_INVALID_MAP;
+               goto end;
+       }
+
+       /* Returns a refcounted reference */
+       session = session_find_by_name(session_name);
+       if(!session) {
+               DBG("Session not found for incr-value action: session-name=%s",
+                       session_name);
+               ret = LTTNG_OK;
+               goto end;
+       }
+
+       cond_status = lttng_condition_on_event_get_rule(condition, &event_rule);
+       if (cond_status != LTTNG_CONDITION_STATUS_OK) {
+               ERR("Error getting on-event condition event-rule");
+               ret = LTTNG_ERR_INVALID_MAP;
+               session_put(session);
+               goto end;
+       }
+
+       action_tracer_token = lttng_action_incr_value_get_tracer_token(action);
+
+       switch (lttng_event_rule_get_domain_type(event_rule)) {
+       case LTTNG_DOMAIN_UST:
+               ret = sync_incr_value_action_ust(session, condition,
+                               map_name, action_tracer_token, key, state);
+               if (ret == LTTNG_ERR_UST_EVENT_EXIST) {
+                       DBG("Incr-value action already registered");
+                       ret = LTTNG_OK;
+               }
+               break;
+       case LTTNG_DOMAIN_KERNEL:
+               ret = sync_incr_value_action_kernel(session, creds, condition,
+                               map_name, action_tracer_token, key, state);
+               if (ret == LTTNG_ERR_KERN_EVENT_EXIST) {
+                       DBG("Incr-value action already registered");
+                       ret = LTTNG_OK;
+               }
+               break;
+       default:
+               abort();
+       }
+
+       goto end;
+end:
+       if (session) {
+               session_put(session);
+       }
+       return ret;
+}
+
+static
+enum lttng_error_code sync_one_tracer_executed_action(
+               const struct lttng_credentials *creds,
+               const struct lttng_condition *condition,
+               const struct lttng_action *action,
+               enum tracer_executed_action_state state)
+{
+       enum lttng_action_type action_type;
+       enum lttng_error_code ret;
+
+       action_type = lttng_action_get_type(action);
+       assert(action_type != LTTNG_ACTION_TYPE_GROUP);
+
+       switch (action_type) {
+       case LTTNG_ACTION_TYPE_INCREMENT_VALUE:
+               DBG("Action type \"%s\" is a tracer executed action.",
+                               lttng_action_type_string(action_type));
+
+               ret = sync_incr_value_action(creds, condition, action, state);
+               if (ret != LTTNG_OK) {
+                       ERR("Error syncing increment value action to the tracer");
+               }
+               break;
+       default:
+               DBG("Action type \"%s\" is not a tracer executed action.",
+                               lttng_action_type_string(action_type));
+               ret = LTTNG_OK;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+enum lttng_error_code sync_all_tracer_executed_actions(
+               const struct lttng_trigger *trigger,
+               const struct lttng_credentials *cmd_creds,
+               enum tracer_executed_action_state state)
+{
+       enum lttng_error_code ret;
+       unsigned int i, count;
+       enum lttng_action_status action_status;
+       enum lttng_action_type action_type;
+       const struct lttng_action *action;
+       const struct lttng_condition *condition;
+
+       condition = lttng_trigger_get_const_condition(trigger);
+       action = lttng_trigger_get_const_action(trigger);
+
+       action_type = lttng_action_get_type(action);
+
+       DBG("Iterating over all actions of trigger \"%s\" to sync any tracer executed actions",
+                       trigger->name);
+
+       if (action_type != LTTNG_ACTION_TYPE_GROUP) {
+               ret = sync_one_tracer_executed_action(cmd_creds, condition, action,
+                                state);
+       } else {
+               action_status = lttng_action_group_get_count(action, &count);
+               assert(action_status == LTTNG_ACTION_STATUS_OK);
+
+               for (i = 0; i < count; i++) {
+                       const struct lttng_action *inner_action =
+                                       lttng_action_group_get_at_index(action, i);
+
+                       ret = sync_one_tracer_executed_action(cmd_creds, condition,
+                                       inner_action, state);
+                       if (ret != LTTNG_OK) {
+                               ERR("Error syncing tracer executed action");
+                               goto end;
+                       }
+               }
+       }
+
+end:
+       return ret;
+}
+
 /*
  * Fill lttng_channel array of all channels.
  */
@@ -1523,6 +1866,237 @@ end:
        return ret;
 }
 
+enum lttng_error_code cmd_add_map(struct command_ctx *cmd_ctx, int sock)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       size_t map_len;
+       struct lttng_payload map_payload;
+       ssize_t sock_recv_len;
+       struct lttng_map *map = NULL;
+       const struct lttng_credentials cmd_creds = {
+               .uid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.uid),
+               .gid = LTTNG_OPTIONAL_INIT_VALUE(cmd_ctx->creds.gid),
+       };
+
+       lttng_payload_init(&map_payload);
+       map_len = (size_t) cmd_ctx->lsm.u.add_map.length;
+       ret = lttng_dynamic_buffer_set_size(
+                       &map_payload.buffer, map_len);
+       if (ret) {
+               ret_code = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       sock_recv_len = lttcomm_recv_unix_sock(
+                       sock, map_payload.buffer.data, map_len);
+       if (sock_recv_len < 0 || sock_recv_len != map_len) {
+               ERR("Failed to receive \"register map\" command payload");
+               ret_code = LTTNG_ERR_INVALID_MAP;
+               goto end;
+       }
+
+       /* Deserialize map. */
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &map_payload, 0, -1);
+
+               if (lttng_map_create_from_payload(&view, &map) != map_len) {
+                       ERR("Invalid map payload received in \"add map\" command");
+                       ret_code = LTTNG_ERR_INVALID_MAP;
+                       goto end;
+               }
+       }
+
+       switch (lttng_map_get_domain(map)) {
+       case LTTNG_DOMAIN_KERNEL:
+               ret_code = map_kernel_add(cmd_ctx->session->kernel_session, map);
+               if (ret_code != LTTNG_OK) {
+                       ERR("Creating a new kernel map: %s", lttng_strerror(ret_code));
+                       goto end;
+               }
+
+               ret_code = LTTNG_OK;
+               break;
+       case LTTNG_DOMAIN_UST:
+               ret = map_ust_add(cmd_ctx->session->ust_session, map);
+               if (ret) {
+                       ERR("Creating a new UST map: %s", lttng_strerror(-ret));
+                       ret_code = ret;
+                       goto end;
+               }
+
+               ret_code = LTTNG_OK;
+               break;
+       default:
+               abort();
+       }
+
+
+       {
+               struct lttng_triggers *triggers = NULL;
+               enum lttng_trigger_status t_status;
+               unsigned int count, i;
+
+               /*
+                * FRDESO: beware of moving this code. This is currently not
+                * racy because this is executed by the client thread and the
+                * client thread is the thread registering new triggers. If
+                * this code is relocate special care must be taken.
+                */
+               ret_code = notification_thread_command_list_triggers(
+                               notification_thread_handle, 0, &triggers);
+               if (ret_code != LTTNG_OK) {
+                       ret = -1;
+                       goto end;
+               }
+
+               assert(triggers);
+
+               t_status = lttng_triggers_get_count(triggers, &count);
+               if (t_status != LTTNG_TRIGGER_STATUS_OK) {
+                       ret = -1;
+                       lttng_triggers_destroy(triggers);
+                       goto end;
+               }
+
+               for (i = 0; i < count; i++) {
+                       const struct lttng_trigger *trigger;
+
+                       trigger = lttng_triggers_get_at_index(triggers, i);
+                       assert(trigger);
+
+                       ret_code = sync_all_tracer_executed_actions(trigger,
+                                       &cmd_creds, TRACER_EXECUTED_ACTION_STATE_REGISTER);
+                       assert(ret_code == LTTNG_OK);
+               }
+
+               lttng_triggers_destroy(triggers);
+       }
+
+       lttng_map_put(map);
+
+end:
+       lttng_payload_reset(&map_payload);
+       return ret_code;
+}
+
+enum lttng_error_code cmd_enable_map(struct ltt_session *session,
+               enum lttng_domain_type domain, char *map_name)
+{
+       struct ltt_ust_session *usess = session->ust_session;
+       enum lttng_error_code ret_code;
+
+       DBG("Enabling map %s for session %s", map_name, session->name);
+
+       rcu_read_lock();
+
+       switch (domain) {
+       case LTTNG_DOMAIN_KERNEL:
+       {
+               struct ltt_kernel_map *kmap;
+               struct ltt_kernel_session *ksess = session->kernel_session;
+
+               kmap = trace_kernel_get_map_by_name(map_name, ksess);
+               if (kmap == NULL) {
+                       ret_code = LTTNG_ERR_KERNEL_MAP_NOT_FOUND;
+                       goto error;
+               }
+
+               ret_code = map_kernel_enable(ksess, kmap);
+               if (ret_code != LTTNG_OK) {
+                       goto error;
+               }
+               break;
+       }
+       case LTTNG_DOMAIN_UST:
+       {
+               struct ltt_ust_map *umap;
+               struct lttng_ht *map_ht;
+
+               map_ht = usess->domain_global.maps;
+
+               umap = trace_ust_find_map_by_name(map_ht, map_name);
+               if (umap == NULL) {
+                       ret_code = LTTNG_ERR_UST_MAP_NOT_FOUND;
+                       goto error;
+               }
+
+               ret_code = map_ust_enable(usess, umap);
+               if (ret_code != LTTNG_OK) {
+                       goto error;
+               }
+               break;
+       }
+       default:
+               abort();
+       }
+
+       ret_code = LTTNG_OK;
+error:
+       rcu_read_unlock();
+       return ret_code;
+}
+
+enum lttng_error_code cmd_disable_map(struct ltt_session *session,
+               enum lttng_domain_type domain, char *map_name)
+{
+       enum lttng_error_code ret_code;
+
+       rcu_read_lock();
+
+       switch (domain) {
+       case LTTNG_DOMAIN_KERNEL:
+       {
+               struct ltt_kernel_map *kmap;
+               struct ltt_kernel_session *ksess = session->kernel_session;
+
+               kmap = trace_kernel_get_map_by_name(map_name, ksess);
+               if (kmap == NULL) {
+                       ret_code = LTTNG_ERR_KERNEL_MAP_NOT_FOUND;
+                       goto error;
+               }
+
+               ret_code = map_kernel_disable(ksess, kmap);
+               if (ret_code != LTTNG_OK) {
+                       goto error;
+               }
+               break;
+       }
+       case LTTNG_DOMAIN_UST:
+       {
+               struct ltt_ust_map *umap;
+               struct lttng_ht *map_ht;
+               struct ltt_ust_session *usess = session->ust_session;
+
+               assert(usess);
+
+               map_ht = usess->domain_global.maps;
+
+               umap = trace_ust_find_map_by_name(map_ht, map_name);
+               if (umap == NULL) {
+                       ret_code = LTTNG_ERR_UST_MAP_NOT_FOUND;
+                       goto error;
+               }
+
+               ret_code = map_ust_disable(usess, umap);
+               if (ret_code != LTTNG_OK) {
+                       goto error;
+               }
+               break;
+       }
+       default:
+               abort();
+       }
+
+       ret_code = LTTNG_OK;
+
+error:
+       rcu_read_unlock();
+       return ret_code;
+}
+
 enum lttng_error_code cmd_process_attr_tracker_get_tracking_policy(
                struct ltt_session *session,
                enum lttng_domain_type domain,
@@ -2594,7 +3168,7 @@ ssize_t cmd_list_syscalls(struct lttng_event **events)
 int cmd_start_trace(struct ltt_session *session)
 {
        enum lttng_error_code ret;
-       unsigned long nb_chan = 0;
+       unsigned long nb_chan = 0, nb_map = 0;
        struct ltt_kernel_session *ksession;
        struct ltt_ust_session *usess;
        const bool session_rotated_after_last_stop =
@@ -2637,11 +3211,13 @@ int cmd_start_trace(struct ltt_session *session)
         */
        if (usess && usess->domain_global.channels) {
                nb_chan += lttng_ht_get_count(usess->domain_global.channels);
+               nb_map += lttng_ht_get_count(usess->domain_global.maps);
        }
        if (ksession) {
                nb_chan += ksession->channel_count;
+               nb_map += ksession->map_count;
        }
-       if (!nb_chan) {
+       if (!nb_chan && !nb_map) {
                ret = LTTNG_ERR_NO_CHANNEL;
                goto error;
        }
@@ -3653,6 +4229,64 @@ end:
        return ret;
 }
 
+enum lttng_error_code cmd_list_maps(enum lttng_domain_type domain,
+               struct ltt_session *session,
+               struct lttng_map_list **return_map_list)
+{
+       enum lttng_error_code ret_code;
+       struct lttng_map_list *map_list = NULL;
+
+       map_list = lttng_map_list_create();
+
+       switch (domain) {
+       case LTTNG_DOMAIN_KERNEL:
+               if (session->kernel_session != NULL) {
+                       struct ltt_kernel_map *kmap;
+                       cds_list_for_each_entry(kmap,
+                                       &session->kernel_session->map_list.head, list) {
+                               enum lttng_map_status map_status;
+                               map_status = lttng_map_list_add(map_list, kmap->map);
+                               if (map_status != LTTNG_MAP_STATUS_OK) {
+                                       ERR("Error appending kernel map to list");
+                                       ret_code = LTTNG_ERR_FATAL;
+                                       break;
+                               }
+                       }
+
+               }
+               break;
+       case LTTNG_DOMAIN_UST:
+       {
+               struct ltt_ust_map *umap;
+               struct lttng_ht_iter iter;
+
+               rcu_read_lock();
+               cds_lfht_for_each_entry(session->ust_session->domain_global.maps->ht,
+                               &iter.iter, umap, node.node) {
+                       enum lttng_map_status map_status;
+                       map_status = lttng_map_list_add(map_list, umap->map);
+                       if (map_status != LTTNG_MAP_STATUS_OK) {
+                               ERR("Error appending UST map to list");
+                               ret_code = LTTNG_ERR_FATAL;
+                               break;
+                       }
+               }
+               rcu_read_unlock();
+               break;
+       }
+       default:
+               ret_code = LTTNG_ERR_UND;
+               goto end;
+       }
+
+       *return_map_list = map_list;
+       map_list = NULL;
+       ret_code = LTTNG_OK;
+end:
+       lttng_map_list_destroy(map_list);
+       return ret_code;
+}
+
 /*
  * Command LTTNG_LIST_EVENTS processed by the client thread.
  */
@@ -4293,21 +4927,82 @@ end:
        return ret;
 }
 
-static enum lttng_error_code trigger_modifies_event_notifier(
-               const struct lttng_trigger *trigger, bool *adds_event_notifier)
+static
+enum lttng_error_code synchronize_tracer_notifier_register(
+               struct notification_thread_handle *notification_thread,
+               struct lttng_trigger *trigger, const struct lttng_credentials *cmd_creds)
 {
-       enum lttng_error_code ret_code = LTTNG_OK;
-       const struct lttng_condition *condition = NULL;
+       enum lttng_error_code ret_code;
+       struct lttng_condition *condition = lttng_trigger_get_condition(trigger);
+       const char *trigger_name;
+       uid_t trigger_owner;
+       enum lttng_trigger_status trigger_status;
+       const enum lttng_domain_type trigger_domain =
+                       lttng_trigger_get_underlying_domain_type_restriction(
+                                       trigger);
 
-       condition = lttng_trigger_get_const_condition(trigger);
-       if (!condition) {
-               ret_code = LTTNG_ERR_INVALID_TRIGGER;
-               goto end;
+       trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_owner);
+       assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       assert(condition);
+       assert(lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_ON_EVENT);
+
+       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+       trigger_name = trigger_status == LTTNG_TRIGGER_STATUS_OK ? trigger_name : "(unnamed)";
+
+       session_lock_list();
+       switch (trigger_domain) {
+       case LTTNG_DOMAIN_KERNEL:
+       {
+               ret_code = kernel_register_event_notifier(trigger, cmd_creds);
+               if (ret_code != LTTNG_OK) {
+                       enum lttng_error_code notif_thread_unregister_ret;
+
+                       notif_thread_unregister_ret =
+                                       notification_thread_command_unregister_trigger(
+                                               notification_thread, trigger);
+
+                       if (notif_thread_unregister_ret != LTTNG_OK) {
+                               /* Return the original error code. */
+                               ERR("Failed to unregister trigger from notification thread during error recovery: trigger name = '%s', trigger owner uid = %d, error code = %d",
+                                               trigger_name,
+                                               (int) trigger_owner,
+                                               ret_code);
+                       }
+               }
+               break;
+       }
+       case LTTNG_DOMAIN_UST:
+               ust_app_global_update_all_event_notifier_rules();
+               break;
+       case LTTNG_DOMAIN_NONE:
+               abort();
+       default:
+       {
+               /* Agent domains. */
+               struct agent *agt = agent_find_by_event_notifier_domain(
+                               trigger_domain);
+               if (!agt) {
+                       agt = agent_create(trigger_domain);
+                       if (!agt) {
+                               ret_code = LTTNG_ERR_NOMEM;
+                               goto end_unlock_session_list;
+                       }
+                       agent_add(agt, trigger_agents_ht_by_domain);
+               }
+
+               ret_code = trigger_agent_enable(trigger, agt);
+               if (ret_code != LTTNG_OK) {
+                       goto end_unlock_session_list;
+               }
+
+               break;
+       }
        }
 
-       *adds_event_notifier = lttng_condition_get_type(condition) ==
-                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT;
-end:
+       ret_code = LTTNG_OK;
+end_unlock_session_list:
+       session_unlock_list();
        return ret_code;
 }
 
@@ -4317,8 +5012,8 @@ enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_c
                struct lttng_trigger **return_trigger)
 {
        enum lttng_error_code ret_code;
-       bool must_update_event_notifiers;
        const char *trigger_name;
+       const struct lttng_condition *condition;
        uid_t trigger_owner;
        enum lttng_trigger_status trigger_status;
 
@@ -4334,7 +5029,7 @@ enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_c
                        trigger_name, (int) trigger_owner,
                        (int) lttng_credentials_get_uid(cmd_creds));
 
-       /*
+/*
         * Validate the trigger credentials against the command credentials.
         * Only the root user can register a trigger with non-matching
         * credentials.
@@ -4384,72 +5079,30 @@ enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_c
        trigger_name = trigger_status == LTTNG_TRIGGER_STATUS_OK ?
                        trigger_name : "(unnamed)";
 
-       ret_code = trigger_modifies_event_notifier(trigger, &must_update_event_notifiers);
-       if (ret_code != LTTNG_OK) {
-               ERR("Failed to determine if event modifies event notifiers: trigger name = '%s', trigger owner uid = %d, error code = %d",
-                               trigger_name, (int) trigger_owner, ret_code);
-               goto end;
-       }
-
        /*
         * Synchronize tracers if the trigger adds an event notifier.
         */
-       if (must_update_event_notifiers) {
-               const enum lttng_domain_type trigger_domain =
-                               lttng_trigger_get_underlying_domain_type_restriction(trigger);
-
-               session_lock_list();
-               switch (trigger_domain) {
-               case LTTNG_DOMAIN_KERNEL:
-               {
-                       ret_code = kernel_register_event_notifier(
-                                       trigger, cmd_creds);
-                       if (ret_code != LTTNG_OK) {
-                               const enum lttng_error_code notif_thread_unregister_ret =
-                                               notification_thread_command_unregister_trigger(
-                                                               notification_thread,
-                                                               trigger);
-
-                               if (notif_thread_unregister_ret != LTTNG_OK) {
-                                       /* Return the original error code. */
-                                       ERR("Failed to unregister trigger from notification thread during error recovery: trigger name = '%s', trigger owner uid = %d, error code = %d",
-                                                       trigger_name,
-                                                       (int) trigger_owner,
-                                                       ret_code);
-                               }
-                       }
-                       break;
+       if (lttng_trigger_needs_tracer_notifier(trigger)) {
+               ret_code = synchronize_tracer_notifier_register(notification_thread,
+                               trigger, cmd_creds);
+               if (ret_code != LTTNG_OK) {
+                       ERR("Error registering tracer notifier");
+                       goto end;
                }
-               case LTTNG_DOMAIN_UST:
-                       ust_app_global_update_all_event_notifier_rules();
-                       break;
-               case LTTNG_DOMAIN_NONE:
-                       abort();
-               default:
-               {
-                       /* Agent domains. */
-                       struct agent *agt = agent_find_by_event_notifier_domain(
-                                       trigger_domain);
-
-                       if (!agt) {
-                               agt = agent_create(trigger_domain);
-                               if (!agt) {
-                                       ret_code = LTTNG_ERR_NOMEM;
-                                       goto end_unlock_session_list;
-                               }
-                               agent_add(agt, trigger_agents_ht_by_domain);
-                       }
-
-                       ret_code = trigger_agent_enable(trigger, agt);
-                       if (ret_code != LTTNG_OK) {
-                               goto end_unlock_session_list;
-                       }
+       }
 
-                       break;
-               }
-               }
+       condition = lttng_trigger_get_const_condition(trigger);
 
+       /* TODO: Extract condition below to lttng_trigger internal function */
+       if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_ON_EVENT) {
+               session_lock_list();
+               ret_code = sync_all_tracer_executed_actions(trigger,
+                               cmd_creds, TRACER_EXECUTED_ACTION_STATE_REGISTER);
                session_unlock_list();
+               if (ret_code != LTTNG_OK) {
+                       ERR("Error registering tracer executed actions");
+                       goto end;
+               }
        }
 
        /*
@@ -4467,6 +5120,57 @@ enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_c
        }
 end:
        return ret_code;
+}
+
+static
+enum lttng_error_code synchronize_tracer_notifier_unregister(
+               const struct lttng_trigger *trigger)
+{
+       enum lttng_error_code ret_code;
+       const struct lttng_condition *condition =
+                       lttng_trigger_get_const_condition(trigger);
+       const enum lttng_domain_type trigger_domain =
+                       lttng_trigger_get_underlying_domain_type_restriction(
+                                       trigger);
+
+       assert(condition);
+       assert(lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_ON_EVENT);
+
+       session_lock_list();
+       switch (trigger_domain) {
+       case LTTNG_DOMAIN_KERNEL:
+               ret_code = kernel_unregister_event_notifier(trigger);
+               break;
+       case LTTNG_DOMAIN_UST:
+               ust_app_global_update_all_event_notifier_rules();
+               break;
+       case LTTNG_DOMAIN_NONE:
+               abort();
+       default:
+       {
+               /* Agent domains. */
+               struct agent *agt = agent_find_by_event_notifier_domain(
+                               trigger_domain);
+               if (!agt) {
+                       agt = agent_create(trigger_domain);
+                       if (!agt) {
+                               ret_code = LTTNG_ERR_NOMEM;
+                               goto end_unlock_session_list;
+                       }
+                       agent_add(agt, trigger_agents_ht_by_domain);
+               }
+
+               ret_code = trigger_agent_disable(trigger, agt);
+               if (ret_code != LTTNG_OK) {
+                       goto end_unlock_session_list;
+               }
+
+               break;
+       }
+       }
+
+       ret_code = LTTNG_OK;
+
 end_unlock_session_list:
        session_unlock_list();
        return ret_code;
@@ -4477,15 +5181,14 @@ enum lttng_error_code cmd_unregister_trigger(const struct lttng_credentials *cmd
                struct notification_thread_handle *notification_thread)
 {
        enum lttng_error_code ret_code;
-       bool must_update_event_notifiers;
        const char *trigger_name;
+       struct lttng_trigger *real_trigger;
        uid_t trigger_owner;
        enum lttng_trigger_status trigger_status;
 
        trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
        trigger_name = trigger_status == LTTNG_TRIGGER_STATUS_OK ? trigger_name : "(unnamed)";
-       trigger_status = lttng_trigger_get_owner_uid(
-               trigger, &trigger_owner);
+       trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_owner);
        assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
 
        DBG("Running unregister trigger command: trigger name = '%s', trigger owner uid = %d, command creds uid = %d",
@@ -4509,18 +5212,20 @@ enum lttng_error_code cmd_unregister_trigger(const struct lttng_credentials *cmd
                }
        }
 
-       ret_code = trigger_modifies_event_notifier(trigger, &must_update_event_notifiers);
+       ret_code = notification_thread_command_get_trigger(
+                       notification_thread, trigger, &real_trigger);
        if (ret_code != LTTNG_OK) {
-               ERR("Failed to determine if event modifies event notifiers: trigger name = '%s', trigger owner uid = %d, error code = %d",
+               DBG("Failed to get the real trigger from notification thread: trigger name = '%s', trigger owner uid = %d, error code = %d",
                                trigger_name, (int) trigger_owner, ret_code);
                goto end;
        }
 
-       ret_code = notification_thread_command_unregister_trigger(notification_thread,
-                                                                 trigger);
+       ret_code = notification_thread_command_unregister_trigger(
+                       notification_thread, real_trigger);
        if (ret_code != LTTNG_OK) {
                DBG("Failed to unregister trigger from notification thread: trigger name = '%s', trigger owner uid = %d, error code = %d",
                                trigger_name, (int) trigger_owner, ret_code);
+               goto end;
        }
 
        /*
@@ -4529,56 +5234,28 @@ enum lttng_error_code cmd_unregister_trigger(const struct lttng_credentials *cmd
         * the tracers from producing notifications associated with this
         * event notifier.
         */
-       if (must_update_event_notifiers) {
-               const enum lttng_domain_type trigger_domain =
-                               lttng_trigger_get_underlying_domain_type_restriction(
-                                               trigger);
-
-               session_lock_list();
-               switch (trigger_domain) {
-               case LTTNG_DOMAIN_KERNEL:
-               {
-                       ret_code = kernel_unregister_event_notifier(
-                                       trigger);
-                       break;
+       if (lttng_trigger_needs_tracer_notifier(real_trigger)) {
+               ret_code = synchronize_tracer_notifier_unregister(real_trigger);
+               if (ret_code != LTTNG_OK) {
+                       ERR("Error unregistering trigger to tracer.");
+                       goto end;
                }
-               case LTTNG_DOMAIN_UST:
-                       ust_app_global_update_all_event_notifier_rules();
-                       break;
-               case LTTNG_DOMAIN_NONE:
-                       abort();
-               default:
-               {
-                       /* Agent domains. */
-                       struct agent *agt = agent_find_by_event_notifier_domain(
-                                       trigger_domain);
-
-                       if (!agt) {
-                               agt = agent_create(trigger_domain);
-                               if (!agt) {
-                                       ret_code = LTTNG_ERR_NOMEM;
-                                       goto end_unlock_session_list;
-                               }
-                               agent_add(agt, trigger_agents_ht_by_domain);
-                       }
-
-                       ret_code = trigger_agent_disable(trigger, agt);
-                       if (ret_code != LTTNG_OK) {
-                               goto end_unlock_session_list;
-                       }
 
-                       break;
-               }
-               }
+       }
 
-               session_unlock_list();
+       session_lock_list();
+       ret_code = sync_all_tracer_executed_actions(real_trigger,
+                       cmd_creds, TRACER_EXECUTED_ACTION_STATE_UNREGISTER);
+       session_unlock_list();
+       if (ret_code != LTTNG_OK) {
+               ERR("Error registering tracer executed actions");
+               goto end;
        }
 
+       lttng_trigger_put(real_trigger);
 end:
        return ret_code;
-end_unlock_session_list:
-       session_unlock_list();
-       return ret_code;}
+}
 
 int cmd_list_triggers(struct command_ctx *cmd_ctx,
                struct notification_thread_handle *notification_thread,
@@ -4603,6 +5280,76 @@ end:
        lttng_triggers_destroy(triggers);
        return ret;
 }
+
+int cmd_list_map_values(const char *session_name,
+               const struct lttng_map *map,
+               const struct lttng_map_query *map_query,
+               struct lttng_map_content **return_map_content)
+{
+       enum lttng_error_code ret;
+       struct ltt_session *session;
+       enum lttng_domain_type domain;
+       const char *map_name;
+       enum lttng_map_status map_status;
+
+       /* Returns a refcounted reference */
+       session = session_find_by_name(session_name);
+       if (!session) {
+               DBG("Session '%s' not found", session_name);
+               ret = LTTNG_ERR_SESS_NOT_FOUND;
+               goto end;
+       }
+
+       domain = lttng_map_get_domain(map);
+
+       map_status = lttng_map_get_name(map, &map_name);
+       assert(map_status == LTTNG_MAP_STATUS_OK);
+
+       if (domain == LTTNG_DOMAIN_KERNEL) {
+               if (session->kernel_session) {
+                       struct ltt_kernel_map *kmap;
+
+                       kmap = trace_kernel_get_map_by_name(map_name,
+                               session->kernel_session);
+                       if (kmap) {
+                               ret = kernel_list_map_values(kmap, map_query,
+                                       return_map_content);
+                               if (ret != LTTNG_OK) {
+                                       ERR("Error listing kernel map '%s' values", map_name);
+                                       goto end;
+                               }
+                       } else {
+                               DBG("No kernel map '%s' in session '%s'", map_name, session_name);
+                       }
+               }
+       } else if (domain == LTTNG_DOMAIN_UST) {
+               if (session->ust_session) {
+                       struct ltt_ust_map *umap;
+                       struct ltt_ust_session *usess = session->ust_session;
+
+                       umap = trace_ust_find_map_by_name(
+                               usess->domain_global.maps, map_name);
+                       if (umap) {
+                               ret = ust_app_map_list_values(usess, umap,
+                                               map_query, return_map_content);
+                               if (ret) {
+                                       ret = LTTNG_ERR_MAP_VALUES_LIST_FAIL;
+                                       ERR("Error listing UST map '%s' values", map_name);
+                                       goto end;
+                               }
+                       } else {
+                               DBG("No UST map '%s' in session '%s'", map_name, session_name);
+                       }
+               }
+       }
+
+
+       ret = LTTNG_OK;
+end:
+       session_put(session);
+       return ret;
+}
+
 /*
  * Send relayd sockets from snapshot output to consumer. Ignore request if the
  * snapshot output is *not* set with a remote destination.
index dcda2365dd0a134d3075c4f1a81af3bf25cdefec..898eba2ed7f6d30ad59a7999b9c0d07a4435f035 100644 (file)
 
 #include "context.h"
 #include "lttng-sessiond.h"
+#include "lttng/map/map.h"
 #include "lttng/tracker.h"
 #include "session.h"
 #include <common/tracker.h>
 
+
 struct notification_thread_handle;
 
 /*
@@ -49,6 +51,13 @@ int cmd_disable_channel(struct ltt_session *session,
 int cmd_enable_channel(struct ltt_session *session,
                const struct lttng_domain *domain, const struct lttng_channel *attr,
                int wpipe);
+enum lttng_error_code cmd_add_map(struct command_ctx *cmd_ctx, int sock);
+
+enum lttng_error_code cmd_enable_map(struct ltt_session *session,
+               enum lttng_domain_type domain, char *map_name);
+
+enum lttng_error_code cmd_disable_map(struct ltt_session *session,
+               enum lttng_domain_type domain, char *map_name);
 
 /* Process attribute tracker commands */
 enum lttng_error_code cmd_process_attr_tracker_get_tracking_policy(
@@ -114,6 +123,9 @@ ssize_t cmd_list_events(enum lttng_domain_type domain,
                struct lttng_payload *payload);
 ssize_t cmd_list_channels(enum lttng_domain_type domain,
                struct ltt_session *session, struct lttng_channel **channels);
+enum lttng_error_code cmd_list_maps(enum lttng_domain_type domain,
+               struct ltt_session *session,
+               struct lttng_map_list **return_map_list);
 ssize_t cmd_list_domains(struct ltt_session *session,
                struct lttng_domain **domains);
 void cmd_list_lttng_sessions(struct lttng_session *sessions,
@@ -167,6 +179,10 @@ int cmd_rotation_set_schedule(struct ltt_session *session,
                uint64_t value,
                struct notification_thread_handle *notification_thread_handle);
 
+int cmd_list_map_values(const char *session_name, const struct lttng_map *map,
+               const struct lttng_map_query *map_query,
+               struct lttng_map_content **return_map_content);
+
 const struct cmd_completion_handler *cmd_pop_completion_handler(void);
 int start_kernel_session(struct ltt_kernel_session *ksess);
 int stop_kernel_session(struct ltt_kernel_session *ksess);
index dc21ca3afbc5931a09850b5625e7784d3984b52b..bde25ea73c0c0997167ffebdfce42b62cf40360f 100644 (file)
 #include <lttng/condition/buffer-usage-internal.h>
 #include <lttng/condition/session-consumed-size-internal.h>
 #include <lttng/condition/session-rotation-internal.h>
-#include <lttng/condition/event-rule-internal.h>
-#include <lttng/condition/event-rule.h>
+#include <lttng/condition/on-event-internal.h>
+#include <lttng/condition/on-event.h>
 #include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/condition/on-event-internal.h>
 #include "condition-internal.h"
 
 static
@@ -95,7 +96,7 @@ unsigned long lttng_condition_session_rotation_hash(
 }
 
 static
-unsigned long lttng_condition_event_rule_hash(
+unsigned long lttng_condition_on_event_hash(
        const struct lttng_condition *condition)
 {
        unsigned long hash, condition_type;
@@ -103,8 +104,7 @@ unsigned long lttng_condition_event_rule_hash(
        const struct lttng_event_rule *event_rule;
 
        condition_type = (unsigned long) condition->type;
-
-       condition_status = lttng_condition_event_rule_get_rule(condition,
+       condition_status = lttng_condition_on_event_get_rule(condition,
                        &event_rule);
        assert(condition_status == LTTNG_CONDITION_STATUS_OK);
 
@@ -128,10 +128,41 @@ unsigned long lttng_condition_hash(const struct lttng_condition *condition)
        case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
        case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
                return lttng_condition_session_rotation_hash(condition);
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
-               return lttng_condition_event_rule_hash(condition);
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
+               return lttng_condition_on_event_hash(condition);
        default:
                //ERR("[notification-thread] Unexpected condition type caught");
                abort();
        }
 }
+
+LTTNG_HIDDEN
+struct lttng_condition *lttng_condition_copy(const struct lttng_condition *condition)
+{
+       int ret;
+       struct lttng_payload copy_buffer;
+       struct lttng_condition *copy = NULL;
+
+       lttng_payload_init(&copy_buffer);
+
+       ret = lttng_condition_serialize(condition, &copy_buffer);
+       if (ret < 0) {
+               goto end;
+       }
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &copy_buffer, 0, -1);
+               ret = lttng_condition_create_from_payload(
+                               &view, &copy);
+               if (ret < 0) {
+                       copy = NULL;
+                       goto end;
+               }
+       }
+
+end:
+       lttng_payload_reset(&copy_buffer);
+       return copy;
+}
index 2863f7bd8d37d87c19688f1442d77e0665519ddc..270a8b1afbf3da33919c3e7864bf6908ff12da44 100644 (file)
@@ -17,4 +17,6 @@
  */
 unsigned long lttng_condition_hash(const struct lttng_condition *condition);
 
+struct lttng_condition *lttng_condition_copy(
+               const struct lttng_condition *condition);
 #endif /* LTTNG_SESSIOND_CONDITION_INTERNAL_H */
index d33a3cba8fac0d231aabd527400b83adc7645d6f..5748223d7f76f04919204ef7e9f8666139c8ff54 100644 (file)
@@ -63,10 +63,13 @@ static void update_ust_app(int app_sock)
 
        /* For all tracing session(s) */
        cds_list_for_each_entry_safe(sess, stmp, &session_list->head, list) {
+
                if (!session_get(sess)) {
                        continue;
                }
                session_lock(sess);
+
+
                if (!sess->active || !sess->ust_session) {
                        goto unlock_session;
                }
diff --git a/src/bin/lttng-sessiond/event-notifier-error-accounting.c b/src/bin/lttng-sessiond/event-notifier-error-accounting.c
new file mode 100644 (file)
index 0000000..aea0548
--- /dev/null
@@ -0,0 +1,820 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <urcu/compiler.h>
+#include <pthread.h>
+
+#include <common/error.h>
+#include <common/hashtable/hashtable.h>
+#include <common/index-allocator.h>
+#include <common/kernel-ctl/kernel-ctl.h>
+#include <common/shm.h>
+#include <lttng/trigger/trigger-internal.h>
+
+#include "event-notifier-error-accounting.h"
+#include "lttng-ust-error.h"
+#include "ust-app.h"
+
+struct index_ht_entry {
+       struct lttng_ht_node_u64 node;
+       uint64_t error_counter_index;
+       struct rcu_head rcu_head;
+};
+
+struct error_account_entry {
+       struct lttng_ht_node_u64 node;
+       struct rcu_head rcu_head;
+       struct ustctl_daemon_counter *daemon_counter;
+       /*
+        * Those `lttng_ust_object_data` are anonymous handles to the counters
+        * objects.
+        * They are only used to be duplicated for each new applications of the
+        * user. To destroy them, call with the `sock` parameter set to -1.
+        * e.g. `ustctl_release_object(-1, data)`;
+        */
+       struct lttng_ust_object_data *counter;
+       struct lttng_ust_object_data **cpu_counters;
+       int nr_counter_cpu_fds;
+};
+
+struct kernel_error_account_entry {
+       int kernel_event_notifier_error_counter_fd;
+};
+
+static struct kernel_error_account_entry kernel_error_accountant = { 0 };
+
+/* Hashtable mapping event notifier token to index_ht_entry */
+static struct lttng_ht *error_counter_indexes_ht;
+
+/* Hashtable mapping uid to error_account_entry */
+static struct lttng_ht *error_counter_uid_ht;
+
+static uint64_t error_counter_size = 0;
+struct lttng_index_allocator *index_allocator;
+
+static inline
+const char *error_accounting_status_str(
+               enum event_notifier_error_accounting_status status)
+{
+       switch (status) {
+       case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK:
+               return "OK";
+       case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR:
+               return "ERROR";
+       case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND:
+               return "NOT_FOUND";
+       case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM:
+               return "NOMEM";
+       case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE:
+               return "NO_INDEX_AVAILABLE";
+       case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD:
+               return "APP_DEAD";
+       default:
+               abort();
+       }
+}
+
+enum event_notifier_error_accounting_status
+event_notifier_error_accounting_init(uint64_t nb_bucket)
+{
+       enum event_notifier_error_accounting_status status;
+
+       index_allocator = lttng_index_allocator_create(nb_bucket);
+       if (!index_allocator) {
+               ERR("Failed to allocate event notifier error counter index");
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM;
+               goto error_index_allocator;
+       }
+
+       error_counter_indexes_ht = lttng_ht_new(16, LTTNG_HT_TYPE_U64);
+       error_counter_uid_ht = lttng_ht_new(16, LTTNG_HT_TYPE_U64);
+       error_counter_size = nb_bucket;
+
+       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+
+error_index_allocator:
+       return status;
+}
+
+static
+enum event_notifier_error_accounting_status get_error_counter_index_for_token(
+               uint64_t tracer_token, uint64_t *error_counter_index)
+{
+       struct lttng_ht_node_u64 *node;
+       struct lttng_ht_iter iter;
+       struct index_ht_entry *index_entry;;
+       enum event_notifier_error_accounting_status status;
+
+       lttng_ht_lookup(error_counter_indexes_ht, &tracer_token, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if (node) {
+               index_entry = caa_container_of(node, struct index_ht_entry, node);
+               *error_counter_index = index_entry->error_counter_index;
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+       } else {
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND;
+       }
+
+       return status;
+}
+
+#ifdef HAVE_LIBLTTNG_UST_CTL
+static
+struct error_account_entry *get_uid_accounting_entry(const struct ust_app *app)
+{
+       struct error_account_entry *entry;
+       struct lttng_ht_node_u64 *node;
+       struct lttng_ht_iter iter;
+       uint64_t key = app->uid;
+
+       lttng_ht_lookup(error_counter_uid_ht, &key, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if(node == NULL) {
+               entry = NULL;
+       } else {
+               entry = caa_container_of(node, struct error_account_entry, node);
+       }
+
+       return entry;
+}
+
+static
+struct error_account_entry *create_uid_accounting_entry(
+               const struct ust_app *app)
+{
+       int i, ret;
+       struct ustctl_counter_dimension dimension[1] = {0};
+       struct ustctl_daemon_counter *daemon_counter;
+       struct lttng_ust_object_data *counter, **counter_cpus;
+       int *counter_cpu_fds;
+       struct error_account_entry *entry = NULL;
+
+       entry = zmalloc(sizeof(struct error_account_entry));
+       if (!entry) {
+               PERROR("Allocating event notifier error acounting entry")
+               goto error;
+       }
+
+       entry->nr_counter_cpu_fds = ustctl_get_nr_cpu_per_counter();
+       counter_cpu_fds = zmalloc(entry->nr_counter_cpu_fds * sizeof(*counter_cpu_fds));
+       if (!counter_cpu_fds) {
+               ret = -1;
+               goto error_counter_cpu_fds_alloc;
+       }
+
+       counter_cpus = zmalloc(entry->nr_counter_cpu_fds * sizeof(**counter_cpus));
+       if (!counter_cpus) {
+               ret = -1;
+               goto error_counter_cpus_alloc;
+       }
+
+       for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
+               counter_cpu_fds[i] = shm_create_anonymous("event-notifier-error-accounting");
+               //FIXME error handling
+       }
+
+
+       dimension[0].size = error_counter_size;
+       dimension[0].has_underflow = false;
+       dimension[0].has_overflow = false;
+
+       daemon_counter = ustctl_create_counter(1, dimension, 0, -1,
+                       entry->nr_counter_cpu_fds, counter_cpu_fds,
+                       USTCTL_COUNTER_BITNESS_32,
+                       USTCTL_COUNTER_ARITHMETIC_MODULAR,
+                       USTCTL_COUNTER_ALLOC_PER_CPU,
+                       false);
+       assert(daemon_counter);
+
+       ret = ustctl_create_counter_data(daemon_counter, &counter);
+       assert(ret == 0);
+
+       for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
+               ret = ustctl_create_counter_cpu_data(daemon_counter, i,
+                               &counter_cpus[i]);
+               assert(ret == 0);
+       }
+
+       entry->daemon_counter = daemon_counter;
+       entry->counter = counter;
+       entry->cpu_counters = counter_cpus;
+
+       lttng_ht_node_init_u64(&entry->node, app->uid);
+       lttng_ht_add_unique_u64(error_counter_uid_ht, &entry->node);
+
+       free(counter_cpu_fds);
+
+       goto end;
+
+error_counter_cpus_alloc:
+       free(counter_cpu_fds);
+error_counter_cpu_fds_alloc:
+       free(entry);
+error:
+       entry = NULL;
+end:
+       return entry;
+}
+
+static
+enum event_notifier_error_accounting_status send_counter_data_to_ust(
+               struct ust_app *app,
+               struct lttng_ust_object_data *new_counter)
+{
+       int ret;
+       enum event_notifier_error_accounting_status status;
+
+       /* Attach counter to trigger group */
+       pthread_mutex_lock(&app->sock_lock);
+       ret = ustctl_send_counter_data_to_ust(app->sock,
+                       app->event_notifier_group.object->handle, new_counter);
+       pthread_mutex_unlock(&app->sock_lock);
+       if (ret < 0) {
+               if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("Error ustctl send counter data to app pid: %d with ret %d",
+                                       app->pid, ret);
+                       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
+               } else {
+                       DBG3("UST app send counter data to ust failed. Application is dead.");
+                       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD;
+               }
+               goto end;
+       }
+
+       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+end:
+       return status;
+}
+
+static
+enum event_notifier_error_accounting_status send_counter_cpu_data_to_ust(
+               struct ust_app *app,
+               struct lttng_ust_object_data *counter,
+               struct lttng_ust_object_data *counter_cpu)
+{
+       int ret;
+       enum event_notifier_error_accounting_status status;
+
+       pthread_mutex_lock(&app->sock_lock);
+       ret = ustctl_send_counter_cpu_data_to_ust(app->sock,
+                       counter, counter_cpu);
+       pthread_mutex_unlock(&app->sock_lock);
+       if (ret < 0) {
+               if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("Error ustctl send counter cpu data to app pid: %d with ret %d",
+                                       app->pid, ret);
+                       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
+               } else {
+                       DBG3("UST app send counter cpu data to ust failed. Application is dead.");
+                       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD;
+               }
+               goto end;
+       }
+
+       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+end:
+       return status;
+}
+
+enum event_notifier_error_accounting_status event_notifier_error_accounting_register_app(
+               struct ust_app *app)
+{
+       int ret;
+       uint64_t i;
+       struct lttng_ust_object_data *new_counter;
+       struct error_account_entry *entry;
+       enum event_notifier_error_accounting_status status;
+
+       /*
+        * Check if we already have a error counter for the user id of this
+        * app. If not, create one.
+        */
+       rcu_read_lock();
+       entry = get_uid_accounting_entry(app);
+       if (entry == NULL) {
+               entry = create_uid_accounting_entry(app);
+       }
+
+       /* Duplicate counter object data*/
+       ret = ustctl_duplicate_ust_object_data(&new_counter,
+                       entry->counter);
+       assert(ret == 0);
+
+       status = send_counter_data_to_ust(app, new_counter);
+       if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+               ERR("Error sending counter data to UST tracer: status=%s",
+                               error_accounting_status_str(status));
+               goto end;
+       }
+
+
+       app->event_notifier_group.counter = new_counter;
+       app->event_notifier_group.nr_counter_cpu = entry->nr_counter_cpu_fds;
+       app->event_notifier_group.counter_cpu =
+                       zmalloc(entry->nr_counter_cpu_fds * sizeof(struct lttng_ust_object_data));
+
+       for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
+               struct lttng_ust_object_data *new_counter_cpu = NULL;
+
+               ret = ustctl_duplicate_ust_object_data(&new_counter_cpu,
+                               entry->cpu_counters[i]);
+               assert(ret == 0);
+
+               status = send_counter_cpu_data_to_ust(app, new_counter,
+                               new_counter_cpu);
+               if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+                       ERR("Error sending counter cpu data to UST tracer: status=%s",
+                                       error_accounting_status_str(status));
+                       goto end;
+               }
+               app->event_notifier_group.counter_cpu[i] = new_counter_cpu;
+       }
+
+end:
+       rcu_read_unlock();
+       return status;
+}
+
+enum event_notifier_error_accounting_status
+event_notifier_error_accounting_unregister_app(struct ust_app *app)
+{
+       enum event_notifier_error_accounting_status status;
+       struct error_account_entry *entry;
+       int i;
+
+       rcu_read_lock();
+       entry = get_uid_accounting_entry(app);
+       if (entry == NULL) {
+               ERR("Event notitifier error accounting entry not found on app teardown");
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
+               goto end;
+       }
+
+       for (i = 0; i < app->event_notifier_group.nr_counter_cpu; i++) {
+               ustctl_release_object(app->sock,
+                               app->event_notifier_group.counter_cpu[i]);
+               free(app->event_notifier_group.counter_cpu[i]);
+       }
+
+       free(app->event_notifier_group.counter_cpu);
+
+       ustctl_release_object(app->sock, app->event_notifier_group.counter);
+       free(app->event_notifier_group.counter);
+
+       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+end:
+       rcu_read_unlock();
+       return status;
+}
+
+static
+enum event_notifier_error_accounting_status
+event_notifier_error_accounting_ust_get_count(
+               const struct lttng_trigger *trigger, uint64_t *count)
+{
+       struct lttng_ht_iter iter;
+       struct error_account_entry *uid_entry;
+       uint64_t error_counter_index, global_sum = 0;
+       enum event_notifier_error_accounting_status status;
+       size_t dimension_indexes[1];
+
+       /*
+        * Go over all error counters (ignoring uid) as a trigger (and trigger
+        * errors) can be generated from any applications that this session
+        * daemon is managing.
+        */
+
+       rcu_read_lock();
+
+       status = get_error_counter_index_for_token(
+                       lttng_trigger_get_tracer_token(trigger), &error_counter_index);
+       if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+               ERR("Error getting index for token: status=%s",
+                               error_accounting_status_str(status));
+               goto end;
+       }
+
+       dimension_indexes[0] = error_counter_index;
+
+       cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
+                       uid_entry, node.node) {
+               int ret;
+               int64_t local_value = 0;
+               bool overflow = 0, underflow = 0;
+               ret = ustctl_counter_aggregate(uid_entry->daemon_counter,
+                               dimension_indexes, &local_value, &overflow,
+                               &underflow);
+               assert(ret == 0);
+
+               /* should always be zero or above. */
+               assert(local_value >= 0);
+               global_sum += (uint64_t) local_value;
+
+       }
+
+
+       *count = global_sum;
+       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+
+end:
+       rcu_read_unlock();
+       return status;
+}
+
+static
+enum event_notifier_error_accounting_status event_notifier_error_accounting_ust_clear(
+               const struct lttng_trigger *trigger)
+{
+       struct lttng_ht_iter iter;
+       struct error_account_entry *uid_entry;
+       uint64_t error_counter_index;
+       enum event_notifier_error_accounting_status status;
+       size_t dimension_indexes[1];
+
+       /*
+        * Go over all error counters (ignoring uid) as a trigger (and trigger
+        * errors) can be generated from any applications that this session
+        * daemon is managing.
+        */
+
+       rcu_read_lock();
+       status = get_error_counter_index_for_token(
+                       lttng_trigger_get_tracer_token(trigger),
+                       &error_counter_index);
+       if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+               ERR("Error getting index for token: status=%s",
+                               error_accounting_status_str(status));
+               goto end;
+       }
+
+       dimension_indexes[0] = error_counter_index;
+
+       cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
+                       uid_entry, node.node) {
+               int ret;
+               ret = ustctl_counter_clear(uid_entry->daemon_counter,
+                               dimension_indexes);
+               assert(ret == 0);
+       }
+
+       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+end:
+       rcu_read_unlock();
+       return status;
+}
+#endif /* HAVE_LIBLTTNG_UST_CTL */
+
+static
+enum event_notifier_error_accounting_status event_notifier_error_accounting_kernel_clear(
+               const struct lttng_trigger *trigger)
+{
+       int ret;
+       uint64_t error_counter_index;
+       enum event_notifier_error_accounting_status status;
+       struct lttng_kernel_counter_clear counter_clear = {0};
+
+       rcu_read_lock();
+       status = get_error_counter_index_for_token(
+                       lttng_trigger_get_tracer_token(trigger),
+                       &error_counter_index);
+       if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+               ERR("Error getting index for token: status=%s",
+                               error_accounting_status_str(status));
+               goto end;
+       }
+
+       counter_clear.index.number_dimensions = 1;
+       counter_clear.index.dimension_indexes[0] = error_counter_index;
+
+       ret = kernctl_counter_clear(
+                       kernel_error_accountant.kernel_event_notifier_error_counter_fd,
+                       &counter_clear);
+       if (ret) {
+               ERR("Error clearing event notifier error counter");
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
+               goto end;
+       }
+
+       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+end:
+       rcu_read_unlock();
+       return status;
+}
+
+enum event_notifier_error_accounting_status event_notifier_error_accounting_register_kernel(
+               int kernel_event_notifier_group_fd)
+{
+       int local_fd = -1, ret;
+       enum event_notifier_error_accounting_status status;
+       struct lttng_kernel_counter_conf error_counter_conf = {0};
+
+       error_counter_conf.arithmetic = LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR;
+       error_counter_conf.bitness = LTTNG_KERNEL_COUNTER_BITNESS_64;
+       error_counter_conf.global_sum_step = 0;
+       error_counter_conf.number_dimensions = 1;
+       error_counter_conf.dimensions[0].size = error_counter_size;
+       error_counter_conf.dimensions[0].has_underflow = false;
+       error_counter_conf.dimensions[0].has_overflow = false;
+
+       ret = kernctl_create_event_notifier_group_error_counter(
+                       kernel_event_notifier_group_fd, &error_counter_conf);
+       if (ret < 0) {
+               PERROR("ioctl kernel create event notifier group error counter");
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
+               goto error;
+       }
+
+       /* Store locally */
+       local_fd = ret;
+
+       /* Prevent fd duplication after execlp() */
+       ret = fcntl(local_fd, F_SETFD, FD_CLOEXEC);
+       if (ret < 0) {
+               PERROR("fcntl event notifier error counter fd");
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
+               goto error;
+       }
+
+       DBG("Kernel event notifier group error counter (fd: %d)", local_fd);
+
+       kernel_error_accountant.kernel_event_notifier_error_counter_fd = local_fd;
+       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+
+error:
+       return status;
+}
+
+static
+enum event_notifier_error_accounting_status create_error_counter_index_for_token(
+               uint64_t tracer_token, uint64_t *error_counter_index)
+{
+       struct index_ht_entry *index_entry;;
+       enum lttng_index_allocator_status index_alloc_status;
+       uint64_t local_error_counter_index;
+       enum event_notifier_error_accounting_status status;
+
+       /* Allocate a new index for that counter. */
+       index_alloc_status = lttng_index_allocator_alloc(index_allocator,
+                       &local_error_counter_index);
+       switch (index_alloc_status) {
+       case LTTNG_INDEX_ALLOCATOR_STATUS_EMPTY:
+               DBG("No more index available in the configured event notifier error counter:"
+                               "number-of-indices=%"PRIu64,
+                               lttng_index_allocator_get_index_count(
+                                       index_allocator));
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE;
+               goto end;
+       case LTTNG_INDEX_ALLOCATOR_STATUS_OK:
+               break;
+       default:
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
+               goto end;
+       }
+
+       index_entry = zmalloc(sizeof(*index_entry));
+       if (index_entry == NULL) {
+               PERROR("Event notifier error counter hashtable entry zmalloc");
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM;
+               goto end;
+       }
+
+       index_entry->error_counter_index = local_error_counter_index;
+       lttng_ht_node_init_u64(&index_entry->node, tracer_token);
+
+       lttng_ht_add_unique_u64(error_counter_indexes_ht, &index_entry->node);
+
+       *error_counter_index = local_error_counter_index;
+       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+end:
+       return status;
+}
+
+enum event_notifier_error_accounting_status event_notifier_error_accounting_register_event_notifier(
+               const struct lttng_trigger *trigger,
+               uint64_t *error_counter_index)
+{
+       enum event_notifier_error_accounting_status status;
+       uint64_t local_error_counter_index;
+
+       rcu_read_lock();
+       /*
+        * Check if this event notifier already has a error counter index
+        * assigned.
+        */
+       status = get_error_counter_index_for_token(
+                       lttng_trigger_get_tracer_token(trigger),
+                       &local_error_counter_index);
+       switch (status) {
+       case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND:
+               DBG("Event notifier error counter index for this tracer token not found. Allocating a new one.");
+               status = create_error_counter_index_for_token(
+                               lttng_trigger_get_tracer_token(trigger),
+                               &local_error_counter_index);
+               if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+                       ERR("Error creating index for token: status=%s",
+                                       error_accounting_status_str(status));
+                       goto end;
+               }
+       case EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK:
+               *error_counter_index = local_error_counter_index;
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+               break;
+       default:
+               break;
+       }
+
+end:
+       rcu_read_unlock();
+       return status;
+}
+
+static
+enum event_notifier_error_accounting_status event_notifier_error_accounting_kernel_get_count(
+               const struct lttng_trigger *trigger, uint64_t *count)
+{
+       struct lttng_kernel_counter_aggregate counter_aggregate = {0};
+       enum event_notifier_error_accounting_status status;
+       uint64_t error_counter_index;
+       int ret;
+
+       rcu_read_lock();
+       status = get_error_counter_index_for_token(
+                       lttng_trigger_get_tracer_token(trigger), &error_counter_index);
+       if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+               ERR("Error getting index for token: status=%s",
+                               error_accounting_status_str(status));
+               goto end;
+       }
+
+       counter_aggregate.index.number_dimensions = 1;
+       counter_aggregate.index.dimension_indexes[0] = error_counter_index;
+
+       assert(kernel_error_accountant.kernel_event_notifier_error_counter_fd);
+
+       ret = kernctl_counter_get_aggregate_value(
+                       kernel_error_accountant.kernel_event_notifier_error_counter_fd,
+                       &counter_aggregate);
+       if (ret) {
+               ERR("Error getting event notifier error count.");
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
+               goto end;
+       }
+
+       if (counter_aggregate.value.value < 0) {
+               ERR("Event notifier error counter less than zero.");
+               status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR;
+               goto end;
+       }
+
+       /* Error count can't be negative. */
+       assert(counter_aggregate.value.value >= 0);
+       *count = (uint64_t) counter_aggregate.value.value;
+
+       status = EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+
+end:
+       rcu_read_unlock();
+       return status;
+}
+
+enum event_notifier_error_accounting_status event_notifier_error_accounting_get_count(
+               const struct lttng_trigger *trigger, uint64_t *count)
+{
+       switch (lttng_trigger_get_underlying_domain_type_restriction(trigger)) {
+       case LTTNG_DOMAIN_KERNEL:
+               return event_notifier_error_accounting_kernel_get_count(trigger, count);
+       case LTTNG_DOMAIN_UST:
+#ifdef HAVE_LIBLTTNG_UST_CTL
+               return event_notifier_error_accounting_ust_get_count(trigger, count);
+#else
+               return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+#endif /* HAVE_LIBLTTNG_UST_CTL */
+       default:
+               abort();
+       }
+}
+
+static
+enum event_notifier_error_accounting_status event_notifier_error_accounting_clear(
+               const struct lttng_trigger *trigger)
+{
+       switch (lttng_trigger_get_underlying_domain_type_restriction(trigger)) {
+       case LTTNG_DOMAIN_KERNEL:
+               return event_notifier_error_accounting_kernel_clear(trigger);
+       case LTTNG_DOMAIN_UST:
+#ifdef HAVE_LIBLTTNG_UST_CTL
+               return event_notifier_error_accounting_ust_clear(trigger);
+#else
+               return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+#endif /* HAVE_LIBLTTNG_UST_CTL */
+       default:
+               abort();
+       }
+}
+
+static void free_index_ht_entry(struct rcu_head *head)
+{
+       struct index_ht_entry *entry = caa_container_of(head,
+                       struct index_ht_entry, rcu_head);
+       free(entry);
+}
+
+void event_notifier_error_accounting_unregister_event_notifier(
+               const struct lttng_trigger *trigger)
+{
+       struct lttng_ht_iter iter;
+       struct lttng_ht_node_u64 *node;
+       struct index_ht_entry *index_entry;
+       enum event_notifier_error_accounting_status status;
+       enum lttng_index_allocator_status index_alloc_status;
+       uint64_t tracer_token = lttng_trigger_get_tracer_token(trigger);
+
+       status = event_notifier_error_accounting_clear(trigger);
+       if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+               ERR("Error clearing event notifier error counter index: status=%s",
+                               error_accounting_status_str(status));
+       }
+
+       rcu_read_lock();
+       lttng_ht_lookup(error_counter_indexes_ht, &tracer_token, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if(node) {
+               index_entry = caa_container_of(node, struct index_ht_entry, node);
+               index_alloc_status = lttng_index_allocator_release(
+                               index_allocator,
+                               index_entry->error_counter_index);
+               if (index_alloc_status != LTTNG_INDEX_ALLOCATOR_STATUS_OK) {
+                       ERR("Error releasing event notifier error counter index: status=%s",
+                               error_accounting_status_str(status));
+               }
+
+               lttng_ht_del(error_counter_indexes_ht, &iter);
+               call_rcu(&index_entry->rcu_head, free_index_ht_entry);
+       }
+       rcu_read_unlock();
+}
+
+static void free_error_account_entry(struct rcu_head *head)
+{
+       struct error_account_entry *entry = caa_container_of(head,
+                       struct error_account_entry, rcu_head);
+#ifdef HAVE_LIBLTTNG_UST_CTL
+       int i;
+       for (i = 0; i < entry->nr_counter_cpu_fds; i++) {
+               ustctl_release_object(-1, entry->cpu_counters[i]);
+               free(entry->cpu_counters[i]);
+       }
+
+       free(entry->cpu_counters);
+
+       ustctl_release_object(-1, entry->counter);
+       free(entry->counter);
+
+       ustctl_destroy_counter(entry->daemon_counter);
+#endif /* HAVE_LIBLTTNG_UST_CTL */
+
+       free(entry);
+}
+
+void event_notifier_error_accounting_fini(void)
+{
+       struct lttng_ht_iter iter;
+       struct index_ht_entry *index_entry;
+       struct error_account_entry *uid_entry;
+
+       lttng_index_allocator_destroy(index_allocator);
+
+       if (kernel_error_accountant.kernel_event_notifier_error_counter_fd) {
+               int ret = close(kernel_error_accountant.kernel_event_notifier_error_counter_fd);
+               if (ret) {
+                       PERROR("Closing kernel event notifier error counter");
+               }
+       }
+
+       rcu_read_lock();
+
+       cds_lfht_for_each_entry(error_counter_uid_ht->ht, &iter.iter,
+                       uid_entry, node.node) {
+               cds_lfht_del(error_counter_uid_ht->ht, &uid_entry->node.node);
+               call_rcu(&uid_entry->rcu_head, free_error_account_entry);
+       }
+
+       cds_lfht_for_each_entry(error_counter_indexes_ht->ht, &iter.iter,
+                       index_entry, node.node) {
+               cds_lfht_del(error_counter_indexes_ht->ht, &index_entry->node.node);
+               call_rcu(&index_entry->rcu_head, free_index_ht_entry);
+       }
+
+       rcu_read_unlock();
+
+       lttng_ht_destroy(error_counter_uid_ht);
+       lttng_ht_destroy(error_counter_indexes_ht);
+}
diff --git a/src/bin/lttng-sessiond/event-notifier-error-accounting.h b/src/bin/lttng-sessiond/event-notifier-error-accounting.h
new file mode 100644 (file)
index 0000000..889efff
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef _EVENT_NOTIFIER_ERROR_ACCOUNTING_H
+#define _EVENT_NOTIFIER_ERROR_ACCOUNTING_H
+
+#include <stdint.h>
+
+#include <lttng/trigger/trigger.h>
+
+#include "ust-app.h"
+
+enum event_notifier_error_accounting_status {
+       EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK,
+       EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_ERR,
+       EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOT_FOUND,
+       EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NOMEM,
+       EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE,
+       EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_APP_DEAD,
+};
+
+enum event_notifier_error_accounting_status
+event_notifier_error_accounting_init(uint64_t nb_bucket);
+
+enum event_notifier_error_accounting_status
+event_notifier_error_accounting_register_kernel(
+               int kernel_event_notifier_group_fd);
+
+#ifdef HAVE_LIBLTTNG_UST_CTL
+enum event_notifier_error_accounting_status
+event_notifier_error_accounting_register_app(struct ust_app *app);
+
+enum event_notifier_error_accounting_status
+event_notifier_error_accounting_unregister_app(struct ust_app *app);
+#else /* HAVE_LIBLTTNG_UST_CTL */
+static inline
+enum event_notifier_error_accounting_status
+event_notifier_error_accounting_register_app(struct ust_app *app)
+{
+       return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+}
+
+static inline
+enum event_notifier_error_accounting_status
+event_notifier_error_accounting_unregister_app(struct ust_app *app)
+{
+       return EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK;
+}
+#endif /* HAVE_LIBLTTNG_UST_CTL */
+
+enum event_notifier_error_accounting_status
+event_notifier_error_accounting_register_event_notifier(
+               const struct lttng_trigger *trigger,
+               uint64_t *error_counter_index);
+
+enum event_notifier_error_accounting_status
+event_notifier_error_accounting_get_count(
+               const struct lttng_trigger *trigger,
+               uint64_t *count);
+
+void event_notifier_error_accounting_unregister_event_notifier(
+               const struct lttng_trigger *trigger);
+
+void event_notifier_error_accounting_fini(void);
+
+#endif /* _EVENT_NOTIFIER_ERROR_ACCOUNTING_H */
index 125adb9a058bf4fdedac31a1daaeaa02733c26c5..dd2e4b382fa46ca76978898a2a0e1b38bd8ccf9c 100644 (file)
 #include <common/compat/errno.h>
 #include <lttng/lttng.h>
 #include <lttng/condition/condition.h>
-#include <lttng/condition/event-rule.h>
+#include <lttng/condition/on-event.h>
 #include <lttng/event-rule/event-rule.h>
 #include <lttng/event-rule/event-rule-internal.h>
 #include <common/bytecode/bytecode.h>
 #include <common/error.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <common/filter.h>
+#include <common/kernel-ctl/kernel-ctl.h>
 #include <common/context.h>
 
 #include "channel.h"
@@ -38,7 +39,7 @@
  * Add unique UST event based on the event name, filter bytecode and loglevel.
  */
 static void add_unique_ust_event(struct lttng_ht *ht,
-               struct ltt_ust_event *event)
+               struct ltt_ust_event *event, struct lttng_map_key *map_key)
 {
        struct cds_lfht_node *node_ptr;
        struct ltt_ust_ht_key key;
@@ -52,6 +53,7 @@ static void add_unique_ust_event(struct lttng_ht *ht,
        key.loglevel_type = event->attr.loglevel_type;
        key.loglevel_value = event->attr.loglevel;
        key.exclusion = event->exclusion;
+       key.key = map_key;
 
        node_ptr = cds_lfht_add_unique(ht->ht,
                        ht->hash_fct(event->node.key, lttng_ht_seed),
@@ -113,8 +115,8 @@ int event_kernel_enable_event(struct ltt_kernel_channel *kchan,
        assert(kchan);
        assert(event);
 
-       kevent = trace_kernel_find_event(event->name, kchan,
-                       event->type, filter);
+       kevent = trace_kernel_find_event(&kchan->events_list,
+                       0, event->name, event->type, filter);
        if (kevent == NULL) {
                ret = kernel_create_event(event, kchan, filter_expression, filter);
                /* We have passed ownership */
@@ -142,6 +144,104 @@ end:
        return ret;
 }
 
+/*
+ * Disable kernel tracepoint events for a map from the kernel session of
+ * a specified event_name and event type.
+ * On type LTTNG_EVENT_ALL all events with event_name are disabled.
+ * If event_name is NULL all events of the specified type are disabled.
+ */
+int map_event_kernel_disable_event(struct ltt_kernel_map *kmap,
+               uint64_t action_tracer_token)
+{
+       struct ltt_kernel_event_counter *kevent_counter;
+       struct lttng_ht_iter iter;
+       const struct lttng_ht_node_u64 *node;
+       enum lttng_error_code ret_code;
+       int ret;
+
+       assert(kmap);
+
+       lttng_ht_lookup(kmap->event_counters_ht, (void *) &action_tracer_token, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if (node){
+               kevent_counter = caa_container_of(node,
+                               struct ltt_kernel_event_counter, ht_node);
+               ret = kernctl_disable(kevent_counter->fd);
+               if (ret < 0) {
+                       ret_code = LTTNG_ERR_KERN_DISABLE_FAIL;
+                       goto end;
+               }
+               kevent_counter->enabled = false;
+               DBG("Disable kernel event counter");
+       } else {
+               ret_code = LTTNG_ERR_NO_EVENT;
+               goto end;
+       }
+
+       ret_code = LTTNG_OK;
+end:
+       return ret_code;
+}
+
+/*
+ * Enable kernel tracepoint event for a map from the kernel session.
+ * We own filter_expression and filter.
+ */
+int map_event_kernel_enable_event(struct ltt_kernel_map *kmap,
+               const struct lttng_credentials *creds,
+               uint64_t action_tracer_token,
+               const struct lttng_event_rule *event_rule,
+               struct lttng_map_key *key)
+{
+       int err;
+       enum lttng_error_code ret_code;
+       struct ltt_kernel_event_counter *kevent_counter;
+       struct lttng_ht_iter iter;
+       const struct lttng_ht_node_u64 *node;
+
+       assert(kmap);
+       assert(event_rule);
+       assert(key);
+
+       lttng_ht_lookup(kmap->event_counters_ht, (void *) &action_tracer_token, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if (node){
+               kevent_counter = caa_container_of(node,
+                               struct ltt_kernel_event_counter, ht_node);
+               if (kevent_counter->enabled) {
+                       /* At this point, the event is considered enabled */
+                       ret_code = LTTNG_ERR_KERN_EVENT_EXIST;
+                       goto end;
+               }
+
+               err = kernctl_enable(kevent_counter->fd);
+               if (err < 0) {
+                       switch (-err) {
+                       case EEXIST:
+                               ret_code = LTTNG_ERR_KERN_EVENT_EXIST;
+                               break;
+                       default:
+                               PERROR("enable kernel event counter");
+                               ret_code = LTTNG_ERR_KERN_ENABLE_FAIL;
+                               break;
+                       }
+                       goto end;
+               }
+
+       } else {
+
+               ret_code = kernel_create_event_counter(kmap, creds,
+                               action_tracer_token, event_rule, key);
+               if (ret_code != LTTNG_OK) {
+                       goto end;
+               }
+       }
+
+       ret_code = LTTNG_OK;
+end:
+       return ret_code;
+}
+
 /*
  * ============================
  * UST : The Ultimate Frontier!
@@ -162,18 +262,26 @@ int event_ust_enable_tracepoint(struct ltt_ust_session *usess,
        int ret = LTTNG_OK, to_create = 0;
        struct ltt_ust_event *uevent;
 
+       /*
+        * FIXME: Frdeso. The tracer token should probably me set for regular
+        * events too.
+        */
+       uint64_t tracer_token = 0;
+
        assert(usess);
        assert(uchan);
        assert(event);
 
        rcu_read_lock();
 
-       uevent = trace_ust_find_event(uchan->events, event->name, filter,
+       uevent = trace_ust_find_event(uchan->events, 0, event->name, filter,
                        (enum lttng_ust_loglevel_type) event->loglevel_type,
-                       event->loglevel, exclusion);
+                       event->loglevel, exclusion, NULL);
        if (!uevent) {
-               ret = trace_ust_create_event(event, filter_expression,
-                               filter, exclusion, internal_event, &uevent);
+               ret = trace_ust_create_event(tracer_token, event->name, NULL, event->type,
+                               event->loglevel_type, event->loglevel,
+                               filter_expression, filter, exclusion,
+                               internal_event, &uevent);
                /* We have passed ownership */
                filter_expression = NULL;
                filter = NULL;
@@ -196,7 +304,7 @@ int event_ust_enable_tracepoint(struct ltt_ust_session *usess,
        uevent->enabled = 1;
        if (to_create) {
                /* Add ltt ust event to channel */
-               add_unique_ust_event(uchan->events, uevent);
+               add_unique_ust_event(uchan->events, uevent, NULL);
        }
 
        if (!usess->active) {
@@ -205,10 +313,10 @@ int event_ust_enable_tracepoint(struct ltt_ust_session *usess,
 
        if (to_create) {
                /* Create event on all UST registered apps for session */
-               ret = ust_app_create_event_glb(usess, uchan, uevent);
+               ret = ust_app_create_channel_event_glb(usess, uchan, uevent);
        } else {
                /* Enable event on all UST registered apps for session */
-               ret = ust_app_enable_event_glb(usess, uchan, uevent);
+               ret = ust_app_enable_channel_event_glb(usess, uchan, uevent);
        }
 
        if (ret < 0) {
@@ -252,6 +360,140 @@ error:
        return ret;
 }
 
+/*
+ * Enable UST tracepoint event for a map from a UST session.
+ */
+enum lttng_error_code map_event_ust_enable_tracepoint(
+               struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap,
+               uint64_t tracer_token,
+               char *ev_name,
+               struct lttng_map_key *key,
+               enum lttng_event_type ev_type,
+               enum lttng_loglevel_type ev_loglevel_type,
+               int ev_loglevel_value,
+               char *_filter_expression,
+               struct lttng_bytecode *_filter,
+               struct lttng_event_exclusion *exclusion,
+               bool internal_event)
+{
+       enum lttng_error_code ret_code = LTTNG_OK;
+       int ret, to_create = 0;
+       struct ltt_ust_event *uevent;
+       struct lttng_bytecode *filter = NULL;
+       char *filter_expression = NULL;
+
+
+       assert(usess);
+       assert(umap);
+
+       /*
+        * FIXME: FRDESO: this function was copied from ust-app.c
+        */
+       if (_filter_expression) {
+               filter_expression = strdup(_filter_expression);
+       }
+
+       if (_filter) {
+               filter = zmalloc(sizeof(*filter) + _filter->len);
+               if (!filter) {
+                       PERROR("Failed to allocate lttng_ust_filter_bytecode: bytecode len = %" PRIu32 " bytes", _filter->len);
+                       goto error;
+               }
+
+               assert(sizeof(struct lttng_bytecode) ==
+                       sizeof(struct lttng_ust_filter_bytecode));
+               memcpy(filter, _filter, sizeof(*filter) + _filter->len);
+       }
+
+       rcu_read_lock();
+
+       uevent = trace_ust_find_event(umap->events, tracer_token, ev_name, filter,
+                       (enum lttng_ust_loglevel_type) ev_loglevel_type,
+                       ev_loglevel_value, exclusion, key);
+       if (!uevent) {
+               ret_code = trace_ust_create_event(tracer_token, ev_name, key, ev_type,
+                               ev_loglevel_type, ev_loglevel_value,
+                               filter_expression, filter, exclusion,
+                               internal_event, &uevent);
+               /* We have passed ownership */
+               filter_expression = NULL;
+               filter = NULL;
+               exclusion = NULL;
+               if (ret_code != LTTNG_OK) {
+                       goto error;
+               }
+
+               /* Valid to set it after the goto error since uevent is still NULL */
+               to_create = 1;
+       }
+
+       if (uevent->enabled) {
+               /* It's already enabled so everything is OK */
+               assert(!to_create);
+               ret_code = LTTNG_ERR_UST_EVENT_ENABLED;
+               goto end;
+       }
+
+       uevent->enabled = 1;
+       if (to_create) {
+               /* Add ltt ust event to map */
+               add_unique_ust_event(umap->events, uevent, key);
+       }
+
+       if (!usess->active) {
+               goto end;
+       }
+
+       if (to_create) {
+               /* Create event on all UST registered apps for session */
+               ret = ust_app_create_map_event_glb(usess, umap, uevent);
+       } else {
+               /* Enable event on all UST registered apps for session */
+               ret = ust_app_enable_map_event_glb(usess, umap, uevent);
+       }
+
+       if (ret < 0) {
+               if (ret == -LTTNG_UST_ERR_EXIST) {
+                       ret_code = LTTNG_ERR_UST_EVENT_EXIST;
+                       goto end;
+               } else {
+                       ret_code = LTTNG_ERR_UST_ENABLE_FAIL;
+                       goto error;
+               }
+       }
+
+       DBG("Event UST %s %s in map %s", uevent->attr.name,
+                       to_create ? "created" : "enabled", umap->name);
+
+       ret_code = LTTNG_OK;
+
+end:
+       rcu_read_unlock();
+       free(filter_expression);
+       free(filter);
+       free(exclusion);
+       return ret_code;
+
+error:
+       /*
+        * Only destroy event on creation time (not enabling time) because if the
+        * event is found in the map (to_create == 0), it means that at some
+        * point the enable_event worked and it's thus valid to keep it alive.
+        * Destroying it also implies that we also destroy it's shadow copy to sync
+        * everyone up.
+        */
+       if (to_create) {
+               /* In this code path, the uevent was not added to the hash table */
+               trace_ust_destroy_event(uevent);
+       }
+       rcu_read_unlock();
+       free(filter_expression);
+       free(filter);
+       free(exclusion);
+       return ret_code;
+}
+
 /*
  * Disable UST tracepoint of a channel from a UST session.
  */
@@ -300,7 +542,7 @@ int event_ust_disable_tracepoint(struct ltt_ust_session *usess,
                if (!usess->active) {
                        goto next;
                }
-               ret = ust_app_disable_event_glb(usess, uchan, uevent);
+               ret = ust_app_disable_channel_event_glb(usess, uchan, uevent);
                if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
                        ret = LTTNG_ERR_UST_DISABLE_FAIL;
                        goto error;
@@ -319,6 +561,69 @@ error:
        return ret;
 }
 
+/*
+ * Disable UST tracepoint of a map from a UST session.
+ */
+enum lttng_error_code map_event_ust_disable_tracepoint(
+               struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap,
+               uint64_t tracer_token,
+               char *event_name,
+               struct lttng_map_key *key,
+               enum lttng_event_type ev_type,
+               enum lttng_loglevel_type ev_loglevel_type,
+               int ev_loglevel_value,
+               char *filter_expression,
+               struct lttng_bytecode *filter,
+               struct lttng_event_exclusion *exclusion,
+               bool internal_event)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       struct ltt_ust_event *uevent;
+
+       assert(usess);
+       assert(umap);
+       assert(event_name);
+
+       rcu_read_lock();
+
+       /*
+        * FIXME: frdeso: We need to pass all the parameters to find the right
+        * event.
+        */
+       uevent = trace_ust_find_event(umap->events, tracer_token, event_name, filter,
+                       (enum lttng_ust_loglevel_type) ev_loglevel_type,
+                       ev_loglevel_value, exclusion, key);
+       assert(uevent);
+
+       if (uevent->enabled == 0) {
+               ret_code = LTTNG_OK;
+               goto end;
+       }
+
+       uevent->enabled = 0;
+       DBG2("Event UST %s disabled in map %s", uevent->attr.name,
+               umap->name);
+
+       if (!usess->active) {
+               ret_code = LTTNG_OK;
+               goto end;
+       }
+
+       ret = ust_app_disable_map_event_glb(usess, umap, uevent);
+       if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
+               ret_code = LTTNG_ERR_UST_DISABLE_FAIL;
+               goto end;
+       }
+
+       ret_code = LTTNG_OK;
+
+end:
+       rcu_read_unlock();
+       return ret_code;
+}
+
 /*
  * Disable all UST tracepoints for a channel from a UST session.
  */
@@ -372,6 +677,56 @@ error:
        return ret;
 }
 
+/*
+ * Disable all UST tracepoints for a map from a UST session.
+ */
+int map_event_ust_disable_all_tracepoints(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap)
+{
+       int ret, error = 0;
+       struct lttng_ht_iter iter;
+       struct ltt_ust_event *uevent = NULL;
+       struct lttng_event *events = NULL;
+
+       assert(usess);
+       assert(umap);
+
+       rcu_read_lock();
+
+       /* Disabling existing events */
+       cds_lfht_for_each_entry(umap->events->ht, &iter.iter, uevent,
+                       node.node) {
+               if (uevent->enabled == 1) {
+                       ret = map_event_ust_disable_tracepoint(usess, umap,
+                                       uevent->attr.token,
+                                       uevent->attr.name,
+                                       uevent->key,
+                                       uevent->attr.instrumentation,
+                                       (enum lttng_loglevel_type) uevent->attr.loglevel_type,
+                                       uevent->attr.loglevel,
+                                       uevent->filter_expression,
+                                       uevent->filter,
+                                       uevent->exclusion,
+                                       false);
+                       if (ret < 0) {
+                               error = LTTNG_ERR_UST_DISABLE_FAIL;
+                               continue;
+                       }
+               }
+       }
+
+       /*
+        * FIXME: FRDESO: in the equivalent function
+        * event_ust_disable_all_tracepoints() (above ^) we also iterator over
+        * all lttng_event. Do we need to do this here too?
+        */
+
+       ret = error ? error : LTTNG_OK;
+       rcu_read_unlock();
+       free(events);
+       return ret;
+}
+
 static void agent_enable_all(struct agent *agt)
 {
        struct agent_event *aevent;
@@ -601,9 +956,9 @@ int trigger_agent_enable(const struct lttng_trigger *trigger, struct agent *agt)
        condition = lttng_trigger_get_const_condition(trigger);
 
        assert(lttng_condition_get_type(condition) ==
-                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+                       LTTNG_CONDITION_TYPE_ON_EVENT);
 
-       c_status = lttng_condition_event_rule_get_rule(condition, &rule);
+       c_status = lttng_condition_on_event_get_rule(condition, &rule);
        assert(c_status == LTTNG_CONDITION_STATUS_OK);
 
        assert(lttng_event_rule_get_type(rule) ==
@@ -779,13 +1134,15 @@ static int event_agent_disable_one(struct ltt_ust_session *usess,
         * happens thanks to an UST filter. The following -1 is actually
         * ignored since the type is LTTNG_UST_LOGLEVEL_ALL.
         */
-       uevent = trace_ust_find_event(uchan->events, (char *) ust_event_name,
-                       aevent->filter, LTTNG_UST_LOGLEVEL_ALL, -1, NULL);
+       /* TODO: JORAJ FRDESO: hmmm what to do with tracer token here?
+        */
+       uevent = trace_ust_find_event(uchan->events, 0, (char *) ust_event_name,
+                       aevent->filter, LTTNG_UST_LOGLEVEL_ALL, -1, NULL, NULL);
        /* If the agent event exists, it must be available on the UST side. */
        assert(uevent);
 
        if (usess->active) {
-               ret = ust_app_disable_event_glb(usess, uchan, uevent);
+               ret = ust_app_disable_channel_event_glb(usess, uchan, uevent);
                if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
                        ret = LTTNG_ERR_UST_DISABLE_FAIL;
                        goto error;
index 8849ee7ccc8ec2bec202dc6ea32c4c74f5ae089a..42b8fb7c2b5a594def195b91e1f191873bbce5bc 100644 (file)
@@ -9,6 +9,7 @@
 #define _LTT_EVENT_H
 
 #include "trace-kernel.h"
+#include "trace-ust.h"
 
 struct agent;
 
@@ -19,18 +20,59 @@ int event_kernel_enable_event(struct ltt_kernel_channel *kchan,
                struct lttng_event *event, char *filter_expression,
                struct lttng_bytecode *filter);
 
+int map_event_kernel_disable_event(struct ltt_kernel_map *kmap,
+               uint64_t action_tracer_token);
+
+int map_event_kernel_enable_event(struct ltt_kernel_map *kmap,
+               const struct lttng_credentials *creds,
+               uint64_t tracer_token,
+               const struct lttng_event_rule *event_rule,
+               struct lttng_map_key *key);
+
 int event_ust_enable_tracepoint(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct lttng_event *event,
                char *filter_expression,
                struct lttng_bytecode *filter,
                struct lttng_event_exclusion *exclusion,
                bool internal_event);
+
+enum lttng_error_code map_event_ust_enable_tracepoint(
+       struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap,
+               uint64_t tracer_token,
+               char *ev_name,
+               struct lttng_map_key *key,
+               enum lttng_event_type ev_type,
+               enum lttng_loglevel_type ev_loglevel_type,
+               int ev_loglevel_value,
+               char *filter_expression,
+               struct lttng_bytecode *filter,
+               struct lttng_event_exclusion *exclusion,
+               bool internal_event);
+
 int event_ust_disable_tracepoint(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, const char *event_name);
 
+enum lttng_error_code map_event_ust_disable_tracepoint(
+               struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap,
+               uint64_t tracer_token,
+               char *ev_name,
+               struct lttng_map_key *key,
+               enum lttng_event_type ev_type,
+               enum lttng_loglevel_type ev_loglevel_type,
+               int ev_loglevel_value,
+               char *filter_expression,
+               struct lttng_bytecode *filter,
+               struct lttng_event_exclusion *exclusion,
+               bool internal_event);
+
 int event_ust_disable_all_tracepoints(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan);
 
+int map_event_ust_disable_all_tracepoints(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap);
+
 int event_agent_enable(struct ltt_ust_session *usess, struct agent *agt,
                struct lttng_event *event, struct lttng_bytecode *filter,
                char *filter_expression);
index 23e8eac2a9f82ee12ea57f879b9df4481a177af3..25d744d1107ef11cf342f21990e0b4bffbac6fa3 100644 (file)
 
 #include <lttng/userspace-probe.h>
 #include <lttng/userspace-probe-internal.h>
-#include <lttng/condition/event-rule.h>
-#include <lttng/condition/event-rule-internal.h>
+#include <lttng/condition/on-event.h>
+#include <lttng/condition/on-event-internal.h>
 #include <lttng/event-rule/event-rule.h>
 #include <lttng/event-rule/event-rule-internal.h>
-#include <lttng/event-rule/uprobe-internal.h>
-
+#include <lttng/event-rule/userspace-probe-internal.h>
+#include <lttng/map/map.h>
+#include <lttng/map/map-internal.h>
+#include <lttng/map/map-query-internal.h>
+#include <lttng/map-key.h>
+#include <lttng/map-key-internal.h>
+
+#include "event-notifier-error-accounting.h"
 #include "lttng-sessiond.h"
 #include "lttng-syscall.h"
 #include "condition-internal.h"
@@ -41,6 +47,8 @@
 #include "kernel.h"
 #include "kernel-consumer.h"
 #include "kern-modules.h"
+#include "map.h"
+#include "sessiond-config.h"
 #include "utils.h"
 #include "rotate.h"
 #include "modprobe.h"
@@ -540,9 +548,9 @@ static int userspace_probe_event_rule_add_callsites(
        assert(creds);
 
        event_rule_type = lttng_event_rule_get_type(rule);
-       assert(event_rule_type == LTTNG_EVENT_RULE_TYPE_UPROBE);
+       assert(event_rule_type == LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE);
 
-       status = lttng_event_rule_uprobe_get_location(rule, &location);
+       status = lttng_event_rule_userspace_probe_get_location(rule, &location);
        if (status != LTTNG_EVENT_RULE_STATUS_OK || !location) {
                ret = -1;
                goto end;
@@ -1989,7 +1997,8 @@ int init_kernel_tracer(void)
                WARN("Failed to create kernel event notifier group");
                kernel_tracer_event_notifier_group_fd = -1;
        } else {
-               const enum lttng_error_code error_code_ret =
+               enum event_notifier_error_accounting_status error_accounting_status;
+               enum lttng_error_code error_code_ret =
                                kernel_create_event_notifier_group_notification_fd(
                                                &kernel_tracer_event_notifier_group_notification_fd);
 
@@ -1997,6 +2006,14 @@ int init_kernel_tracer(void)
                        goto error_modules;
                }
 
+               error_accounting_status = event_notifier_error_accounting_register_kernel(
+                               kernel_tracer_event_notifier_group_fd);
+               if (error_accounting_status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+                       ERR("Error initializing event notifier error accounting for kernel tracer.");
+                       error_code_ret = LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING;
+                       goto error_modules;
+               }
+
                kernel_token_to_event_notifier_rule_ht = cds_lfht_new(
                                DEFAULT_HT_SIZE, 1, 0,
                                CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING,
@@ -2113,8 +2130,6 @@ void cleanup_kernel_tracer(void)
                kernel_tracer_fd = -1;
        }
 
-       DBG("Unloading kernel modules");
-       modprobe_remove_lttng_all();
        free(syscall_table);
 }
 
@@ -2123,13 +2138,8 @@ bool kernel_tracer_is_initialized(void)
 {
        return kernel_tracer_fd >= 0;
 }
-
-/*
- *  Clear a kernel session.
- *
- * Return LTTNG_OK on success or else an LTTng error code.
- */
-enum lttng_error_code kernel_clear_session(struct ltt_session *session)
+static
+enum lttng_error_code  kernel_clear_session_channels(struct ltt_session *session)
 {
        int ret;
        enum lttng_error_code status = LTTNG_OK;
@@ -2140,9 +2150,6 @@ enum lttng_error_code kernel_clear_session(struct ltt_session *session)
        assert(ksess);
        assert(ksess->consumer);
 
-       DBG("Clear kernel session %s (session %" PRIu64 ")",
-                       session->name, session->id);
-
        rcu_read_lock();
 
        if (ksess->active) {
@@ -2189,6 +2196,7 @@ enum lttng_error_code kernel_clear_session(struct ltt_session *session)
                }
        }
 
+
        goto end;
 error:
        switch (-ret) {
@@ -2204,6 +2212,116 @@ end:
        return status;
 }
 
+static
+enum lttng_error_code kernel_map_clear_all(struct ltt_kernel_map *map)
+{
+       enum lttng_error_code status;
+       uint64_t descr_count, i;
+       int ret;
+
+       assert(map);
+
+       ret = kernctl_counter_map_descriptor_count(map->fd, &descr_count);
+       if (ret) {
+               ERR("Error getting map descriptor count");
+               status = LTTNG_ERR_MAP_VALUES_LIST_FAIL;
+               goto end;
+       }
+
+       for(i = 0; i < descr_count; i++) {
+               struct lttng_kernel_counter_map_descriptor descriptor = {0};
+               struct lttng_kernel_counter_clear counter_clear = {0};
+
+               descriptor.descriptor_index = i;
+
+               ret = kernctl_counter_map_descriptor(map->fd, &descriptor);
+               if (ret) {
+                       ERR("Error getting map descriptor %"PRIu64, i);
+                       status = LTTNG_ERR_MAP_VALUES_LIST_FAIL;
+                       goto end;
+               }
+
+               counter_clear.index.number_dimensions = 1;
+               counter_clear.index.dimension_indexes[0] = descriptor.array_index;
+
+               ret = kernctl_counter_clear(map->fd, &counter_clear);
+               if (ret) {
+                       ERR("Error clearing value of map descriptor %"PRIu64, i);
+                       status = LTTNG_ERR_MAP_VALUES_LIST_FAIL;
+                       goto end;
+               }
+       }
+
+       status = LTTNG_OK;
+end:
+       return status;
+}
+
+static
+enum lttng_error_code kernel_clear_session_maps(struct ltt_session *session)
+{
+       enum lttng_error_code status = LTTNG_OK;
+       struct ltt_kernel_map *map;
+       struct ltt_kernel_session *ksess = session->kernel_session;
+
+       assert(ksess);
+
+       cds_list_for_each_entry(map, &ksess->map_list.head, list) {
+               DBG("Clear kernel map %" PRIu64 ", session %s",
+                               map->key, session->name);
+               status = kernel_map_clear_all(map);
+               if (status != LTTNG_OK) {
+                       ERR("Clearing all values of map");
+                       goto end;
+               }
+       }
+
+end:
+       return status;
+}
+
+/*
+ *  Clear a kernel session.
+ *
+ * Return LTTNG_OK on success or else an LTTng error code.
+ */
+enum lttng_error_code kernel_clear_session(struct ltt_session *session)
+{
+       enum lttng_error_code status = LTTNG_OK;
+       struct ltt_kernel_session *ksess = session->kernel_session;
+
+       assert(ksess);
+       assert(ksess->consumer);
+
+       DBG("Clear kernel session %s (session %" PRIu64 ")",
+                       session->name, session->id);
+
+       rcu_read_lock();
+
+       if (ksess->active) {
+               ERR("Expecting inactive session %s (%" PRIu64 ")", session->name, session->id);
+               status = LTTNG_ERR_FATAL;
+               goto end;
+       }
+
+       status = kernel_clear_session_channels(session);
+       if (status != LTTNG_OK) {
+               goto end;
+       }
+       /*
+        * Iterate and clear all kernel maps.
+        */
+       status = kernel_clear_session_maps(session);
+       if (status != LTTNG_OK) {
+               goto end;
+       }
+
+
+end:
+       rcu_read_unlock();
+       return status;
+}
+
 enum lttng_error_code kernel_create_event_notifier_group_notification_fd(
                int *event_notifier_group_notification_fd)
 {
@@ -2288,6 +2406,193 @@ int match_trigger(struct cds_lfht_node *node, const void *key)
        return lttng_trigger_is_equal(trigger, event_notifier_rule->trigger);
 }
 
+static
+int add_key_token(struct lttng_kernel_key_token *kernel_key_token,
+               const struct lttng_map_key_token *key_token)
+{
+       int ret;
+       switch (key_token->type) {
+       case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
+       {
+               const struct lttng_map_key_token_string *str_token;
+               str_token = (typeof(str_token)) key_token;
+
+               kernel_key_token->type = LTTNG_KERNEL_KEY_TOKEN_STRING;
+               kernel_key_token->arg.string_ptr = (uint64_t) str_token->string;
+
+               break;
+       }
+       case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
+       {
+               const struct lttng_map_key_token_variable *var_token;
+               var_token = (typeof(var_token)) key_token;
+               switch (var_token->type) {
+               case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME:
+                       kernel_key_token->type = LTTNG_KERNEL_KEY_TOKEN_EVENT_NAME;
+                       break;
+               case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME:
+                       /* The kernel events don't have providers */
+                       ERR("Provider variable token type not supported for kernel tracer");
+                       ret = -1;
+                       goto end;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       default:
+               abort();
+       }
+       ret = 0;
+end:
+       return ret;
+}
+
+enum lttng_error_code kernel_create_event_counter(
+               struct ltt_kernel_map *kmap,
+               const struct lttng_credentials *creds,
+               uint64_t action_tracer_token,
+               const struct lttng_event_rule *event_rule,
+               struct lttng_map_key *key)
+{
+       int err, fd, ret = 0;
+       unsigned int i, key_token_count;
+       enum lttng_error_code error_code_ret;
+       enum lttng_map_key_status status;
+       struct ltt_kernel_event_counter *event_counter;
+       struct lttng_kernel_counter_event k_counter_event = {};
+
+
+       event_counter = zmalloc(sizeof(*event_counter));
+       if (!event_counter) {
+               error_code_ret = LTTNG_ERR_NOMEM;
+               goto error;
+       }
+
+       trace_kernel_init_event_counter_from_event_rule(event_rule,
+                       &k_counter_event);
+       event_counter->fd = -1;
+       event_counter->enabled = 1;
+       event_counter->action_tracer_token = action_tracer_token;
+       event_counter->filter = lttng_event_rule_get_filter_bytecode(event_rule);
+
+       k_counter_event.event.token = action_tracer_token;
+
+       /* Set the key pattern for this event counter. */
+       k_counter_event.key.nr_dimensions = 1;
+
+       status = lttng_map_key_get_token_count(key, &key_token_count);
+       if (status != LTTNG_MAP_KEY_STATUS_OK) {
+               error_code_ret = LTTNG_ERR_UNK;
+               goto error;
+       }
+
+       assert(key_token_count > 0);
+
+       k_counter_event.key.key_dimensions[0].nr_key_tokens = key_token_count;
+
+       for (i = 0; i < key_token_count; i++) {
+               const struct lttng_map_key_token *token =
+                               lttng_map_key_get_token_at_index(key, i);
+
+               ret = add_key_token(&k_counter_event.key.key_dimensions[0].key_tokens[i],
+                               token);
+               if (ret) {
+                       ERR("Error appending map key token");
+                       error_code_ret = LTTNG_ERR_INVALID;
+                       goto error;
+               }
+       }
+
+       fd = kernctl_create_counter_event(kmap->fd, &k_counter_event);
+       if (fd < 0) {
+               switch (-fd) {
+               case EEXIST:
+                       error_code_ret = LTTNG_ERR_KERN_EVENT_EXIST;
+                       break;
+               case ENOSYS:
+                       WARN("Event counter type not implemented");
+                       error_code_ret = LTTNG_ERR_KERN_EVENT_ENOSYS;
+                       break;
+               case ENOENT:
+                       WARN("Event counter %s not found!", k_counter_event.event.name);
+                       error_code_ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+                       break;
+               default:
+                       error_code_ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+                       PERROR("create event counter ioctl");
+               }
+       }
+
+       event_counter->fd = fd;
+       event_counter->enabled = true;
+
+       /* Prevent fd duplication after execlp() */
+       err = fcntl(fd, F_SETFD, FD_CLOEXEC);
+       if (err < 0) {
+               PERROR("fcntl session fd");
+       }
+
+       if (event_counter->filter) {
+               err = kernctl_filter(event_counter->fd, event_counter->filter);
+               if (err < 0) {
+                       switch (-err) {
+                       case ENOMEM:
+                               error_code_ret = LTTNG_ERR_FILTER_NOMEM;
+                               break;
+                       default:
+                               error_code_ret = LTTNG_ERR_FILTER_INVAL;
+                               break;
+                       }
+                       goto filter_error;
+               }
+       }
+       if (lttng_event_rule_get_type(event_rule) ==
+                       LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE) {
+               ret = userspace_probe_event_rule_add_callsites(
+                               event_rule, creds, event_counter->fd);
+               if (ret) {
+                       error_code_ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+                       goto add_callsite_error;
+               }
+       }
+
+       err = kernctl_enable(event_counter->fd);
+       if (err < 0) {
+               switch (-err) {
+               case EEXIST:
+                       error_code_ret = LTTNG_ERR_KERN_EVENT_EXIST;
+                       break;
+               default:
+                       PERROR("enable kernel counter event");
+                       error_code_ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+                       break;
+               }
+               goto enable_error;
+       }
+
+       /* Add event to event list */
+       rcu_read_lock();
+       lttng_ht_node_init_u64(&event_counter->ht_node,
+                       event_counter->action_tracer_token);
+       lttng_ht_add_unique_u64(kmap->event_counters_ht,
+                       &event_counter->ht_node);
+       rcu_read_unlock();
+       kmap->event_count++;
+
+       DBG("Kernel event counter %s created (fd: %d)",
+                       event_counter->event->name,
+                       event_counter->fd);
+       error_code_ret = LTTNG_OK;
+
+add_callsite_error:
+filter_error:
+enable_error:
+error:
+       return error_code_ret;
+}
+
 static enum lttng_error_code kernel_create_event_notifier_rule(
                struct lttng_trigger *trigger,
                const struct lttng_credentials *creds, uint64_t token)
@@ -2299,8 +2604,10 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
        enum lttng_event_rule_type event_rule_type;
        struct ltt_kernel_event_notifier_rule *event_notifier_rule;
        struct lttng_kernel_event_notifier kernel_event_notifier = {};
+       unsigned int capture_bytecode_count = 0, i;
        const struct lttng_condition *condition = NULL;
        const struct lttng_event_rule *event_rule = NULL;
+       enum lttng_condition_status cond_status;
 
        assert(trigger);
 
@@ -2308,10 +2615,10 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
        assert(condition);
 
        condition_type = lttng_condition_get_type(condition);
-       assert(condition_type == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+       assert(condition_type == LTTNG_CONDITION_TYPE_ON_EVENT);
 
        /* Does not acquire a reference. */
-       condition_status = lttng_condition_event_rule_get_rule(
+       condition_status = lttng_condition_on_event_get_rule(
                        condition, &event_rule);
        assert(condition_status == LTTNG_CONDITION_STATUS_OK);
        assert(event_rule);
@@ -2320,6 +2627,7 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
        assert(event_rule_type != LTTNG_EVENT_RULE_TYPE_UNKNOWN);
 
        error_code_ret = trace_kernel_create_event_notifier_rule(trigger, token,
+                       lttng_condition_on_event_get_error_counter_index(condition),
                        &event_notifier_rule);
        if (error_code_ret != LTTNG_OK) {
                goto error;
@@ -2332,6 +2640,8 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
        }
 
        kernel_event_notifier.event.token = event_notifier_rule->token;
+       kernel_event_notifier.error_counter_idx =
+                       lttng_condition_on_event_get_error_counter_index(condition);
 
        fd = kernctl_create_event_notifier(
                        kernel_tracer_event_notifier_group_fd,
@@ -2384,7 +2694,7 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
        }
 
        if (lttng_event_rule_get_type(event_rule) ==
-                       LTTNG_EVENT_RULE_TYPE_UPROBE) {
+                       LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE) {
                ret = userspace_probe_event_rule_add_callsites(
                                event_rule, creds, event_notifier_rule->fd);
                if (ret) {
@@ -2393,6 +2703,25 @@ static enum lttng_error_code kernel_create_event_notifier_rule(
                }
        }
 
+       /* Set the capture bytecode if any */
+       cond_status = lttng_condition_on_event_get_capture_descriptor_count(condition, &capture_bytecode_count);
+       assert(cond_status == LTTNG_CONDITION_STATUS_OK);
+       for (i = 0; i < capture_bytecode_count; i++) {
+               const struct lttng_bytecode *capture_bytecode =
+                               lttng_condition_on_event_get_capture_bytecode_at_index(
+                                               condition, i);
+               if (capture_bytecode == NULL) {
+                       error_code_ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+                       goto error;
+               }
+
+               ret = kernctl_capture(event_notifier_rule->fd, capture_bytecode);
+               if (ret < 0) {
+                       error_code_ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+                       goto error;
+               }
+       }
+
        err = kernctl_enable(event_notifier_rule->fd);
        if (err < 0) {
                switch (-err) {
@@ -2452,7 +2781,7 @@ enum lttng_error_code kernel_register_event_notifier(
        assert(condition);
 
        /* Does not acquire a reference to the event rule. */
-       status = lttng_condition_event_rule_get_rule(
+       status = lttng_condition_on_event_get_rule(
                        condition, &event_rule);
        assert(status == LTTNG_CONDITION_STATUS_OK);
 
@@ -2505,6 +2834,210 @@ error:
        return error_code_ret;
 }
 
+struct key_ht_entry {
+       char *key;
+       struct lttng_ht_node_str node;
+};
+
+enum lttng_error_code kernel_list_map_values(const struct ltt_kernel_map *map,
+               const struct lttng_map_query *query,
+               struct lttng_map_content **map_content)
+{
+       enum lttng_map_status map_status;
+       enum lttng_error_code ret_code;
+       const char *map_name = NULL;
+       uint64_t descr_count, descr_idx, cpu_idx;
+       struct lttng_map_content *local_map_content;
+       struct lttng_ht *key_ht;
+       struct lttng_ht *values = NULL;
+       struct lttng_ht_node_str *node;
+       struct key_ht_entry *ht_entry;
+       struct lttng_ht_iter iter;
+       enum lttng_map_query_status map_query_status;
+       const char *key_filter;
+       bool sum_cpus = lttng_map_query_get_config_sum_by_cpu(query);
+       enum lttng_map_query_config_cpu config_cpu;
+       int ret;
+       int selected_cpu;
+
+
+       local_map_content = lttng_map_content_create(LTTNG_BUFFER_GLOBAL);
+       if (!local_map_content) {
+               ERR("Error creating map content");
+               ret_code = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       map_query_status = lttng_map_query_get_key_filter(query, &key_filter);
+       if (map_query_status == LTTNG_MAP_QUERY_STATUS_NONE) {
+               key_filter = NULL;
+       } else if (map_query_status != LTTNG_MAP_QUERY_STATUS_OK) {
+               ret_code = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       config_cpu = lttng_map_query_get_config_cpu(query);
+       if (config_cpu == LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+               unsigned int count;
+               map_query_status = lttng_map_query_get_cpu_count(query, &count);
+               assert(map_query_status == LTTNG_MAP_QUERY_STATUS_OK);
+               assert(count == 1);
+
+               map_query_status = lttng_map_query_get_cpu_at_index(query, 0,
+                               &selected_cpu);
+               assert(map_query_status == LTTNG_MAP_QUERY_STATUS_OK);
+       }
+
+       map_status = lttng_map_get_name(map->map, &map_name);
+       assert(map_status == LTTNG_MAP_STATUS_OK);
+
+       DBG("Listing kernel map values: map-name = '%s'", map_name);
+
+       ret = kernctl_counter_map_descriptor_count(map->fd, &descr_count);
+       if (ret) {
+               ERR("Error getting map descriptor count");
+               ret_code = LTTNG_ERR_MAP_VALUES_LIST_FAIL;
+               goto end;
+       }
+
+       /*
+        * The kernel tracer sends us descriptors that may be identical aside
+        * from their user token field. This ABI was design this way to cover a
+        * potential use case where the user wants to know what enabler might
+        * have contributed to a specific bucket.
+        *
+        * We use this hashtable to de-duplicate keys.
+        */
+       if (sum_cpus) {
+               values = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+               if (!values) {
+                       ret_code = LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+       }
+
+       DBG("Querying kernel for all map values: "
+                       "map-name = '%s', key-value count = %"PRIu64,
+                       map_name, descr_count);
+       for (cpu_idx = 0; cpu_idx < utils_get_number_of_possible_cpus(); cpu_idx++) {
+               struct lttng_kernel_counter_read value = {0};
+
+               if (config_cpu == LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+                       if (selected_cpu != cpu_idx) {
+                               continue;
+                       }
+               }
+
+               if (!sum_cpus) {
+                       values = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+                       assert(values);
+               }
+
+               key_ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+               if (!key_ht) {
+                       ret_code = LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               for(descr_idx = 0; descr_idx < descr_count; descr_idx++) {
+                       struct lttng_kernel_counter_map_descriptor descriptor = {0};
+
+                       DBG("Querying kernel for map key-value descriptor: "
+                                       "map-name = '%s', descriptor = %"PRIu64,
+                                       map_name, descr_idx);
+                       descriptor.descriptor_index = descr_idx;
+
+                       ret = kernctl_counter_map_descriptor(map->fd, &descriptor);
+                       if (ret) {
+                               ERR("Error getting map descriptor %"PRIu64, descr_idx);
+                               ret_code = LTTNG_ERR_MAP_VALUES_LIST_FAIL;
+                               goto end;
+                       }
+
+                       if (key_filter && strcmp(key_filter, descriptor.key) != 0) {
+                               continue;
+                       }
+
+                       lttng_ht_lookup(key_ht, descriptor.key, &iter);
+                       node = lttng_ht_iter_get_node_str(&iter);
+                       if (node) {
+                               /* This key was already appended to the list. */
+                               continue;
+                       }
+
+
+                       value.index.number_dimensions = 1;
+                       value.index.dimension_indexes[0] = descriptor.array_index;
+                       value.cpu = cpu_idx;
+
+                       DBG("Querying kernel for map descriptor value: "
+                                       "map-name = '%s', counter-index = %"PRIu64,
+                                       map_name, descriptor.array_index);
+                       ret = kernctl_counter_read_value(map->fd, &value);
+                       if (ret) {
+                               ERR("Error getting value of map descriptor %"PRIu64, descr_idx);
+                               ret_code = LTTNG_ERR_MAP_VALUES_LIST_FAIL;
+                               goto end;
+                       }
+
+                       map_add_or_increment_map_values(values, descriptor.key,
+                                       value.value.value, value.value.underflow,
+                                       value.value.overflow);
+
+                       ht_entry = zmalloc(sizeof(*ht_entry));
+                       assert(ht_entry);
+                       ht_entry->key = strdup(descriptor.key);
+                       lttng_ht_node_init_str(&ht_entry->node, ht_entry->key);
+                       lttng_ht_add_unique_str(key_ht, &ht_entry->node);
+               }
+
+               if (!sum_cpus) {
+                       ret = map_new_content_section(local_map_content,
+                                       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_KERNEL,
+                                       sum_cpus, 0,
+                                       cpu_idx, values);
+                       if (ret) {
+                               abort();
+                       }
+
+                       lttng_ht_destroy(values);
+               }
+
+               /*
+                * Remove all the keys before destroying the hashtable.
+                */
+               cds_lfht_for_each_entry(key_ht->ht, &iter.iter, ht_entry, node.node) {
+                       struct lttng_ht_iter entry_iter;
+
+                       entry_iter.iter.node = &ht_entry->node.node;
+                       lttng_ht_del(key_ht, &entry_iter);
+
+                       free(ht_entry);
+               }
+
+               lttng_ht_destroy(key_ht);
+       }
+
+       if (sum_cpus) {
+               ret = map_new_content_section(local_map_content,
+                               LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_KERNEL,
+                               sum_cpus, 0, 0, values);
+               if (ret) {
+                       abort();
+               }
+               lttng_ht_destroy(values);
+       }
+
+
+       *map_content = local_map_content;
+       local_map_content = NULL;
+       ret_code = LTTNG_OK;
+
+end:
+       lttng_map_content_destroy(local_map_content);
+       return ret_code;
+}
+
 int kernel_get_notification_fd(void)
 {
        return kernel_tracer_event_notifier_group_notification_fd;
index a2dd7f060394b782763082692b928a014ee4448d..16d8099303f112bff916484194dd7caa5062cf14 100644 (file)
@@ -87,12 +87,32 @@ enum lttng_error_code kernel_create_event_notifier_group_notification_fd(
 enum lttng_error_code kernel_destroy_event_notifier_group_notification_fd(
                int event_notifier_group_notification_fd);
 
+enum lttng_error_code kernel_create_event_counter(
+               struct ltt_kernel_map *kmap,
+               const struct lttng_credentials *creds,
+               uint64_t action_tracer_token,
+               const struct lttng_event_rule *event_rule,
+               struct lttng_map_key *key);
+
+enum lttng_error_code kernel_register_incr_value_action(
+               struct ltt_session *session,
+               const struct lttng_condition *condition,
+               const char *map_name,
+               uint64_t tracer_token,
+               struct lttng_map_key *key);
+
 enum lttng_error_code kernel_register_event_notifier(
                struct lttng_trigger *trigger,
                const struct lttng_credentials *cmd_creds);
 enum lttng_error_code kernel_unregister_event_notifier(
                const struct lttng_trigger *trigger);
 
+enum lttng_error_code kernel_synchronize_tracer_executed_action(void);
+
+enum lttng_error_code kernel_list_map_values(const struct ltt_kernel_map *map,
+               const struct lttng_map_query *query,
+               struct lttng_map_content **map_content);
+
 int kernel_get_notification_fd(void);
 
 #endif /* _LTT_KERNEL_CTL_H */
index a344cd4769dbce11493828e2c1f6bbb367f255c3..6e4950e54887a9767bad655653335a8ad15b0304 100644 (file)
@@ -49,9 +49,9 @@
 #include "consumer.h"
 #include "context.h"
 #include "event.h"
+#include "event-notifier-error-accounting.h"
 #include "kernel.h"
 #include "kernel-consumer.h"
-#include "shm.h"
 #include "lttng-ust-ctl.h"
 #include "ust-consumer.h"
 #include "utils.h"
@@ -74,6 +74,7 @@
 #include "register.h"
 #include "manage-apps.h"
 #include "manage-kernel.h"
+#include "modprobe.h"
 
 static const char *help_msg =
 #ifdef LTTNG_EMBED_HELP
@@ -83,6 +84,8 @@ NULL
 #endif
 ;
 
+#define EVENT_NOTIFIER_ERROR_COUNTER_NUMBER_OF_BUCKET_MAX 65535
+
 const char *progname;
 static int lockfile_fd = -1;
 static int opt_print_version;
@@ -120,6 +123,7 @@ static const struct option long_options[] = {
        { "load", required_argument, 0, 'l' },
        { "kmod-probes", required_argument, 0, '\0' },
        { "extra-kmod-probes", required_argument, 0, '\0' },
+       { "event-notifier-error-number-of-bucket", required_argument, 0, '\0' },
        { NULL, 0, 0, 0 }
 };
 
@@ -697,6 +701,23 @@ static int set_option(int opt, const char *arg, const char *optname)
                                ret = -ENOMEM;
                        }
                }
+       } else if (string_match(optname, "event-notifier-error-number-of-bucket")) {
+               unsigned long v;
+
+               errno = 0;
+               v = strtoul(arg, NULL, 0);
+               if (errno != 0 || !isdigit(arg[0])) {
+                       ERR("Wrong value in --event-notifier-error-number-of-bucket parameter: %s", arg);
+                       return -1;
+               }
+               if (v == 0 || v >= EVENT_NOTIFIER_ERROR_COUNTER_NUMBER_OF_BUCKET_MAX) {
+                       ERR("Value out of range for --event-notifier-error-number-of-bucket parameter: %s", arg);
+                       return -1;
+               }
+               config.event_notifier_error_counter_bucket = (int) v;
+               DBG3("Number of event notifier error counter set to non default: %i",
+                               config.event_notifier_error_counter_bucket);
+               goto end;
        } else if (string_match(optname, "config") || opt == 'f') {
                /* This is handled in set_options() thus silent skip. */
                goto end;
@@ -1243,6 +1264,7 @@ static void destroy_all_sessions_and_wait(void)
                        goto unlock_session;
                }
                (void) cmd_stop_trace(session);
+
                (void) cmd_destroy_session(session, notification_thread_handle,
                                NULL);
        unlock_session:
@@ -1589,6 +1611,8 @@ int main(int argc, char **argv)
                goto stop_threads;
        }
 
+       event_notifier_error_accounting_init(config.event_notifier_error_counter_bucket);
+
        /*
         * Initialize agent app hash table. We allocate the hash table here
         * since cleanup() can get called after this point.
@@ -1826,6 +1850,7 @@ int main(int argc, char **argv)
        sessiond_wait_for_quit_pipe(-1);
 
 stop_threads:
+
        /*
         * Ensure that the client thread is no longer accepting new commands,
         * which could cause new sessions to be created.
@@ -1864,7 +1889,7 @@ stop_threads:
        sessiond_cleanup();
 
        /*
-        * Wait for all pending call_rcu work to complete tearing shutting down
+        * Wait for all pending call_rcu work to complete before shutting down
         * the notification thread. This call_rcu work includes shutting down
         * UST apps and event notifier pipes.
         */
@@ -1875,6 +1900,27 @@ stop_threads:
                lttng_thread_put(notification_thread);
        }
 
+       /*
+        * Error accounting teardown has to be done after the teardown of all
+        * event notifier pipes to ensure that no tracer may try to use the
+        * error accounting facilities.
+        */
+       event_notifier_error_accounting_fini();
+
+       /*
+        * Unloading the kernel modules needs to be done after all kernel
+        * ressources have been released. In our case, this includes the
+        * notification fd, the event notifier group fd, error accounting fd,
+        * all event and event notifier fds, etc.
+        *
+        * In short, at this point, we need to have called close() on all fds
+        * received from the kernel tracer.
+        */
+       if (is_root && !config.no_kernel) {
+               DBG("Unloading kernel modules");
+               modprobe_remove_lttng_all();
+       }
+
        /*
         * Ensure all prior call_rcu are done. call_rcu callbacks may push
         * hash tables to the ht_cleanup thread. Therefore, we ensure that
diff --git a/src/bin/lttng-sessiond/map.c b/src/bin/lttng-sessiond/map.c
new file mode 100644 (file)
index 0000000..6e63504
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+
+#include "lttng/domain.h"
+#include <common/kernel-ctl/kernel-ctl.h>
+#include <lttng/map/map.h>
+#include <lttng/map/map-internal.h>
+
+#include "lttng-sessiond.h"
+#include "lttng-ust-error.h"
+#include "notification-thread-commands.h"
+#include "trace-kernel.h"
+#include "trace-ust.h"
+
+#include "map.h"
+
+enum lttng_error_code map_kernel_add(struct ltt_kernel_session *ksession,
+               struct lttng_map *map)
+{
+       enum lttng_error_code ret;
+       struct ltt_kernel_map *kmap;
+       enum lttng_map_status map_status;
+       const char *map_name;
+
+       assert(lttng_map_get_domain(map) == LTTNG_DOMAIN_KERNEL);
+
+       map_status = lttng_map_get_name(map, &map_name);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Can't get map name");
+               ret = -1;
+               goto error;
+       }
+
+       kmap = trace_kernel_get_map_by_name(map_name, ksession);
+       if (kmap) {
+               DBG("Kernel map named \"%s\" already present", map_name);
+               ret = -1;
+               goto error;
+       }
+
+       kmap = trace_kernel_create_map(map);
+       assert(kmap);
+
+       ret = kernctl_create_session_counter(ksession->fd,
+                       &kmap->counter_conf);
+       if (ret < 0) {
+               PERROR("ioctl kernel create session counter");
+               goto error;
+       }
+
+       kmap->fd = ret;
+
+       /* Prevent fd duplication after execlp() */
+       ret = fcntl(kmap->fd, F_SETFD, FD_CLOEXEC);
+       if (ret < 0) {
+               PERROR("fcntl session counter fd");
+               goto error;
+       }
+
+       kmap->map = map;
+       lttng_map_get(map);
+       cds_list_add(&kmap->list, &ksession->map_list.head);
+       ksession->map_count++;
+
+       DBG("Kernel session counter created (fd: %d)", kmap->fd);
+
+       ret = kernctl_enable(kmap->fd);
+       if (ret < 0) {
+               PERROR("Enable kernel map");
+       }
+
+       ret = LTTNG_OK;
+error:
+       return ret;
+}
+
+enum lttng_error_code map_kernel_enable(struct ltt_kernel_session *ksess,
+               struct ltt_kernel_map *kmap)
+{
+       enum lttng_error_code ret = LTTNG_OK;
+       const char *map_name;
+       enum lttng_map_status map_status;
+
+
+       assert(ksess);
+       assert(kmap);
+
+       map_status = lttng_map_get_name(kmap->map, &map_name);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Error getting kernel map name");
+               ret = -1;
+               goto end;
+       }
+
+       /* If already enabled, everything is OK */
+       if (kmap->enabled) {
+               DBG3("Map %s already enabled. Skipping", map_name);
+               ret = LTTNG_ERR_UST_MAP_EXIST;
+               goto end;
+       } else {
+               kmap->enabled = 1;
+               lttng_map_set_is_enabled(kmap->map, true);
+               DBG2("Map %s enabled successfully", map_name);
+       }
+
+       DBG2("Map %s being enabled in kernel domain", map_name);
+
+       /*
+        * Enable map for UST global domain on all applications. Ignore return
+        * value here since whatever error we got, it means that the map was
+        * not created on one or many registered applications and we can not report
+        * this to the user yet. However, at this stage, the map was
+        * successfully created on the session daemon side so the enable-map
+        * command is a success.
+        */
+
+       ret = kernctl_enable(kmap->fd);
+       if (ret < 0) {
+               PERROR("Enable kernel map");
+       }
+
+       ret = LTTNG_OK;
+end:
+       return ret;
+}
+
+enum lttng_error_code map_kernel_disable(struct ltt_kernel_session *usess,
+               struct ltt_kernel_map *kmap)
+{
+       enum lttng_error_code ret = LTTNG_OK;
+       enum lttng_map_status map_status;
+       const char *map_name = NULL;
+
+       assert(usess);
+       assert(kmap);
+
+       map_status = lttng_map_get_name(kmap->map, &map_name);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Error getting kernel map name");
+               ret = -1;
+               goto end;
+       }
+
+       /* Already disabled */
+       if (kmap->enabled == 0) {
+               DBG2("Map kernel %s already disabled", map_name);
+               ret = LTTNG_ERR_KERNEL_MAP_EXIST;
+               goto end;
+       }
+
+       kmap->enabled = 0;
+       lttng_map_set_is_enabled(kmap->map, false);
+
+       DBG2("Map %s being disabled in kernel global domain", map_name);
+
+       /* Disable map for global domain */
+       ret = kernctl_disable(kmap->fd);
+       if (ret < 0) {
+               ret = LTTNG_ERR_KERNEL_MAP_DISABLE_FAIL;
+               goto error;
+       }
+
+
+       DBG2("Map %s disabled successfully", map_name);
+
+       return LTTNG_OK;
+
+end:
+error:
+       return ret;
+}
+
+int map_ust_add(struct ltt_ust_session *usession, struct lttng_map *map)
+{
+       int ret = 0;
+       struct ltt_ust_map *umap;
+       enum lttng_map_status map_status;
+       const char *map_name;
+       enum lttng_buffer_type buffer_type;
+
+       assert(lttng_map_get_domain(map) == LTTNG_DOMAIN_UST);
+
+       map_status = lttng_map_get_name(map, &map_name);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Can't get map name");
+               ret = -1;
+               goto end;
+       }
+
+       umap = trace_ust_find_map_by_name(usession->domain_global.maps,
+                       map_name);
+       if (umap) {
+               DBG("UST map named \"%s\" already present", map_name);
+               ret = -1;
+               goto end;
+       }
+
+       buffer_type = lttng_map_get_buffer_type(map);
+
+       umap = trace_ust_create_map(map);
+       assert(umap);
+
+       umap->enabled = 1;
+       umap->id = trace_ust_get_next_chan_id(usession);
+       umap->map = map;
+       lttng_map_get(map);
+
+       lttng_map_set_is_enabled(umap->map, true);
+
+       DBG2("Map %s is being created for UST with buffer type %d and id %" PRIu64,
+                       umap->name, buffer_type, umap->id);
+
+       /* Flag session buffer type. */
+       if (!usession->buffer_type_changed) {
+               usession->buffer_type = buffer_type;
+               usession->buffer_type_changed = 1;
+       } else if (usession->buffer_type != buffer_type) {
+               /* Buffer type was already set. Refuse to create channel. */
+               ret = LTTNG_ERR_BUFFER_TYPE_MISMATCH;
+               goto error_free_map;
+       }
+
+       rcu_read_lock();
+
+       /* Adding the map to the map hash table. */
+       lttng_ht_add_unique_str(usession->domain_global.maps, &umap->node);
+
+       rcu_read_unlock();
+
+       DBG2("Map %s created successfully", umap->name);
+
+       ret = 0;
+       goto end;
+
+error_free_map:
+       trace_ust_destroy_map(umap);
+end:
+       return ret;
+}
+
+/*
+ * Enable UST map for session and domain.
+ */
+int map_ust_enable(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap)
+{
+       int ret = LTTNG_OK;
+
+       assert(usess);
+       assert(umap);
+
+       /* If already enabled, everything is OK */
+       if (umap->enabled) {
+               DBG3("Map %s already enabled. Skipping", umap->name);
+               ret = LTTNG_ERR_UST_MAP_EXIST;
+               goto end;
+       } else {
+               umap->enabled = 1;
+               lttng_map_set_is_enabled(umap->map, true);
+               DBG2("Map %s enabled successfully", umap->name);
+       }
+
+       if (!usess->active) {
+               /*
+                * The map will be activated against the apps
+                * when the session is started as part of the
+                * application map "synchronize" operation.
+                */
+               goto end;
+       }
+
+       DBG2("Map %s being enabled in UST domain", umap->name);
+
+       /*
+        * Enable map for UST global domain on all applications. Ignore return
+        * value here since whatever error we got, it means that the map was
+        * not created on one or many registered applications and we can not report
+        * this to the user yet. However, at this stage, the map was
+        * successfully created on the session daemon side so the enable-map
+        * command is a success.
+        */
+       (void) ust_app_enable_map_glb(usess, umap);
+
+
+end:
+       return ret;
+}
+
+int map_ust_disable(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap)
+{
+       int ret = LTTNG_OK;
+
+       assert(usess);
+       assert(umap);
+
+       /* Already disabled */
+       if (umap->enabled == 0) {
+               DBG2("Map UST %s already disabled", umap->name);
+               ret = LTTNG_ERR_UST_MAP_EXIST;
+               goto end;
+       }
+
+       umap->enabled = 0;
+       lttng_map_set_is_enabled(umap->map, false);
+
+       /*
+        * If session is inactive we don't notify the tracer right away. We
+        * wait for the next synchronization.
+        */
+       if (!usess->active) {
+               goto end;
+       }
+
+       DBG2("Map %s being disabled in UST global domain", umap->name);
+
+       /* Disable map for global domain */
+       ret = ust_app_disable_map_glb(usess, umap);
+       if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
+               ret = LTTNG_ERR_UST_MAP_DISABLE_FAIL;
+               goto error;
+       }
+
+
+       DBG2("Map %s disabled successfully", umap->name);
+
+       return LTTNG_OK;
+
+end:
+error:
+       return ret;
+}
+
+void map_add_or_increment_map_values(struct lttng_ht *map_values, const char *key,
+               int64_t value, bool has_underflowed, bool has_overflowed)
+{
+       struct map_kv_ht_entry *kv_entry;
+       struct lttng_ht_node_str *node;
+       struct lttng_ht_iter ht_iter;
+
+       lttng_ht_lookup(map_values, (void *) key, &ht_iter);
+       node = lttng_ht_iter_get_node_str(&ht_iter);
+       if (node == NULL) {
+               /*
+                * If the key is absent, the key value mapping.
+                */
+               kv_entry = zmalloc(sizeof(*kv_entry));
+               if (!kv_entry) {
+                       abort();
+               }
+
+               kv_entry->key = strdup(key);
+               kv_entry->value = value;
+               kv_entry->has_underflowed = has_underflowed;
+               kv_entry->has_overflowed = has_overflowed;
+
+               lttng_ht_node_init_str(&kv_entry->node, (char *) kv_entry->key);
+               lttng_ht_add_unique_str(map_values, &kv_entry->node);
+
+       } else {
+               /*
+                * If the key is already present, increment the current value with the
+                * new value.
+                */
+               kv_entry = caa_container_of(node, typeof(*kv_entry), node);
+               kv_entry->value += value;
+               kv_entry->has_underflowed |= has_underflowed;
+               kv_entry->has_overflowed |= has_overflowed;
+       }
+}
+
+int map_new_content_section(struct lttng_map_content *map_content,
+               enum lttng_map_key_value_pair_list_type list_type,
+               bool summed_all_cpus, unsigned int identifier,
+               int cpu, struct lttng_ht *values)
+{
+       int ret;
+       struct lttng_map_key_value_pair_list *kv_pair_list;
+       enum lttng_map_status map_status;
+       struct map_kv_ht_entry *kv_entry;
+       struct lttng_ht_iter key_iter;
+
+       kv_pair_list = lttng_map_key_value_pair_list_create(list_type,
+                       summed_all_cpus);
+       switch (list_type) {
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID:
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID:
+               map_status = lttng_map_key_value_pair_list_set_identifier(
+                               kv_pair_list, identifier);
+               assert(map_status == LTTNG_MAP_STATUS_OK);
+               break;
+       default:
+               break;
+       }
+
+       if (!summed_all_cpus) {
+               map_status = lttng_map_key_value_pair_list_set_cpu(kv_pair_list,
+                               cpu);
+       }
+
+       cds_lfht_for_each_entry(values->ht, &key_iter.iter, kv_entry, node.node) {
+               struct lttng_ht_iter entry_iter;
+
+               struct lttng_map_key_value_pair *pair =
+                               lttng_map_key_value_pair_create(kv_entry->key,
+                                       kv_entry->value);
+               if (kv_entry->has_overflowed) {
+                       lttng_map_key_value_pair_set_has_overflowed(pair);
+               }
+
+               if (kv_entry->has_underflowed) {
+                       lttng_map_key_value_pair_set_has_underflowed(pair);
+               }
+
+               map_status = lttng_map_key_value_pair_list_append_key_value(
+                               kv_pair_list, pair);
+
+               entry_iter.iter.node = &kv_entry->node.node;
+               lttng_ht_del(values, &entry_iter);
+
+               free(kv_entry->key);
+               free(kv_entry);
+       }
+
+       map_status = lttng_map_content_append_key_value_list(map_content,
+                       kv_pair_list);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               lttng_map_key_value_pair_list_destroy(kv_pair_list);
+               ret = -1;
+               ERR("Error appending key-value pair list to map content object");
+               goto end;
+       }
+       ret = 0;
+end:
+       return ret;
+}
+
diff --git a/src/bin/lttng-sessiond/map.h b/src/bin/lttng-sessiond/map.h
new file mode 100644 (file)
index 0000000..1c84fe6
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+#ifndef _LTT_MAP_H
+#define _LTT_MAP_H
+
+#include <lttng/map/map.h>
+#include <common/kernel-ctl/kernel-ctl.h>
+#include "trace-kernel.h"
+#include "trace-ust.h"
+
+struct map_kv_ht_entry {
+       struct lttng_ht_node_str node;
+       char *key;
+       int64_t value;
+       bool has_overflowed;
+       bool has_underflowed;
+};
+
+enum lttng_error_code map_kernel_add(struct ltt_kernel_session *ksession,
+               struct lttng_map *map);
+enum lttng_error_code map_kernel_enable(struct ltt_kernel_session *ksession,
+               struct ltt_kernel_map *kmap);
+enum lttng_error_code map_kernel_disable(struct ltt_kernel_session *ksession,
+               struct ltt_kernel_map *kmap);
+
+int map_ust_add(struct ltt_ust_session *usession,
+               struct lttng_map *map);
+int map_ust_enable(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap);
+int map_ust_disable(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap);
+
+void map_add_or_increment_map_values(struct lttng_ht *map_values, const char *key,
+               int64_t value, bool has_underflowed, bool has_overflowed);
+
+int map_new_content_section(struct lttng_map_content *map_content,
+               enum lttng_map_key_value_pair_list_type list_type,
+               bool summed_all_cpus, unsigned int identifier,
+               int cpu, struct lttng_ht *values);
+
+#endif /* _LTT_MAP_H */
index 28385ea39e6affd19e30627b97411c8fa2817a99..8d162857f6ae88eeec547857d96baf055db99b63 100644 (file)
@@ -56,6 +56,14 @@ struct kern_modules_param kern_modules_control_core[] = {
                .name = (char *) "lttng-ring-buffer-event_notifier-client",
                .load_policy = KERNEL_MODULE_PROPERTY_LOAD_POLICY_OPTIONAL,
        },
+       {
+               .name = (char *) "lttng-counter-client-percpu-64-modular",
+               .load_policy = KERNEL_MODULE_PROPERTY_LOAD_POLICY_OPTIONAL,
+       },
+       {
+               .name = (char *) "lttng-counter-client-percpu-32-modular",
+               .load_policy = KERNEL_MODULE_PROPERTY_LOAD_POLICY_OPTIONAL,
+       },
 };
 
 /* LTTng kerneltracer probe modules list */
@@ -506,14 +514,23 @@ static void modprobe_remove_lttng(const struct kern_modules_param *modules,
                modprobe[sizeof(modprobe) - 1] = '\0';
                ret = system(modprobe);
                if (ret == -1) {
-                       ERR("Unable to launch modprobe -r for module %s",
-                                       modules[i].name);
-               } else if (modules[i].load_policy == KERNEL_MODULE_PROPERTY_LOAD_POLICY_REQUIRED && WEXITSTATUS(ret) != 0) {
-                       ERR("Unable to remove module %s",
-                                       modules[i].name);
+                       if (modules[i].load_policy == KERNEL_MODULE_PROPERTY_LOAD_POLICY_REQUIRED) {
+                               ERR("Unable to launch modprobe -r for required module %s",
+                                               modules[i].name);
+                       } else {
+                               DBG("Unable to launch modprobe -r for optional module %s",
+                                               modules[i].name);
+                       }
+               } else if (WEXITSTATUS(ret) != 0) {
+                       if (modules[i].load_policy == KERNEL_MODULE_PROPERTY_LOAD_POLICY_REQUIRED) {
+                               ERR("Unable to remove required module %s",
+                                               modules[i].name);
+                       } else {
+                               DBG("Unable to remove optional module %s",
+                                               modules[i].name);
+                       }
                } else {
-                       DBG("Modprobe removal successful %s",
-                                       modules[i].name);
+                       DBG("Modprobe removal successful %s", modules[i].name);
                }
        }
 }
index 44bee3d3ba6f634e4fe14db72db3e612ead6a5d6..bc8db39d7e452e14df6053b4116effcbde40415d 100644 (file)
@@ -382,17 +382,48 @@ int notification_thread_client_communication_update(
        return run_command_no_wait(handle, &cmd);
 }
 
+enum lttng_error_code notification_thread_command_get_trigger(
+               struct notification_thread_handle *handle,
+               const struct lttng_trigger *trigger,
+               struct lttng_trigger **real_trigger)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       struct notification_thread_command cmd = {};
+
+       init_notification_thread_command(&cmd);
+
+       cmd.type = NOTIFICATION_COMMAND_TYPE_GET_TRIGGER;
+       cmd.parameters.get_trigger.trigger= trigger;
+       ret = run_command_wait(handle, &cmd);
+       if (ret) {
+               ret_code = LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       ret_code = cmd.reply_code;
+       *real_trigger = cmd.reply.get_trigger.trigger;
+
+end:
+       return ret_code;
+}
+
+/*
+ * Takes ownership of the payload if present.
+ */
 LTTNG_HIDDEN
-struct lttng_event_notifier_notification *
-lttng_event_notifier_notification_create(uint64_t tracer_token,
-               enum lttng_domain_type domain)
+struct lttng_event_notifier_notification *lttng_event_notifier_notification_create(
+               uint64_t tracer_token,
+               enum lttng_domain_type domain,
+               char *payload,
+               size_t payload_size)
 {
        struct lttng_event_notifier_notification *notification = NULL;
 
        assert(domain != LTTNG_DOMAIN_NONE);
+       assert((payload && payload_size) || (!payload && !payload_size));
 
-       notification = zmalloc(
-                       sizeof(struct lttng_event_notifier_notification));
+       notification = zmalloc(sizeof(struct lttng_event_notifier_notification));
        if (notification == NULL) {
                ERR("[notification-thread] Error allocating notification");
                goto end;
@@ -400,6 +431,8 @@ lttng_event_notifier_notification_create(uint64_t tracer_token,
 
        notification->tracer_token = tracer_token;
        notification->type = domain;
+       notification->capture_buffer = payload;
+       notification->capture_buf_size = payload_size;
 
 end:
        return notification;
@@ -413,5 +446,6 @@ void lttng_event_notifier_notification_destroy(
                return;
        }
 
+       free(notification->capture_buffer);
        free(notification);
 }
index 50751a94d1ed4dc3c6cf6f2a4c68e55d6d4abf12..882959a29d0cc2c571e70e49d78552997ae71531 100644 (file)
@@ -32,6 +32,7 @@ enum notification_thread_command_type {
        NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS,
        NOTIFICATION_COMMAND_TYPE_QUIT,
        NOTIFICATION_COMMAND_TYPE_CLIENT_COMMUNICATION_UPDATE,
+       NOTIFICATION_COMMAND_TYPE_GET_TRIGGER,
 };
 
 struct notification_thread_command {
@@ -89,12 +90,19 @@ struct notification_thread_command {
                        enum client_transmission_status status;
                } client_communication_update;
 
+               struct {
+                       const struct lttng_trigger *trigger;
+               } get_trigger;
+
        } parameters;
 
        union {
                struct {
                        struct lttng_triggers *triggers;
                } list_triggers;
+               struct {
+                       struct lttng_trigger *trigger;
+               } get_trigger;
        } reply;
        /* lttng_waiter on which to wait for command reply (optional). */
        struct lttng_waiter reply_waiter;
@@ -166,4 +174,9 @@ enum lttng_error_code notification_thread_command_remove_tracer_event_source(
 void notification_thread_command_quit(
                struct notification_thread_handle *handle);
 
+enum lttng_error_code notification_thread_command_get_trigger(
+               struct notification_thread_handle *handle,
+               const struct lttng_trigger *trigger,
+               struct lttng_trigger **real_trigger);
+
 #endif /* NOTIFICATION_THREAD_COMMANDS_H */
index 747902612d93059705cd9d987cde39e1cc757a31..0498aac353813bbf6a00271ab8b7bd44e3255050 100644 (file)
 #include <common/macros.h>
 #include <lttng/condition/condition.h>
 #include <lttng/action/action-internal.h>
+#include <lttng/action/group-internal.h>
+#include <lttng/action/incr-value-internal.h>
+#include <lttng/domain-internal.h>
 #include <lttng/notification/notification-internal.h>
 #include <lttng/condition/condition-internal.h>
 #include <lttng/condition/buffer-usage-internal.h>
 #include <lttng/condition/session-consumed-size-internal.h>
 #include <lttng/condition/session-rotation-internal.h>
-#include <lttng/condition/event-rule-internal.h>
+#include <lttng/condition/on-event-internal.h>
 #include <lttng/domain-internal.h>
 #include <lttng/notification/channel-internal.h>
 #include <lttng/trigger/trigger-internal.h>
 #include <fcntl.h>
 
 #include "condition-internal.h"
+#include "event-notifier-error-accounting.h"
 #include "notification-thread.h"
 #include "notification-thread-events.h"
 #include "notification-thread-commands.h"
 #include "lttng-sessiond.h"
 #include "kernel.h"
+#include "event.h"
 
 #define CLIENT_POLL_MASK_IN (LPOLLIN | LPOLLERR | LPOLLHUP | LPOLLRDHUP)
 #define CLIENT_POLL_MASK_IN_OUT (CLIENT_POLL_MASK_IN | LPOLLOUT)
 
+/* The tracers currently limit the capture size to PIPE_BUF (4kb on linux). */
+#define MAX_CAPTURE_SIZE (PIPE_BUF)
+
 enum lttng_object_type {
        LTTNG_OBJECT_TYPE_UNKNOWN,
        LTTNG_OBJECT_TYPE_NONE,
@@ -116,6 +124,7 @@ struct lttng_trigger_ht_element {
        struct lttng_trigger *trigger;
        struct cds_lfht_node node;
        struct cds_lfht_node node_by_name_uid;
+       struct cds_list_head client_list_trigger_node;
        /* call_rcu delayed reclaim. */
        struct rcu_head rcu_node;
 };
@@ -308,7 +317,7 @@ int match_client_list_condition(struct cds_lfht_node *node, const void *key)
 
        client_list = caa_container_of(node, struct notification_client_list,
                        notification_trigger_clients_ht_node);
-       condition = lttng_trigger_get_const_condition(client_list->trigger);
+       condition = client_list->condition;
 
        return !!lttng_condition_is_equal(condition_key, condition);
 }
@@ -346,6 +355,8 @@ const char *notification_command_type_str(
                return "REMOVE_TRACER_EVENT_SOURCE";
        case NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS:
                return "LIST_TRIGGERS";
+       case NOTIFICATION_COMMAND_TYPE_GET_TRIGGER:
+               return "GET_TRIGGER";
        case NOTIFICATION_COMMAND_TYPE_QUIT:
                return "QUIT";
        case NOTIFICATION_COMMAND_TYPE_CLIENT_COMMUNICATION_UPDATE:
@@ -462,7 +473,7 @@ enum lttng_object_type get_condition_binding_object(
        case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
        case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
                return LTTNG_OBJECT_TYPE_SESSION;
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
                return LTTNG_OBJECT_TYPE_NONE;
        default:
                return LTTNG_OBJECT_TYPE_UNKNOWN;
@@ -655,62 +666,119 @@ void notification_client_list_release(struct urcu_ref *list_ref)
                        container_of(list_ref, typeof(*list), ref);
        struct notification_client_list_element *client_list_element, *tmp;
 
+       lttng_condition_put(list->condition);
+
        if (list->notification_trigger_clients_ht) {
                rcu_read_lock();
+
                cds_lfht_del(list->notification_trigger_clients_ht,
                                &list->notification_trigger_clients_ht_node);
                rcu_read_unlock();
                list->notification_trigger_clients_ht = NULL;
        }
        cds_list_for_each_entry_safe(client_list_element, tmp,
-                                    &list->list, node) {
+                                    &list->clients_list, node) {
                free(client_list_element);
        }
+
+       assert(cds_list_empty(&list->triggers_list));
+
        pthread_mutex_destroy(&list->lock);
        call_rcu(&list->rcu_node, free_notification_client_list_rcu);
 }
 
+static
+bool condition_applies_to_client(const struct lttng_condition *condition,
+               struct notification_client *client)
+{
+       bool applies = false;
+       struct lttng_condition_list_element *condition_list_element;
+
+       cds_list_for_each_entry(condition_list_element, &client->condition_list,
+                       node) {
+               applies = lttng_condition_is_equal(
+                               condition_list_element->condition,
+                               condition);
+               if (applies) {
+                       break;
+               }
+       }
+       return applies;
+}
+
 static
 struct notification_client_list *notification_client_list_create(
-               const struct lttng_trigger *trigger)
+               struct notification_thread_state *state,
+               const struct lttng_condition *condition)
 {
-       struct notification_client_list *client_list =
-                       zmalloc(sizeof(*client_list));
+       struct notification_client *client;
+       struct cds_lfht_iter iter;
+       struct notification_client_list *client_list;
 
+       client_list = zmalloc(sizeof(*client_list));
        if (!client_list) {
-               goto error;
+               goto end;
        }
+
        pthread_mutex_init(&client_list->lock, NULL);
+       /*
+        * The trigger that owns the condition has the first reference to this
+        * client list.
+        */
        urcu_ref_init(&client_list->ref);
        cds_lfht_node_init(&client_list->notification_trigger_clients_ht_node);
-       CDS_INIT_LIST_HEAD(&client_list->list);
-       client_list->trigger = trigger;
-error:
-       return client_list;
-}
+       CDS_INIT_LIST_HEAD(&client_list->clients_list);
+       CDS_INIT_LIST_HEAD(&client_list->triggers_list);
 
-static
-void publish_notification_client_list(
-               struct notification_thread_state *state,
-               struct notification_client_list *list)
-{
-       const struct lttng_condition *condition =
-                       lttng_trigger_get_const_condition(list->trigger);
+       /*
+        * Create a copy of the condition so that it's independent of any
+        * trigger. The client list may outlive the trigger object (which owns
+        * the condition) that is used to create it.
+        */
+       client_list->condition = lttng_condition_copy(condition);
+
+       /* Build a list of clients to which this new condition applies. */
+       cds_lfht_for_each_entry (state->client_socket_ht, &iter, client,
+                       client_socket_ht_node) {
+               struct notification_client_list_element *client_list_element;
 
-       assert(!list->notification_trigger_clients_ht);
-       notification_client_list_get(list);
+               if (!condition_applies_to_client(condition, client)) {
+                       continue;
+               }
 
-       list->notification_trigger_clients_ht =
+               client_list_element = zmalloc(sizeof(*client_list_element));
+               if (!client_list_element) {
+                       goto error_put_client_list;
+               }
+
+               CDS_INIT_LIST_HEAD(&client_list_element->node);
+               client_list_element->client = client;
+               cds_list_add(&client_list_element->node, &client_list->clients_list);
+       }
+
+       client_list->notification_trigger_clients_ht =
                        state->notification_trigger_clients_ht;
 
        rcu_read_lock();
-       cds_lfht_add(state->notification_trigger_clients_ht,
-                       lttng_condition_hash(condition),
-                       &list->notification_trigger_clients_ht_node);
+       /*
+        * Add the client list to the global list of client list.
+        */
+       cds_lfht_add_unique(state->notification_trigger_clients_ht,
+                       lttng_condition_hash(client_list->condition),
+                       match_client_list_condition,
+                       client_list->condition,
+                       &client_list->notification_trigger_clients_ht_node);
        rcu_read_unlock();
+       goto end;
+
+error_put_client_list:
+       notification_client_list_put(client_list);
+       client_list = NULL;
+
+end:
+       return client_list;
 }
 
-LTTNG_HIDDEN
 void notification_client_list_put(struct notification_client_list *list)
 {
        if (!list) {
@@ -998,12 +1066,11 @@ int evaluate_condition_for_client(const struct lttng_trigger *trigger,
         * subscribing.
         */
        cds_lfht_node_init(&client_list.notification_trigger_clients_ht_node);
-       CDS_INIT_LIST_HEAD(&client_list.list);
-       client_list.trigger = trigger;
+       CDS_INIT_LIST_HEAD(&client_list.clients_list);
 
        CDS_INIT_LIST_HEAD(&client_list_element.node);
        client_list_element.client = client;
-       cds_list_add(&client_list_element.node, &client_list.list);
+       cds_list_add(&client_list_element.node, &client_list.clients_list);
 
        /* Send evaluation result to the newly-subscribed client. */
        DBG("[notification-thread] Newly subscribed-to condition evaluated to true, notifying client");
@@ -1077,13 +1144,19 @@ int notification_thread_client_subscribe(struct notification_client *client,
         * This is correct since the list doesn't own the trigger and the
         * object is immutable.
         */
-       if (evaluate_condition_for_client(client_list->trigger, condition,
-                       client, state)) {
-               WARN("[notification-thread] Evaluation of a condition on client subscription failed, aborting.");
-               ret = -1;
-               free(client_list_element);
-               goto end;
+       struct lttng_trigger_ht_element *trigger_ht_element;
+       pthread_mutex_lock(&client_list->lock);
+       cds_list_for_each_entry(trigger_ht_element,
+                       &client_list->triggers_list, client_list_trigger_node) {
+               if (evaluate_condition_for_client(trigger_ht_element->trigger, condition,
+                               client, state)) {
+                       WARN("[notification-thread] Evaluation of a condition on client subscription failed, aborting.");
+                       ret = -1;
+                       free(client_list_element);
+                       goto end;
+               }
        }
+       pthread_mutex_unlock(&client_list->lock);
 
        /*
         * Add the client to the list of clients interested in a given trigger
@@ -1094,7 +1167,7 @@ int notification_thread_client_subscribe(struct notification_client *client,
        CDS_INIT_LIST_HEAD(&client_list_element->node);
 
        pthread_mutex_lock(&client_list->lock);
-       cds_list_add(&client_list_element->node, &client_list->list);
+       cds_list_add(&client_list_element->node, &client_list->clients_list);
        pthread_mutex_unlock(&client_list->lock);
 end:
        if (_status) {
@@ -1165,7 +1238,7 @@ int notification_thread_client_unsubscribe(
 
        pthread_mutex_lock(&client_list->lock);
        cds_list_for_each_entry_safe(client_list_element, client_tmp,
-                       &client_list->list, node) {
+                       &client_list->clients_list, node) {
                if (client_list_element->client->id != client->id) {
                        continue;
                }
@@ -1358,25 +1431,6 @@ fail:
        return false;
 }
 
-static
-bool trigger_applies_to_client(struct lttng_trigger *trigger,
-               struct notification_client *client)
-{
-       bool applies = false;
-       struct lttng_condition_list_element *condition_list_element;
-
-       cds_list_for_each_entry(condition_list_element, &client->condition_list,
-                       node) {
-               applies = lttng_condition_is_equal(
-                               condition_list_element->condition,
-                               lttng_trigger_get_condition(trigger));
-               if (applies) {
-                       break;
-               }
-       }
-       return applies;
-}
-
 /* Must be called with RCU read lock held. */
 static
 struct lttng_session_trigger_list *get_session_trigger_list(
@@ -1718,7 +1772,6 @@ error:
        session_info_put(session_info);
        return 1;
 }
-
 static
 void free_channel_trigger_list_rcu(struct rcu_head *node)
 {
@@ -2118,6 +2171,29 @@ end:
        return ret;
 }
 
+static
+int condition_on_event_update_error_count(struct lttng_trigger *trigger)
+{
+       int ret = 0;
+       uint64_t error_count = 0;
+       struct lttng_condition *condition;
+       enum event_notifier_error_accounting_status status;
+
+       condition = lttng_trigger_get_condition(trigger);
+
+       assert(lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_ON_EVENT);
+
+       status = event_notifier_error_accounting_get_count(trigger, &error_count);
+       if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+               ERR("Error getting event notifier error count.");
+               ret = -1;
+       }
+
+       lttng_condition_on_event_set_error_count(condition, error_count);
+
+       return ret;
+}
+
 int handle_notification_thread_remove_tracer_event_source_no_result(
                struct notification_thread_state *state,
                int tracer_event_source_fd)
@@ -2165,6 +2241,12 @@ static int handle_notification_thread_command_list_triggers(
                        continue;
                }
 
+               if (lttng_trigger_needs_tracer_notifier(trigger_ht_element->trigger)) {
+                       ret = condition_on_event_update_error_count(
+                                       trigger_ht_element->trigger);
+                       assert(!ret);
+               }
+
                ret = lttng_triggers_add(local_triggers,
                                trigger_ht_element->trigger);
                if (ret < 0) {
@@ -2186,6 +2268,42 @@ end:
        return ret;
 }
 
+static
+int handle_notification_thread_command_get_trigger(
+               struct notification_thread_state *state,
+               const struct lttng_trigger *trigger,
+               struct lttng_trigger **real_trigger,
+               enum lttng_error_code *_cmd_result)
+{
+       int ret = -1;
+       struct cds_lfht_iter iter;
+       struct lttng_trigger_ht_element *trigger_ht_element;
+       enum lttng_error_code cmd_result = LTTNG_ERR_TRIGGER_NOT_FOUND;
+
+       rcu_read_lock();
+
+       cds_lfht_for_each_entry(state->triggers_ht, &iter,
+                       trigger_ht_element, node) {
+
+               if (lttng_trigger_is_equal(trigger, trigger_ht_element->trigger)) {
+                       /*
+                        * Take one reference on the return trigger.
+                        */
+                       *real_trigger = trigger_ht_element->trigger;
+                       lttng_trigger_get(*real_trigger);
+                       ret = 0;
+                       cmd_result = LTTNG_OK;
+                       goto end;
+               }
+       }
+
+
+end:
+       rcu_read_unlock();
+       *_cmd_result = cmd_result;
+       return ret;
+}
+
 static
 bool condition_is_supported(struct lttng_condition *condition)
 {
@@ -2217,12 +2335,12 @@ bool condition_is_supported(struct lttng_condition *condition)
                is_supported = kernel_supports_ring_buffer_snapshot_sample_positions() == 1;
                break;
        }
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
        {
                const struct lttng_event_rule *event_rule;
                enum lttng_domain_type domain;
                const enum lttng_condition_status status =
-                               lttng_condition_event_rule_get_rule(
+                               lttng_condition_on_event_get_rule(
                                                condition, &event_rule);
 
                assert(status == LTTNG_CONDITION_STATUS_OK);
@@ -2424,6 +2542,114 @@ enum lttng_error_code generate_trigger_name(
        return ret_code;
 }
 
+static inline
+void notif_thread_state_remove_trigger_ht_elem(
+               struct notification_thread_state *state,
+               struct lttng_trigger_ht_element *trigger_ht_element)
+{
+       assert(state);
+       assert(trigger_ht_element);
+
+       cds_lfht_del(state->triggers_ht, &trigger_ht_element->node);
+       cds_lfht_del(state->triggers_by_name_uid_ht, &trigger_ht_element->node_by_name_uid);
+}
+
+static
+enum lttng_error_code setup_tracer_notifier(
+               struct notification_thread_state *state,
+               struct lttng_trigger *trigger)
+{
+       enum lttng_error_code ret;
+       enum event_notifier_error_accounting_status error_accounting_status;
+       struct cds_lfht_node *node;
+       uint64_t error_counter_index = 0;
+       struct lttng_condition *condition = lttng_trigger_get_condition(trigger);
+       struct notification_trigger_tokens_ht_element *trigger_tokens_ht_element = NULL;
+
+       trigger_tokens_ht_element = zmalloc(sizeof(*trigger_tokens_ht_element));
+       if (!trigger_tokens_ht_element) {
+               ret = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /* Add trigger token to the trigger_tokens_ht. */
+       cds_lfht_node_init(&trigger_tokens_ht_element->node);
+       trigger_tokens_ht_element->token = LTTNG_OPTIONAL_GET(trigger->tracer_token);
+       trigger_tokens_ht_element->trigger = trigger;
+
+       node = cds_lfht_add_unique(state->trigger_tokens_ht,
+                       hash_key_u64(&trigger_tokens_ht_element->token, lttng_ht_seed),
+                       match_trigger_token,
+                       &trigger_tokens_ht_element->token,
+                       &trigger_tokens_ht_element->node);
+       if (node != &trigger_tokens_ht_element->node) {
+               ret = LTTNG_ERR_TRIGGER_EXISTS;
+               goto error_free_ht_element;
+       }
+
+       error_accounting_status = event_notifier_error_accounting_register_event_notifier(
+                       trigger, &error_counter_index);
+       if (error_accounting_status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+               if (error_accounting_status == EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE) {
+                       DBG("Trigger group error accounting counter full.");
+                       ret = LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING_FULL;
+               } else {
+                       ERR("Error registering trigger for error accounting");
+                       ret = LTTNG_ERR_EVENT_NOTIFIER_REGISTRATION;
+               }
+
+               goto error_remove_ht_element;
+       }
+
+       lttng_condition_on_event_set_error_counter_index(
+                       condition, error_counter_index);
+
+       ret = LTTNG_OK;
+       goto end;
+
+error_remove_ht_element:
+       cds_lfht_del(state->trigger_tokens_ht, &trigger_tokens_ht_element->node);
+error_free_ht_element:
+       free(trigger_tokens_ht_element);
+end:
+       return ret;
+}
+
+static
+void set_action_incr_value_tracer_token(struct notification_thread_state *state,
+               struct lttng_action *action)
+{
+       lttng_action_incr_value_set_tracer_token(action,
+                       state->trigger_id.next_tracer_token++);
+}
+
+static
+void set_all_action_incr_value_tracer_token(struct notification_thread_state *state,
+               struct lttng_action *action)
+{
+       unsigned int i, count;
+       enum lttng_action_status action_status;
+       enum lttng_action_type action_type;
+       action_type = lttng_action_get_type(action);
+
+       if (action_type != LTTNG_ACTION_TYPE_GROUP) {
+               if (action_type == LTTNG_ACTION_TYPE_INCREMENT_VALUE) {
+                       set_action_incr_value_tracer_token(state, action);
+               }
+       } else {
+               action_status = lttng_action_group_get_count(action, &count);
+               assert(action_status == LTTNG_ACTION_STATUS_OK);
+
+               for (i = 0; i < count; i++) {
+                       struct lttng_action *inner_action =
+                                       lttng_action_group_get_mutable_at_index(
+                                                       action, i);
+                       set_all_action_incr_value_tracer_token(state,
+                                       inner_action);
+               }
+       }
+}
+
 /*
  * FIXME A client's credentials are not checked when registering a trigger.
  *
@@ -2447,13 +2673,9 @@ int handle_notification_thread_command_register_trigger(
 {
        int ret = 0;
        struct lttng_condition *condition;
-       struct notification_client *client;
        struct notification_client_list *client_list = NULL;
        struct lttng_trigger_ht_element *trigger_ht_element = NULL;
-       struct notification_client_list_element *client_list_element;
-       struct notification_trigger_tokens_ht_element *trigger_tokens_ht_element = NULL;
        struct cds_lfht_node *node;
-       struct cds_lfht_iter iter;
        const char* trigger_name;
        bool free_trigger = true;
        struct lttng_evaluation *evaluation = NULL;
@@ -2469,6 +2691,8 @@ int handle_notification_thread_command_register_trigger(
        /* Set the trigger's tracer token. */
        lttng_trigger_set_tracer_token(trigger, trigger_tracer_token);
 
+       set_all_action_incr_value_tracer_token(state, lttng_trigger_get_action(trigger));
+
        if (lttng_trigger_get_name(trigger, &trigger_name) ==
                        LTTNG_TRIGGER_STATUS_UNSET) {
                const enum lttng_error_code ret_code = generate_trigger_name(
@@ -2530,95 +2754,72 @@ int handle_notification_thread_command_register_trigger(
                goto error_free_ht_element;
        }
 
-       if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
-               trigger_tokens_ht_element = zmalloc(sizeof(*trigger_tokens_ht_element));
-               if (!trigger_tokens_ht_element) {
-                       /* Fatal error. */
-                       ret = -1;
-                       cds_lfht_del(state->triggers_ht,
-                                       &trigger_ht_element->node);
-                       cds_lfht_del(state->triggers_by_name_uid_ht,
-                                       &trigger_ht_element->node_by_name_uid);
-                       goto error_free_ht_element;
-               }
+       /*
+        * Some triggers might need a tracer notifier depending on its
+        * condition and actions.
+        */
+       if (lttng_trigger_needs_tracer_notifier(trigger)) {
+               enum lttng_error_code error_code;
+
+               error_code = setup_tracer_notifier(state, trigger);
+               if (error_code != LTTNG_OK) {
+                       notif_thread_state_remove_trigger_ht_elem(state,
+                                       trigger_ht_element);
+                       if (error_code == LTTNG_ERR_NOMEM) {
+                               ret = -1;
+                       } else {
+                               *cmd_result = error_code;
+                               ret = 0;
+                       }
 
-               /* Add trigger token to the trigger_tokens_ht. */
-               cds_lfht_node_init(&trigger_tokens_ht_element->node);
-               trigger_tokens_ht_element->token =
-                               LTTNG_OPTIONAL_GET(trigger->tracer_token);
-               trigger_tokens_ht_element->trigger = trigger;
-
-               node = cds_lfht_add_unique(state->trigger_tokens_ht,
-                               hash_key_u64(&trigger_tokens_ht_element->token,
-                                               lttng_ht_seed),
-                               match_trigger_token,
-                               &trigger_tokens_ht_element->token,
-                               &trigger_tokens_ht_element->node);
-               if (node != &trigger_tokens_ht_element->node) {
-                       /* Internal corruption, fatal error. */
-                       ret = -1;
-                       *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
-                       cds_lfht_del(state->triggers_ht,
-                                       &trigger_ht_element->node);
-                       cds_lfht_del(state->triggers_by_name_uid_ht,
-                                       &trigger_ht_element->node_by_name_uid);
                        goto error_free_ht_element;
                }
        }
 
-       /*
-        * Ownership of the trigger and of its wrapper was transfered to
-        * the triggers_ht. Same for token ht element if necessary.
-        */
-       trigger_tokens_ht_element = NULL;
-       trigger_ht_element = NULL;
-       free_trigger = false;
-
        /*
         * The rest only applies to triggers that have a "notify" action.
         * It is not skipped as this is the only action type currently
         * supported.
         */
        if (is_trigger_action_notify(trigger)) {
-               client_list = notification_client_list_create(trigger);
+               /*
+                * Find or create the client list of this condition. It may
+                * already be present if another trigger is already registered
+                * with the same condition.
+                */
+               client_list = get_client_list_from_condition(state, condition);
                if (!client_list) {
-                       ret = -1;
-                       goto error_free_ht_element;
-               }
-
-               /* Build a list of clients to which this new trigger applies. */
-               cds_lfht_for_each_entry (state->client_socket_ht, &iter, client,
-                               client_socket_ht_node) {
-                       if (!trigger_applies_to_client(trigger, client)) {
-                               continue;
-                       }
-
-                       client_list_element =
-                                       zmalloc(sizeof(*client_list_element));
-                       if (!client_list_element) {
-                               ret = -1;
-                               goto error_put_client_list;
+                       /*
+                        * No client list for this condition yet. We create new
+                        * one and build it up.
+                        */
+                       client_list = notification_client_list_create(state, condition);
+                       if (!client_list) {
+                               ERR("Error creating notification client list for trigger %s", trigger->name);
+                               goto error_free_ht_element;
                        }
-
-                       CDS_INIT_LIST_HEAD(&client_list_element->node);
-                       client_list_element->client = client;
-                       cds_list_add(&client_list_element->node,
-                                       &client_list->list);
                }
 
-               /*
-                * Client list ownership transferred to the
-                * notification_trigger_clients_ht.
-                */
-               publish_notification_client_list(state, client_list);
+               CDS_INIT_LIST_HEAD(&trigger_ht_element->client_list_trigger_node);
+
+               pthread_mutex_lock(&client_list->lock);
+               cds_list_add(&trigger_ht_element->client_list_trigger_node, &client_list->triggers_list);
+               pthread_mutex_unlock(&client_list->lock);
        }
 
+       /*
+        * Ownership of the trigger and of its wrapper was transfered to
+        * the triggers_ht. Same for token ht element if necessary.
+        */
+       trigger_ht_element = NULL;
+       free_trigger = false;
+
        switch (get_condition_binding_object(condition)) {
        case LTTNG_OBJECT_TYPE_SESSION:
                /* Add the trigger to the list if it matches a known session. */
                ret = bind_trigger_to_matching_session(trigger, state);
                if (ret) {
-                       goto error_put_client_list;
+                       goto error_free_ht_element;
                }
                break;
        case LTTNG_OBJECT_TYPE_CHANNEL:
@@ -2628,7 +2829,7 @@ int handle_notification_thread_command_register_trigger(
                 */
                ret = bind_trigger_to_matching_channels(trigger, state);
                if (ret) {
-                       goto error_put_client_list;
+                       goto error_free_ht_element;
                }
                break;
        case LTTNG_OBJECT_TYPE_NONE:
@@ -2636,7 +2837,7 @@ int handle_notification_thread_command_register_trigger(
        default:
                ERR("Unknown object type on which to bind a newly registered trigger was encountered");
                ret = -1;
-               goto error_put_client_list;
+               goto error_free_ht_element;
        }
 
        /*
@@ -2694,7 +2895,7 @@ int handle_notification_thread_command_register_trigger(
 
        if (ret) {
                /* Fatal error. */
-               goto error_put_client_list;
+               goto error_free_ht_element;
        }
 
        DBG("Newly registered trigger's condition evaluated to %s",
@@ -2702,7 +2903,7 @@ int handle_notification_thread_command_register_trigger(
        if (!evaluation) {
                /* Evaluation yielded nothing. Normal exit. */
                ret = 0;
-               goto end;
+               goto success;
        }
 
        /*
@@ -2723,7 +2924,7 @@ int handle_notification_thread_command_register_trigger(
                 */
                ERR("Fatal error occurred while enqueuing action associated to newly registered trigger");
                ret = -1;
-               goto error_put_client_list;
+               goto error_free_ht_element;
        case ACTION_EXECUTOR_STATUS_OVERFLOW:
                /*
                 * TODO Add trigger identification (name/id) when
@@ -2733,18 +2934,16 @@ int handle_notification_thread_command_register_trigger(
                 */
                WARN("No space left when enqueuing action associated to newly registered trigger");
                ret = 0;
-               goto end;
+               goto success;
        default:
                abort();
        }
 
-end:
+success:
        *cmd_result = LTTNG_OK;
        DBG("Registered trigger: name = `%s`, tracer token = %" PRIu64,
                        trigger_name, trigger_tracer_token);
-
-error_put_client_list:
-       notification_client_list_put(client_list);
+       goto end;
 
 error_free_ht_element:
        if (trigger_ht_element) {
@@ -2752,12 +2951,11 @@ error_free_ht_element:
                call_rcu(&trigger_ht_element->rcu_node,
                                free_lttng_trigger_ht_element_rcu);
        }
-
-       free(trigger_tokens_ht_element);
 error:
        if (free_trigger) {
                lttng_trigger_destroy(trigger);
        }
+end:
        rcu_read_unlock();
        return ret;
 }
@@ -2776,6 +2974,36 @@ void free_notification_trigger_tokens_ht_element_rcu(struct rcu_head *node)
                        rcu_node));
 }
 
+static
+void teardown_tracer_notifier(struct notification_thread_state *state,
+               const struct lttng_trigger *trigger)
+{
+       struct cds_lfht_iter iter;
+       struct notification_trigger_tokens_ht_element *trigger_tokens_ht_element;
+
+       cds_lfht_for_each_entry(state->trigger_tokens_ht, &iter,
+                       trigger_tokens_ht_element, node) {
+
+               if (!lttng_trigger_is_equal(trigger,
+                                       trigger_tokens_ht_element->trigger)) {
+                       continue;
+               }
+
+               event_notifier_error_accounting_unregister_event_notifier(
+                               trigger_tokens_ht_element->trigger);
+
+               /* TODO talk to all app and remove it */
+               DBG("[notification-thread] Removed trigger from tokens_ht");
+               cds_lfht_del(state->trigger_tokens_ht,
+                               &trigger_tokens_ht_element->node);
+
+               call_rcu(&trigger_tokens_ht_element->rcu_node,
+                               free_notification_trigger_tokens_ht_element_rcu);
+
+               break;
+       }
+}
+
 static
 int handle_notification_thread_command_unregister_trigger(
                struct notification_thread_state *state,
@@ -2824,28 +3052,13 @@ int handle_notification_thread_command_unregister_trigger(
                }
        }
 
-       if (lttng_condition_get_type(condition) ==
-                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
-               struct notification_trigger_tokens_ht_element
-                               *trigger_tokens_ht_element;
-
-               cds_lfht_for_each_entry (state->trigger_tokens_ht, &iter,
-                               trigger_tokens_ht_element, node) {
-                       if (!lttng_trigger_is_equal(trigger,
-                                           trigger_tokens_ht_element->trigger)) {
-                               continue;
-                       }
-
-                       DBG("[notification-thread] Removed trigger from tokens_ht");
-                       cds_lfht_del(state->trigger_tokens_ht,
-                                       &trigger_tokens_ht_element->node);
-                       call_rcu(&trigger_tokens_ht_element->rcu_node,
-                                       free_notification_trigger_tokens_ht_element_rcu);
-
-                       break;
-               }
+       if (lttng_trigger_needs_tracer_notifier(trigger)) {
+               teardown_tracer_notifier(state, trigger);
        }
 
+       trigger_ht_element = caa_container_of(triggers_ht_node,
+                       struct lttng_trigger_ht_element, node);
+
        if (is_trigger_action_notify(trigger)) {
                /*
                 * Remove and release the client list from
@@ -2854,6 +3067,10 @@ int handle_notification_thread_command_unregister_trigger(
                client_list = get_client_list_from_condition(state, condition);
                assert(client_list);
 
+               pthread_mutex_lock(&client_list->lock);
+               cds_list_del(&trigger_ht_element->client_list_trigger_node);
+               pthread_mutex_unlock(&client_list->lock);
+
                /* Put new reference and the hashtable's reference. */
                notification_client_list_put(client_list);
                notification_client_list_put(client_list);
@@ -2861,10 +3078,7 @@ int handle_notification_thread_command_unregister_trigger(
        }
 
        /* Remove trigger from triggers_ht. */
-       trigger_ht_element = caa_container_of(triggers_ht_node,
-                       struct lttng_trigger_ht_element, node);
-       cds_lfht_del(state->triggers_by_name_uid_ht, &trigger_ht_element->node_by_name_uid);
-       cds_lfht_del(state->triggers_ht, triggers_ht_node);
+       notif_thread_state_remove_trigger_ht_elem(state, trigger_ht_element);
 
        /* Release the ownership of the trigger. */
        lttng_trigger_destroy(trigger_ht_element->trigger);
@@ -2974,6 +3188,19 @@ int handle_notification_thread_command(
                cmd->reply_code = LTTNG_OK;
                ret = 1;
                goto end;
+       case NOTIFICATION_COMMAND_TYPE_GET_TRIGGER:
+       {
+               struct lttng_trigger *trigger = NULL;
+
+               ret = handle_notification_thread_command_get_trigger(
+                               state,
+                               cmd->parameters.get_trigger.trigger,
+                               &trigger,
+                               &cmd->reply_code);
+               cmd->reply.get_trigger.trigger = trigger;
+               ret = 0;
+               break;
+       }
        case NOTIFICATION_COMMAND_TYPE_CLIENT_COMMUNICATION_UPDATE:
        {
                const enum client_transmission_status client_status =
@@ -4153,7 +4380,7 @@ int notification_client_list_send_evaluation(
 
        pthread_mutex_lock(&client_list->lock);
        cds_list_for_each_entry_safe(client_list_element, tmp,
-                       &client_list->list, node) {
+                       &client_list->clients_list, node) {
                enum client_transmission_status transmission_status;
                struct notification_client *client =
                                client_list_element->client;
@@ -4244,6 +4471,8 @@ struct lttng_event_notifier_notification *recv_one_event_notifier_notification(
        int ret;
        uint64_t token;
        struct lttng_event_notifier_notification *notification = NULL;
+       char *capture_buffer = NULL;
+       size_t capture_buffer_size;
        void *reception_buffer;
        size_t reception_size;
 
@@ -4280,17 +4509,55 @@ struct lttng_event_notifier_notification *recv_one_event_notifier_notification(
        switch(domain) {
        case LTTNG_DOMAIN_UST:
                token = ust_notification.token;
+               capture_buffer_size = ust_notification.capture_buf_size;
                break;
        case LTTNG_DOMAIN_KERNEL:
                token = kernel_notification.token;
+               capture_buffer_size = kernel_notification.capture_buf_size;
                break;
        default:
                abort();
        }
 
-       notification = lttng_event_notifier_notification_create(
-                       token, domain);
+       if (capture_buffer_size == 0) {
+               capture_buffer = NULL;
+               goto skip_capture;
+       }
+
+       if (capture_buffer_size > MAX_CAPTURE_SIZE) {
+               ERR("[notification-thread] Event notifier has a capture payload size which exceeds the maximum allowed size: capture_payload_size = %zu bytes, max allowed size = %d bytes",
+                               capture_buffer_size, MAX_CAPTURE_SIZE);
+               goto end;
+       }
+
+       capture_buffer = zmalloc(capture_buffer_size);
+       if (!capture_buffer) {
+               ERR("[notification-thread] Failed to allocate capture buffer");
+               goto end;
+       }
+
+       /* Fetch additional payload (capture). */
+       ret = lttng_read(notification_pipe_read_fd, capture_buffer, capture_buffer_size);
+       if (ret != capture_buffer_size) {
+               ERR("[notification-thread] Failed to read from event source pipe (fd = %i)",
+                               notification_pipe_read_fd);
+               goto end;
+       }
+
+skip_capture:
+       notification = lttng_event_notifier_notification_create(token, domain,
+                       capture_buffer, capture_buffer_size);
+       if (notification == NULL) {
+               goto end;
+       }
+
+       /*
+        * Ownership transfered to the lttng_event_notifier_notification object.
+        */
+       capture_buffer = NULL;
+
 end:
+       free(capture_buffer);
        return notification;
 }
 
@@ -4307,6 +4574,7 @@ int dispatch_one_event_notifier_notification(struct notification_thread_state *s
        struct notification_client_list *client_list = NULL;
        const char *trigger_name;
        int ret;
+       unsigned int capture_count = 0;
 
        /* Find triggers associated with this token. */
        rcu_read_lock();
@@ -4339,14 +4607,34 @@ int dispatch_one_event_notifier_notification(struct notification_thread_state *s
        trigger_status = lttng_trigger_get_name(element->trigger, &trigger_name);
        assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
 
+       if (lttng_condition_on_event_get_capture_descriptor_count(
+                           lttng_trigger_get_const_condition(element->trigger),
+                           &capture_count) != LTTNG_CONDITION_STATUS_OK) {
+               ERR("Failed to get capture count");
+               ret = -1;
+               goto end;
+       }
+
+       if (!notification->capture_buffer && capture_count != 0) {
+               ERR("Expected capture but capture buffer is null");
+               ret = -1;
+               goto end;
+       }
+
        evaluation = lttng_evaluation_event_rule_create(
-                       trigger_name);
+                       container_of(lttng_trigger_get_const_condition(
+                                                    element->trigger),
+                                       struct lttng_condition_on_event,
+                                       parent),
+                       trigger_name,
+                       notification->capture_buffer,
+                       notification->capture_buf_size, false);
+
        if (evaluation == NULL) {
                ERR("[notification-thread] Failed to create event rule hit evaluation while creating and enqueuing action executor job");
                ret = -1;
                goto end_unlock;
        }
-
        client_list = get_client_list_from_condition(state,
                        lttng_trigger_get_const_condition(element->trigger));
        executor_status = action_executor_enqueue(state->executor,
@@ -4374,7 +4662,7 @@ int dispatch_one_event_notifier_notification(struct notification_thread_state *s
                /* Warn clients that a notification (or more) was dropped. */
                pthread_mutex_lock(&client_list->lock);
                cds_list_for_each_entry_safe(client_list_element, tmp,
-                               &client_list->list, node) {
+                               &client_list->clients_list, node) {
                        enum client_transmission_status transmission_status;
                        struct notification_client *client =
                                        client_list_element->client;
@@ -4404,6 +4692,7 @@ next_client:
                pthread_mutex_unlock(&client_list->lock);
                break;
        }
+       case ACTION_EXECUTOR_STATUS_INVALID:
        case ACTION_EXECUTOR_STATUS_ERROR:
                /* Fatal error, shut down everything. */
                ERR("Fatal error encoutered while enqueuing action to the action executor");
@@ -4417,6 +4706,7 @@ next_client:
 end_unlock:
        notification_client_list_put(client_list);
        rcu_read_unlock();
+end:
        return ret;
 }
 
@@ -4425,14 +4715,14 @@ int handle_one_event_notifier_notification(
                struct notification_thread_state *state,
                int pipe, enum lttng_domain_type domain)
 {
-       int ret;
+       int ret = 0;
        struct lttng_event_notifier_notification *notification = NULL;
 
        notification = recv_one_event_notifier_notification(pipe, domain);
        if (notification == NULL) {
+               /* Reception failed, don't consider it fatal. */
                ERR("[notification-thread] Error receiving an event notifier notification from tracer: fd = %i, domain = %s",
                                pipe, lttng_domain_type_str(domain));
-               ret = -1;
                goto end;
        }
 
index 0403527dca1f4f5b67d0f25cbe0cb91efee27eda..38d968a4dbd685996ff0d1da92c5a383bccf1125 100644 (file)
@@ -82,6 +82,8 @@ struct channel_info {
 struct lttng_event_notifier_notification {
        uint64_t tracer_token;
        enum lttng_domain_type type;
+       size_t capture_buf_size;
+       char *capture_buffer;
 };
 
 struct notification_client_list_element {
@@ -111,8 +113,9 @@ struct notification_client_list_element {
 struct notification_client_list {
        pthread_mutex_t lock;
        struct urcu_ref ref;
-       const struct lttng_trigger *trigger;
-       struct cds_list_head list;
+       struct lttng_condition *condition;
+       struct cds_list_head triggers_list;
+       struct cds_list_head clients_list;
        /* Weak reference to container. */
        struct cds_lfht *notification_trigger_clients_ht;
        struct cds_lfht_node notification_trigger_clients_ht_node;
@@ -248,10 +251,15 @@ int notification_thread_client_communication_update(
                notification_client_id id,
                enum client_transmission_status transmission_status);
 
+/*
+ * Takes ownership of the payload if present.
+ */
 LTTNG_HIDDEN
 struct lttng_event_notifier_notification *lttng_event_notifier_notification_create(
                uint64_t tracer_token,
-               enum lttng_domain_type domain);
+               enum lttng_domain_type domain,
+               char *payload,
+               size_t payload_size);
 
 LTTNG_HIDDEN
 void lttng_event_notifier_notification_destroy(
index dd1dc3e8fe50753cfe7ac10978a6f6898df25dd3..b91dc5798df67140a43958f5cf87e128bd60acc7 100644 (file)
@@ -27,6 +27,7 @@
 #include "lttng-sessiond.h"
 #include "health-sessiond.h"
 #include "thread.h"
+#include "testpoint.h"
 
 #include "kernel.h"
 #include <common/kernel-ctl/kernel-ctl.h>
@@ -35,6 +36,8 @@
 #include <urcu/list.h>
 #include <urcu/rculfhash.h>
 
+
+int notifier_consumption_paused;
 /*
  * Destroy the thread data previously created by the init function.
  */
@@ -482,6 +485,7 @@ int init_thread_state(struct notification_thread_handle *handle,
        if (!state->channels_ht) {
                goto error;
        }
+
        state->sessions_ht = cds_lfht_new(DEFAULT_HT_SIZE,
                        1, 0, CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
        if (!state->sessions_ht) {
@@ -574,6 +578,17 @@ static int handle_event_notification_pipe(int event_source_fd,
                goto end;
        }
 
+       if (testpoint(sessiond_handle_notifier_event_pipe)) {
+               ret = 0;
+               goto end;
+       }
+
+       if (caa_unlikely(notifier_consumption_paused)) {
+               DBG("Event notifier notification consumption paused, sleeping...");
+               sleep(1);
+               goto end;
+       }
+
        ret = handle_notification_thread_event_notification(
                        state, event_source_fd, domain);
        if (ret) {
@@ -582,6 +597,7 @@ static int handle_event_notification_pipe(int event_source_fd,
                ret = -1;
                goto end;
        }
+
 end:
        return ret;
 }
@@ -640,6 +656,10 @@ void *thread_notification(void *data)
                goto end;
        }
 
+       if (testpoint(sessiond_thread_notification)) {
+               goto end;
+       }
+
        while (true) {
                int fd_count, i;
 
index 6381c117950f767ef705d2ccbb66a218d3c1701d..ac1583dc24eb8f3610dfcb481d8cfb19b726d962 100644 (file)
@@ -12,6 +12,7 @@
 #include <urcu.h>
 #include <common/futex.h>
 #include <common/macros.h>
+#include <common/shm.h>
 #include <common/utils.h>
 #include <sys/stat.h>
 
@@ -20,7 +21,6 @@
 #include "testpoint.h"
 #include "health-sessiond.h"
 #include "fd-limit.h"
-#include "shm.h"
 #include "utils.h"
 #include "thread.h"
 
index 6ca756365de18f8177309c52e2d93301d6db651e..da6d948c4283c313437714362a446ac69b7166fc 100644 (file)
@@ -131,6 +131,87 @@ end:
        return ret;
 }
 
+static
+int save_map_attributes(struct config_writer *writer,
+       struct lttng_map *map)
+{
+       int ret;
+       unsigned int i;
+
+       ret = config_writer_write_element_unsigned_int(writer,
+               config_element_bitness,
+               lttng_map_get_bitness(map)==LTTNG_MAP_BITNESS_32BITS ? 32: 64);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       assert( lttng_map_get_boundary_policy(map) == LTTNG_MAP_BOUNDARY_POLICY_OVERFLOW);
+       ret = config_writer_write_element_string(writer,
+               config_element_boundary_policy, config_boundary_policy_overflow);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       ret = config_writer_write_element_bool(writer,
+                       config_element_coalesce_hits,
+                       lttng_map_get_coalesce_hits(map));
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       ret = config_writer_open_element(writer,
+                       config_element_dimensions);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+       for (i = 0; i < lttng_map_get_dimension_count(map); i++) {
+               enum lttng_map_status map_status;
+               uint64_t dim_len;
+
+               ret = config_writer_open_element(writer,
+                               config_element_dimension);
+               if (ret) {
+                       ret = LTTNG_ERR_SAVE_IO_FAIL;
+                       goto end;
+               }
+
+               map_status = lttng_map_get_dimension_length(map, i, &dim_len);
+               if (map_status != LTTNG_MAP_STATUS_OK) {
+                       ret = LTTNG_ERR_SAVE_IO_FAIL;
+                       goto end;
+               }
+
+               ret = config_writer_write_element_unsigned_int(writer,
+                       config_element_dimension_size, dim_len);
+               if (ret) {
+                       ret = LTTNG_ERR_SAVE_IO_FAIL;
+                       goto end;
+               }
+
+               /* dimension */
+               ret = config_writer_close_element(writer);
+               if (ret) {
+                       ret = LTTNG_ERR_SAVE_IO_FAIL;
+                       goto end;
+               }
+       }
+
+       /* dimensions */
+       ret = config_writer_close_element(writer);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+
 /* Return LTTNG_OK on success else a LTTNG_ERR* code. */
 static
 int save_ust_channel_attributes(struct config_writer *writer,
@@ -1642,6 +1723,61 @@ end:
        return ret;
 }
 
+/* Return LTTNG_OK on success else a LTTNG_ERR* code. */
+static
+int save_kernel_map(struct config_writer *writer,
+       struct ltt_kernel_map *kmap)
+{
+       int ret;
+       const char *map_name = NULL;
+       enum lttng_map_status map_status;
+
+       assert(writer);
+       assert(kmap);
+
+       ret = config_writer_open_element(writer, config_element_map);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       map_status = lttng_map_get_name(kmap->map, &map_name);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       ret = config_writer_write_element_string(writer, config_element_name,
+               map_name);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       ret = config_writer_write_element_bool(writer, config_element_enabled,
+               lttng_map_get_is_enabled(kmap->map));
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       ret = save_map_attributes(writer, kmap->map);
+       if (ret) {
+               goto end;
+       }
+
+       /* map */
+       ret = config_writer_close_element(writer);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       ret = LTTNG_OK;
+end:
+       return ret;
+}
+
 /* Return LTTNG_OK on success else a LTTNG_ERR* code. */
 static
 int save_ust_channel(struct config_writer *writer,
@@ -1745,6 +1881,56 @@ end:
        return ret;
 }
 
+/* Return LTTNG_OK on success else a LTTNG_ERR* code. */
+static
+int save_ust_map(struct config_writer *writer,
+       struct ltt_ust_map *ust_map,
+       struct ltt_ust_session *session)
+{
+       int ret;
+
+       assert(writer);
+       assert(ust_map);
+       assert(session);
+
+       ret = config_writer_open_element(writer, config_element_map);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       ret = config_writer_write_element_string(writer, config_element_name,
+               ust_map->name);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       ret = config_writer_write_element_bool(writer, config_element_enabled,
+               ust_map->enabled);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       ret = save_map_attributes(writer, ust_map->map);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       /* /map */
+       ret = config_writer_close_element(writer);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
+       ret = LTTNG_OK;
+end:
+       return ret;
+}
+
 /* Return LTTNG_OK on success else a LTTNG_ERR* code. */
 static
 int save_kernel_session(struct config_writer *writer,
@@ -1752,6 +1938,7 @@ int save_kernel_session(struct config_writer *writer,
 {
        int ret;
        struct ltt_kernel_channel *kchan;
+       struct ltt_kernel_map *kmap;
 
        assert(writer);
        assert(session);
@@ -1785,6 +1972,14 @@ int save_kernel_session(struct config_writer *writer,
                }
        }
 
+       cds_list_for_each_entry(kmap, &session->kernel_session->map_list.head,
+                       list) {
+               ret = save_kernel_map(writer, kmap);
+               if (ret != LTTNG_OK) {
+                       goto end;
+               }
+       }
+
        /* /channels */
        ret = config_writer_close_element(writer);
        if (ret) {
@@ -2085,6 +2280,7 @@ int save_ust_domain(struct config_writer *writer,
 {
        int ret;
        struct ltt_ust_channel *ust_chan;
+       struct ltt_ust_map *ust_map;
        const char *buffer_type_string;
        struct lttng_ht_node_str *node;
        struct lttng_ht_iter iter;
@@ -2155,6 +2351,32 @@ int save_ust_domain(struct config_writer *writer,
                goto end;
        }
 
+       ret = config_writer_open_element(writer, config_element_maps);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+       rcu_read_lock();
+       cds_lfht_for_each_entry(session->ust_session->domain_global.maps->ht,
+                       &iter.iter, node, node) {
+               ust_map = caa_container_of(node, struct ltt_ust_map, node);
+               if (domain == LTTNG_DOMAIN_UST) {
+                       ret = save_ust_map(writer, ust_map, session->ust_session);
+                       if (ret != LTTNG_OK) {
+                               rcu_read_unlock();
+                               goto end;
+                       }
+               }
+       }
+       rcu_read_unlock();
+
+       /* /maps */
+       ret = config_writer_close_element(writer);
+       if (ret) {
+               ret = LTTNG_ERR_SAVE_IO_FAIL;
+               goto end;
+       }
+
        if (domain == LTTNG_DOMAIN_UST) {
                ret = config_writer_open_element(
                                writer, config_element_process_attr_trackers);
index 5ff20ad412eea13c1cdde2e0aa4c6e9202d37399..3c6c34792d9e733ebfc9121ae83602a5757b956d 100644 (file)
@@ -210,6 +210,7 @@ void session_unlock(struct ltt_session *session);
  * are being transmitted to the various applications.
  */
 void session_lock_list(void);
+
 int session_trylock_list(void);
 void session_unlock_list(void);
 
index c7a91830768389b82972da51ead472390657d98d..fbd301e97168dc82b069178046a7555582bdfe1f 100644 (file)
@@ -24,6 +24,7 @@ struct sessiond_config sessiond_config_build_defaults = {
        .verbose_consumer =                     0,
 
        .agent_tcp_port =                       { .begin = DEFAULT_AGENT_TCP_PORT_RANGE_BEGIN, .end = DEFAULT_AGENT_TCP_PORT_RANGE_END },
+       .event_notifier_error_counter_bucket =  4096,
        .app_socket_timeout =                   DEFAULT_APP_SOCKET_RW_TIMEOUT,
 
        .no_kernel =                            false,
index 9ce036e70a8e56e2fbd2f25ad4db4ee89e101f2e..9369f4cc037de9265bed98f6e94eb9643230338e 100644 (file)
@@ -29,6 +29,8 @@ struct sessiond_config {
        int verbose_consumer;
        /* Agent TCP port range for registration. Used by the agent thread. */
        struct config_int_range agent_tcp_port;
+
+       int event_notifier_error_counter_bucket;
        /* Socket timeout for receiving and sending (in seconds). */
        int app_socket_timeout;
 
diff --git a/src/bin/lttng-sessiond/shm.c b/src/bin/lttng-sessiond/shm.c
deleted file mode 100644 (file)
index 8b77442..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <urcu.h>
-
-#include <common/error.h>
-
-#include "shm.h"
-
-/*
- * Using fork to set umask in the child process (not multi-thread safe). We
- * deal with the shm_open vs ftruncate race (happening when the sessiond owns
- * the shm and does not let everybody modify it, to ensure safety against
- * shm_unlink) by simply letting the mmap fail and retrying after a few
- * seconds. For global shm, everybody has rw access to it until the sessiond
- * starts.
- */
-static int get_wait_shm(char *shm_path, size_t mmap_size, int global)
-{
-       int wait_shm_fd, ret;
-       mode_t mode;
-
-       assert(shm_path);
-
-       /* Default permissions */
-       mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
-
-       /*
-        * Change owner of the shm path.
-        */
-       if (global) {
-               /*
-                * If global session daemon, any application can
-                * register. Make it initially writeable so applications
-                * registering concurrently can do ftruncate() by
-                * themselves.
-                */
-               mode |= S_IROTH | S_IWOTH;
-       }
-
-       /*
-        * We're alone in a child process, so we can modify the process-wide
-        * umask.
-        */
-       umask(~mode);
-
-       /*
-        * Try creating shm (or get rw access). We don't do an exclusive open,
-        * because we allow other processes to create+ftruncate it concurrently.
-        *
-        * A sysctl, fs.protected_regular may prevent the session daemon from
-        * opening a previously created shm when the O_CREAT flag is provided.
-        * Systemd enables this ABI-breaking change by default since v241.
-        *
-        * First, attempt to use the create-or-open semantic that is
-        * desired here. If this fails with EACCES, work around this broken
-        * behaviour and attempt to open the shm without the O_CREAT flag.
-        *
-        * The two attempts are made in this order since applications are
-        * expected to race with the session daemon to create this shm.
-        * Attempting an shm_open() without the O_CREAT flag first could fail
-        * because the file doesn't exist. It could then be created by an
-        * application, which would cause a second try with the O_CREAT flag to
-        * fail with EACCES.
-        *
-        * Note that this introduces a new failure mode where a user could
-        * launch an application (creating the shm) and unlink the shm while
-        * the session daemon is launching, causing the second attempt
-        * to fail. This is not recovered-from as unlinking the shm will
-        * prevent userspace tracing from succeeding anyhow: the sessiond would
-        * use a now-unlinked shm, while the next application would create
-        * a new named shm.
-        */
-       wait_shm_fd = shm_open(shm_path, O_RDWR | O_CREAT, mode);
-       if (wait_shm_fd < 0) {
-               if (errno == EACCES) {
-                       /* Work around sysctl fs.protected_regular. */
-                       DBG("shm_open of %s returned EACCES, this may be caused "
-                                       "by the fs.protected_regular sysctl. "
-                                       "Attempting to open the shm without "
-                                       "creating it.", shm_path);
-                       wait_shm_fd = shm_open(shm_path, O_RDWR, mode);
-               }
-               if (wait_shm_fd < 0) {
-                       PERROR("Failed to open wait shm at %s", shm_path);
-                       goto error;
-               }
-       }
-
-       ret = ftruncate(wait_shm_fd, mmap_size);
-       if (ret < 0) {
-               PERROR("ftruncate wait shm");
-               exit(EXIT_FAILURE);
-       }
-
-       if (global) {
-               ret = fchown(wait_shm_fd, 0, 0);
-               if (ret < 0) {
-                       PERROR("fchown");
-                       exit(EXIT_FAILURE);
-               }
-               /*
-                * If global session daemon, any application can
-                * register so the shm needs to be set in read-only mode
-                * for others.
-                */
-               mode &= ~S_IWOTH;
-               ret = fchmod(wait_shm_fd, mode);
-               if (ret < 0) {
-                       PERROR("fchmod");
-                       exit(EXIT_FAILURE);
-               }
-       } else {
-               ret = fchown(wait_shm_fd, getuid(), getgid());
-               if (ret < 0) {
-                       PERROR("fchown");
-                       exit(EXIT_FAILURE);
-               }
-       }
-
-       DBG("Got the wait shm fd %d", wait_shm_fd);
-
-       return wait_shm_fd;
-
-error:
-       DBG("Failing to get the wait shm fd");
-
-       return -1;
-}
-
-/*
- * Return the wait shm mmap for UST application notification. The global
- * variable is used to indicate if the the session daemon is global
- * (root:tracing) or running with an unprivileged user.
- *
- * This returned value is used by futex_wait_update() in futex.c to WAKE all
- * waiters which are UST application waiting for a session daemon.
- */
-char *shm_ust_get_mmap(char *shm_path, int global)
-{
-       size_t mmap_size;
-       int wait_shm_fd, ret;
-       char *wait_shm_mmap;
-       long sys_page_size;
-
-       assert(shm_path);
-
-       sys_page_size = sysconf(_SC_PAGE_SIZE);
-       if (sys_page_size < 0) {
-               PERROR("sysconf PAGE_SIZE");
-               goto error;
-       }
-       mmap_size = sys_page_size;
-
-       wait_shm_fd = get_wait_shm(shm_path, mmap_size, global);
-       if (wait_shm_fd < 0) {
-               goto error;
-       }
-
-       wait_shm_mmap = mmap(NULL, mmap_size, PROT_WRITE | PROT_READ,
-                       MAP_SHARED, wait_shm_fd, 0);
-
-       /* close shm fd immediately after taking the mmap reference */
-       ret = close(wait_shm_fd);
-       if (ret) {
-               PERROR("Error closing fd");
-       }
-
-       if (wait_shm_mmap == MAP_FAILED) {
-               DBG("mmap error (can be caused by race with ust).");
-               goto error;
-       }
-
-       return wait_shm_mmap;
-
-error:
-       return NULL;
-}
diff --git a/src/bin/lttng-sessiond/shm.h b/src/bin/lttng-sessiond/shm.h
deleted file mode 100644 (file)
index 94d2b72..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#ifndef _LTT_SHM_H
-#define _LTT_SHM_H
-
-char *shm_ust_get_mmap(char *shm_path, int global);
-
-#endif /* _LTT_SHM_H */
index 8524e1fd3186d54088840fb22d770527c1f627a8..2ddd662834b2cb6ce7e604d0c9d5f79436e252b1 100644 (file)
@@ -22,5 +22,7 @@ TESTPOINT_DECL(sessiond_thread_manage_consumer);
 TESTPOINT_DECL(sessiond_thread_ht_cleanup);
 TESTPOINT_DECL(sessiond_thread_app_manage_notify);
 TESTPOINT_DECL(sessiond_thread_app_reg_dispatch);
+TESTPOINT_DECL(sessiond_thread_notification);
+TESTPOINT_DECL(sessiond_handle_notifier_event_pipe);
 
 #endif /* SESSIOND_TESTPOINT_H */
index 2623b2971a5273a0e84dd0a711243c99268e2a80..b550ccab5e12ba8214aea4fe4182c8e5d5092d3e 100644 (file)
 
 #include <lttng/event.h>
 #include <lttng/lttng-error.h>
+#include <lttng/kernel-function.h>
 #include <lttng/kernel-probe.h>
 #include <lttng/userspace-probe.h>
 #include <lttng/userspace-probe-internal.h>
 #include <lttng/event-rule/event-rule.h>
 #include <lttng/event-rule/event-rule-internal.h>
-#include <lttng/event-rule/kprobe.h>
-#include <lttng/event-rule/kprobe-internal.h>
+#include <lttng/event-rule/kernel-function.h>
+#include <lttng/event-rule/kernel-function-internal.h>
+#include <lttng/event-rule/kernel-probe.h>
+#include <lttng/event-rule/kernel-probe-internal.h>
 #include <lttng/event-rule/syscall.h>
 #include <lttng/event-rule/syscall-internal.h>
 #include <lttng/event-rule/tracepoint.h>
 #include <lttng/event-rule/tracepoint-internal.h>
-#include <lttng/event-rule/uprobe-internal.h>
+#include <lttng/event-rule/userspace-probe-internal.h>
+#include <lttng/map/map.h>
+#include <lttng/map-key-internal.h>
 #include <common/common.h>
 #include <common/defaults.h>
 #include <common/trace-chunk.h>
 #include "lttng-sessiond.h"
 #include "notification-thread-commands.h"
 
+/* Next available map key. Access under next_map_key_lock. */
+static uint64_t _next_map_key;
+static pthread_mutex_t next_map_key_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Return the incremented value of next_map_key.
+ */
+static uint64_t get_next_map_key(void)
+{
+       uint64_t ret;
+
+       pthread_mutex_lock(&next_map_key_lock);
+       ret = ++_next_map_key;
+       pthread_mutex_unlock(&next_map_key_lock);
+       return ret;
+}
+
 /*
  * Find the channel name for the given kernel session.
  */
@@ -66,10 +88,40 @@ struct ltt_kernel_channel *trace_kernel_get_channel_by_name(
 }
 
 /*
- * Find the event for the given channel.
+ * Find the map name for the given kernel session.
+ */
+struct ltt_kernel_map *trace_kernel_get_map_by_name(
+               const char *name, struct ltt_kernel_session *session)
+{
+       struct ltt_kernel_map *map;
+
+       assert(session);
+       assert(name);
+
+       DBG("Trying to find map %s", name);
+
+       cds_list_for_each_entry(map, &session->map_list.head, list) {
+               enum lttng_map_status status;
+               const char *cur_map_name;
+
+               status = lttng_map_get_name(map->map, &cur_map_name);
+               assert(status == LTTNG_MAP_STATUS_OK);
+
+               if (strcmp(name, cur_map_name) == 0) {
+                       DBG("Found map by name %s", name);
+                       return map;
+               }
+       }
+
+       return NULL;
+}
+
+/*
+ * Find the event for the given channel or map.
  */
 struct ltt_kernel_event *trace_kernel_find_event(
-               char *name, struct ltt_kernel_channel *channel,
+               struct ltt_kernel_event_list *events_list,
+               uint64_t tracer_token, char *name,
                enum lttng_event_type type,
                struct lttng_bytecode *filter)
 {
@@ -77,9 +129,11 @@ struct ltt_kernel_event *trace_kernel_find_event(
        int found = 0;
 
        assert(name);
-       assert(channel);
 
-       cds_list_for_each_entry(ev, &channel->events_list.head, list) {
+       cds_list_for_each_entry(ev, &events_list->head, list) {
+               if (ev->event->token != tracer_token) {
+                       continue;
+               }
                if (type != LTTNG_EVENT_ALL && ev->type != type) {
                        continue;
                }
@@ -100,10 +154,10 @@ struct ltt_kernel_event *trace_kernel_find_event(
                break;
        }
        if (found) {
-               DBG("Found event %s for channel %s", name,
-                       channel->channel->name);
+               DBG("Kernel event %s found", name);
                return ev;
        } else {
+               DBG("Kernel event %s not found", name);
                return NULL;
        }
 }
@@ -160,9 +214,11 @@ struct ltt_kernel_session *trace_kernel_create_session(void)
        lks->fd = -1;
        lks->metadata_stream_fd = -1;
        lks->channel_count = 0;
+       lks->map_count = 0;
        lks->stream_count_global = 0;
        lks->metadata = NULL;
        CDS_INIT_LIST_HEAD(&lks->channel_list.head);
+       CDS_INIT_LIST_HEAD(&lks->map_list.head);
 
        lks->tracker_pid = process_attr_tracker_create();
        if (!lks->tracker_pid) {
@@ -274,6 +330,68 @@ error:
        return NULL;
 }
 
+struct ltt_kernel_map *trace_kernel_create_map(
+               const struct lttng_map *map)
+{
+       struct ltt_kernel_map *kernel_map = NULL;
+       unsigned int i, number_dimensions;
+
+       kernel_map = zmalloc(sizeof(*kernel_map));
+       if (!kernel_map) {
+               PERROR("ltt_kernel_map zmalloc");
+               goto end;
+       }
+
+       switch (lttng_map_get_boundary_policy(map)) {
+       case LTTNG_MAP_BOUNDARY_POLICY_OVERFLOW:
+               kernel_map->counter_conf.arithmetic = LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR;
+               break;
+       default:
+               abort();
+       }
+
+       switch (lttng_map_get_bitness(map)) {
+       case LTTNG_MAP_BITNESS_32BITS:
+               kernel_map->counter_conf.bitness = LTTNG_KERNEL_COUNTER_BITNESS_32;
+               break;
+       case LTTNG_MAP_BITNESS_64BITS:
+               kernel_map->counter_conf.bitness = LTTNG_KERNEL_COUNTER_BITNESS_64;
+               break;
+       default:
+               abort();
+       }
+
+       kernel_map->counter_conf.coalesce_hits = lttng_map_get_coalesce_hits(map);
+
+       number_dimensions = lttng_map_get_dimension_count(map);
+       assert(number_dimensions <= LTTNG_KERNEL_COUNTER_DIMENSION_MAX);
+
+       kernel_map->counter_conf.number_dimensions = number_dimensions;
+
+       for (i = 0; i < kernel_map->counter_conf.number_dimensions; i++) {
+               enum lttng_map_status map_status;
+               uint64_t dimension_length;
+
+               map_status = lttng_map_get_dimension_length(map, i,
+                               &dimension_length);
+               assert(map_status == LTTNG_MAP_STATUS_OK);
+
+               kernel_map->counter_conf.dimensions[i].size = dimension_length;
+
+               //FIXME: We need to turn on overflow and underflow
+               kernel_map->counter_conf.dimensions[i].has_overflow = false;
+               kernel_map->counter_conf.dimensions[i].has_underflow = false;
+       }
+
+       kernel_map->fd = -1;
+       kernel_map->enabled = 1;
+       kernel_map->key = get_next_map_key();
+
+       kernel_map->event_counters_ht = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+end:
+       return kernel_map;
+}
+
 /*
  * Allocate and init a kernel context object.
  *
@@ -485,6 +603,7 @@ error:
 enum lttng_error_code trace_kernel_create_event_notifier_rule(
                struct lttng_trigger *trigger,
                uint64_t token,
+               uint64_t error_counter_index,
                struct ltt_kernel_event_notifier_rule **event_notifier_rule)
 {
        enum lttng_error_code ret = LTTNG_OK;
@@ -501,9 +620,9 @@ enum lttng_error_code trace_kernel_create_event_notifier_rule(
        assert(condition);
 
        condition_type = lttng_condition_get_type(condition);
-       assert(condition_type == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+       assert(condition_type == LTTNG_CONDITION_TYPE_ON_EVENT);
 
-       condition_status = lttng_condition_event_rule_get_rule(
+       condition_status = lttng_condition_on_event_get_rule(
                        condition, &event_rule);
        assert(condition_status == LTTNG_CONDITION_STATUS_OK);
        assert(event_rule);
@@ -522,6 +641,7 @@ enum lttng_error_code trace_kernel_create_event_notifier_rule(
        local_kernel_token_event_rule->fd = -1;
        local_kernel_token_event_rule->enabled = 1;
        local_kernel_token_event_rule->token = token;
+       local_kernel_token_event_rule->error_counter_index = error_counter_index;
 
        /* Get the reference of the event rule. */
        lttng_trigger_get(trigger);
@@ -538,19 +658,26 @@ error:
        return ret;
 }
 
+enum trace_kernel_event_type {
+       TRACE_KERNEL_EVENT_TYPE_NOTIFIER,
+       TRACE_KERNEL_EVENT_TYPE_COUNTER,
+};
+
 /*
- * Initialize a kernel trigger from an event rule.
+ * Initialize a kernel event from an event rule.
  */
-enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule(
+static
+enum lttng_error_code trace_kernel_init_event_from_event_rule(
                const struct lttng_event_rule *rule,
-               struct lttng_kernel_event_notifier *kernel_event_notifier)
+               struct lttng_kernel_event *kernel_event,
+               enum trace_kernel_event_type event_type)
 {
        enum lttng_error_code ret_code;
        const char *name;
        int strncpy_ret;
 
        switch (lttng_event_rule_get_type(rule)) {
-       case LTTNG_EVENT_RULE_TYPE_KPROBE:
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE:
        {
                uint64_t address = 0, offset = 0;
                const char *symbol_name = NULL;
@@ -558,7 +685,7 @@ enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule(
                enum lttng_kernel_probe_location_status k_status;
                enum lttng_event_rule_status status;
 
-               status = lttng_event_rule_kprobe_get_location(rule, &location);
+               status = lttng_event_rule_kernel_probe_get_location(rule, &location);
                if (status != LTTNG_EVENT_RULE_STATUS_OK) {
                        ret_code = LTTNG_ERR_PROBE_LOCATION_INVAL;
                        goto error;
@@ -585,12 +712,68 @@ enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule(
                        abort();
                }
 
-               kernel_event_notifier->event.instrumentation = LTTNG_KERNEL_KPROBE;
-               kernel_event_notifier->event.u.kprobe.addr = address;
-               kernel_event_notifier->event.u.kprobe.offset = offset;
+               kernel_event->instrumentation = LTTNG_KERNEL_KPROBE;
+               kernel_event->u.kprobe.addr = address;
+               kernel_event->u.kprobe.offset = offset;
+               if (symbol_name) {
+                       strncpy_ret = lttng_strncpy(
+                                       kernel_event->u.kprobe.symbol_name,
+                                       symbol_name, LTTNG_KERNEL_SYM_NAME_LEN);
+
+                       if (strncpy_ret) {
+                               ret_code = LTTNG_ERR_INVALID;
+                               goto error;
+                       }
+               }
+
+               kernel_event->u.kprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
+
+               status = lttng_event_rule_kernel_probe_get_event_name(rule, &name);
+               assert(status == LTTNG_EVENT_RULE_STATUS_OK);
+               ret_code = LTTNG_OK;
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION:
+       {
+               uint64_t address = 0, offset = 0;
+               const char *symbol_name = NULL;
+               const struct lttng_kernel_function_location *location = NULL;
+               enum lttng_kernel_function_location_status k_status;
+               enum lttng_event_rule_status status;
+
+               status = lttng_event_rule_kernel_function_get_location(rule, &location);
+               if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       ret_code = LTTNG_ERR_PROBE_LOCATION_INVAL;
+                       goto error;
+               }
+
+               switch (lttng_kernel_function_location_get_type(location)) {
+               case LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_ADDRESS:
+               {
+                       k_status = lttng_kernel_function_location_address_get_address(
+                                       location, &address);
+                       assert(k_status == LTTNG_KERNEL_FUNCTION_LOCATION_STATUS_OK);
+                       break;
+               }
+               case LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_SYMBOL_OFFSET:
+               {
+                       k_status = lttng_kernel_function_location_symbol_get_offset(
+                                       location, &offset);
+                       assert(k_status == LTTNG_KERNEL_FUNCTION_LOCATION_STATUS_OK);
+                       symbol_name = lttng_kernel_function_location_symbol_get_name(
+                                       location);
+                       break;
+               }
+               default:
+                       abort();
+               }
+
+               kernel_event->instrumentation = LTTNG_KERNEL_KRETPROBE;
+               kernel_event->u.kretprobe.addr = address;
+               kernel_event->u.kretprobe.offset = offset;
                if (symbol_name) {
                        strncpy_ret = lttng_strncpy(
-                                       kernel_event_notifier->event.u.kprobe.symbol_name,
+                                       kernel_event->u.kretprobe.symbol_name,
                                        symbol_name, LTTNG_KERNEL_SYM_NAME_LEN);
 
                        if (strncpy_ret) {
@@ -599,25 +782,26 @@ enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule(
                        }
                }
 
-               kernel_event_notifier->event.u.kprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
-               status = lttng_event_rule_kprobe_get_name(rule, &name);
+               kernel_event->u.kretprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
+
+               status = lttng_event_rule_kernel_function_get_event_name(rule, &name);
                assert(status == LTTNG_EVENT_RULE_STATUS_OK);
                ret_code = LTTNG_OK;
                break;
        }
-       case LTTNG_EVENT_RULE_TYPE_UPROBE:
+       case LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE:
        {
                const struct lttng_userspace_probe_location* location = NULL;
                const struct lttng_userspace_probe_location_lookup_method *lookup = NULL;
                enum lttng_event_rule_status status;
 
-               status = lttng_event_rule_uprobe_get_location(rule, &location);
+               status = lttng_event_rule_userspace_probe_get_location(rule, &location);
                if (status != LTTNG_EVENT_RULE_STATUS_OK) {
                        ret_code = LTTNG_ERR_PROBE_LOCATION_INVAL;
                        goto error;
                }
 
-               kernel_event_notifier->event.instrumentation = LTTNG_KERNEL_UPROBE;
+               kernel_event->instrumentation = LTTNG_KERNEL_UPROBE;
 
                lookup = lttng_userspace_probe_location_get_lookup_method(
                                location);
@@ -633,20 +817,20 @@ enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule(
                switch (lttng_userspace_probe_location_lookup_method_get_type(lookup)) {
                case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
                        /* Get the file descriptor on the target binary. */
-                       kernel_event_notifier->event.u.uprobe.fd =
+                       kernel_event->u.uprobe.fd =
                                        lttng_userspace_probe_location_function_get_binary_fd(location);
 
                        break;
                case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
                        /* Get the file descriptor on the target binary. */
-                       kernel_event_notifier->event.u.uprobe.fd =
+                       kernel_event->u.uprobe.fd =
                                        lttng_userspace_probe_location_tracepoint_get_binary_fd(location);
                        break;
                default:
                        abort();
                }
 
-               status = lttng_event_rule_uprobe_get_name(rule, &name);
+               status = lttng_event_rule_userspace_probe_get_event_name(rule, &name);
                assert(status == LTTNG_EVENT_RULE_STATUS_OK);
                ret_code = LTTNG_OK;
                break;
@@ -661,7 +845,7 @@ enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule(
 
                assert(domain == LTTNG_DOMAIN_KERNEL);
                assert(status == LTTNG_EVENT_RULE_STATUS_OK);
-               kernel_event_notifier->event.instrumentation =
+               kernel_event->instrumentation =
                                LTTNG_KERNEL_TRACEPOINT;
 
                ret_code = LTTNG_OK;
@@ -675,24 +859,31 @@ enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule(
 
                assert(status == LTTNG_EVENT_RULE_STATUS_OK);
 
-               kernel_event_notifier->event.instrumentation =
+               kernel_event->instrumentation =
                                LTTNG_KERNEL_SYSCALL;
-               kernel_event_notifier->event.u.syscall.abi =
+               kernel_event->u.syscall.abi =
                                LTTNG_KERNEL_SYSCALL_ABI_ALL;
-               kernel_event_notifier->event.u.syscall.entryexit =
-                               LTTNG_KERNEL_SYSCALL_ENTRY;
-               kernel_event_notifier->event.u.syscall.match =
+               kernel_event->u.syscall.match =
                                LTTNG_KERNEL_SYSCALL_MATCH_NAME;
+               switch (event_type) {
+               case TRACE_KERNEL_EVENT_TYPE_COUNTER:
+                       kernel_event->u.syscall.entryexit =
+                                       LTTNG_KERNEL_SYSCALL_ENTRYEXIT;
+                       break;
+               case TRACE_KERNEL_EVENT_TYPE_NOTIFIER:
+                       kernel_event->u.syscall.entryexit =
+                                       LTTNG_KERNEL_SYSCALL_ENTRY;
+                       break;
+               }
                ret_code = LTTNG_OK;
                break;
        }
-       case LTTNG_EVENT_RULE_TYPE_KRETPROBE:
        default:
                abort();
                break;
        }
 
-       strncpy_ret = lttng_strncpy(kernel_event_notifier->event.name, name,
+       strncpy_ret = lttng_strncpy(kernel_event->name, name,
                        LTTNG_KERNEL_SYM_NAME_LEN);
        if (strncpy_ret) {
                ret_code = LTTNG_ERR_INVALID;
@@ -702,6 +893,25 @@ enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule(
 error:
        return ret_code;
 }
+
+enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule(
+               const struct lttng_event_rule *rule,
+               struct lttng_kernel_event_notifier *kernel_event_notifier)
+{
+       return trace_kernel_init_event_from_event_rule(rule,
+                       &kernel_event_notifier->event,
+                       TRACE_KERNEL_EVENT_TYPE_NOTIFIER);
+}
+
+enum lttng_error_code trace_kernel_init_event_counter_from_event_rule(
+               const struct lttng_event_rule *rule,
+               struct lttng_kernel_counter_event *kernel_counter_event)
+{
+       return trace_kernel_init_event_from_event_rule(rule,
+                       &kernel_counter_event->event,
+                       TRACE_KERNEL_EVENT_TYPE_COUNTER);
+}
+
 /*
  * Allocate and initialize a kernel metadata.
  *
@@ -857,6 +1067,41 @@ void trace_kernel_destroy_event(struct ltt_kernel_event *event)
        free(event);
 }
 
+/*
+ * Free kernel event counter structure from RCU context
+ */
+static void free_event_counter_rcu(struct rcu_head *rcu_node)
+{
+       struct ltt_kernel_event_counter *event_counter = caa_container_of(rcu_node,
+                       struct ltt_kernel_event_counter, rcu_node);
+
+       free(event_counter);
+}
+/*
+ * Cleanup kernel event counter structure.
+ */
+void trace_kernel_destroy_event_counter(struct ltt_kernel_event_counter *event_counter)
+{
+       assert(event_counter);
+
+       if (event_counter->fd >= 0) {
+               int ret;
+
+               DBG("[trace] Closing event counter fd %d", event_counter->fd);
+               /* Close kernel fd */
+               ret = close(event_counter->fd);
+               if (ret) {
+                       PERROR("close");
+               }
+       } else {
+               DBG("[trace] Tearing down event counter (no associated file descriptor)");
+       }
+
+       lttng_map_key_put(event_counter->key);
+       call_rcu(&event_counter->rcu_node, free_event_counter_rcu);
+}
+
+
 /*
  * Cleanup kernel event structure.
  */
@@ -954,6 +1199,38 @@ void trace_kernel_destroy_channel(struct ltt_kernel_channel *channel)
        free(channel);
 }
 
+/*
+ * Cleanup kernel map structure.
+ */
+void trace_kernel_destroy_map(struct ltt_kernel_map *map)
+{
+       int ret;
+       struct ltt_kernel_event_counter *event_counter;
+       struct lttng_ht_iter iter;
+
+       assert(map);
+
+       DBG("[trace] Closing map fd %d", map->fd);
+       /* Close kernel fd */
+       if (map->fd >= 0) {
+               ret = close(map->fd);
+               if (ret) {
+                       PERROR("close");
+               }
+       }
+
+       /* For each event counter in the map hashtable */
+       cds_lfht_for_each_entry(map->event_counters_ht->ht, &iter.iter,
+                       event_counter, ht_node.node) {
+               trace_kernel_destroy_event_counter(event_counter);
+       }
+
+       /* Remove from map list */
+       cds_list_del(&map->list);
+
+       free(map);
+}
+
 /*
  * Cleanup kernel metadata structure.
  */
@@ -984,6 +1261,7 @@ void trace_kernel_destroy_metadata(struct ltt_kernel_metadata *metadata)
 void trace_kernel_destroy_session(struct ltt_kernel_session *session)
 {
        struct ltt_kernel_channel *channel, *ctmp;
+       struct ltt_kernel_map *map, *map_tmp;
        int ret;
 
        assert(session);
@@ -1012,6 +1290,10 @@ void trace_kernel_destroy_session(struct ltt_kernel_session *session)
        cds_list_for_each_entry_safe(channel, ctmp, &session->channel_list.head, list) {
                trace_kernel_destroy_channel(channel);
        }
+
+       cds_list_for_each_entry_safe(map, map_tmp, &session->map_list.head, list) {
+               trace_kernel_destroy_map(map);
+       }
 }
 
 /* Free elements needed by destroy notifiers. */
index 89a4ab19f03364222dfd4f356b7db109ca372746..35e054f91ac8d2810a81852c40be2595b19ab62c 100644 (file)
@@ -11,6 +11,7 @@
 #include <urcu/list.h>
 
 #include <lttng/lttng.h>
+#include <lttng/map/map.h>
 #include <common/lttng-kernel.h>
 #include <common/lttng-kernel-old.h>
 #include <common/defaults.h>
@@ -33,6 +34,11 @@ struct ltt_kernel_channel_list {
        struct cds_list_head head;
 };
 
+/* map list */
+struct ltt_kernel_map_list {
+       struct cds_list_head head;
+};
+
 struct ltt_kernel_context {
        struct lttng_kernel_context ctx;
        struct cds_list_head list;
@@ -52,9 +58,10 @@ struct ltt_kernel_event {
        struct lttng_userspace_probe_location *userspace_probe_location;
 };
 
-/* Kernel event */
+/* Kernel event notifier */
 struct ltt_kernel_event_notifier_rule {
        int fd;
+       uint64_t error_counter_index;
        int enabled;
        enum lttng_event_type type;
        struct lttng_trigger *trigger;
@@ -66,6 +73,24 @@ struct ltt_kernel_event_notifier_rule {
        struct rcu_head rcu_node;
 };
 
+/* Kernel event counter */
+struct ltt_kernel_event_counter {
+       int fd;
+       int enabled;
+       uint64_t action_tracer_token;
+       struct lttng_kernel_event *event;
+       struct lttng_event_rule *event_rule;
+       const struct lttng_bytecode *filter;
+       struct lttng_userspace_probe_location *userspace_probe_location;
+       struct cds_list_head list;
+       struct lttng_ht_node_u64 ht_node;
+
+       /* refcounted */
+       struct lttng_map_key *key;
+       /* call_rcu delayed reclaim. */
+       struct rcu_head rcu_node;
+};
+
 /* Kernel channel */
 struct ltt_kernel_channel {
        int fd;
@@ -84,6 +109,20 @@ struct ltt_kernel_channel {
        bool sent_to_consumer;
 };
 
+/* Kernel map */
+struct ltt_kernel_map {
+       int fd;
+       uint64_t key; /* Key to reference this map with the notification thread. */
+       int enabled;
+       unsigned int event_count;
+       struct lttng_map *map;
+       struct lttng_kernel_counter_conf counter_conf;
+       struct lttng_ht *event_counters_ht;
+       struct cds_list_head list;
+       /* Session pointer which has a reference to this object. */
+       struct ltt_kernel_session *session;
+};
+
 /* Metadata */
 struct ltt_kernel_metadata {
        int fd;
@@ -110,9 +149,11 @@ struct ltt_kernel_session {
        int metadata_stream_fd;
        int consumer_fds_sent;
        unsigned int channel_count;
+       unsigned int map_count;
        unsigned int stream_count_global;
        struct ltt_kernel_metadata *metadata;
        struct ltt_kernel_channel_list channel_list;
+       struct ltt_kernel_map_list map_list;
        /* UID/GID of the user owning the session */
        uid_t uid;
        gid_t gid;
@@ -144,18 +185,23 @@ struct ltt_kernel_event *trace_kernel_get_event_by_name(
                char *name, struct ltt_kernel_channel *channel,
                enum lttng_event_type type);
 struct ltt_kernel_event *trace_kernel_find_event(
-               char *name, struct ltt_kernel_channel *channel,
+               struct ltt_kernel_event_list *events_list,
+               uint64_t tracer_token, char *name,
                enum lttng_event_type type,
                struct lttng_bytecode *filter);
 struct ltt_kernel_channel *trace_kernel_get_channel_by_name(
                const char *name, struct ltt_kernel_session *session);
 
+struct ltt_kernel_map *trace_kernel_get_map_by_name(
+               const char *name, struct ltt_kernel_session *session);
+
 /*
  * Create functions malloc() the data structure.
  */
 struct ltt_kernel_session *trace_kernel_create_session(void);
 struct ltt_kernel_channel *trace_kernel_create_channel(
                struct lttng_channel *chan);
+struct ltt_kernel_map *trace_kernel_create_map(const struct lttng_map *map);
 enum lttng_error_code trace_kernel_create_event(struct lttng_event *ev,
                char *filter_expression, struct lttng_bytecode *filter,
                struct ltt_kernel_event **kernel_event);
@@ -167,12 +213,16 @@ struct ltt_kernel_context *trace_kernel_create_context(
 enum lttng_error_code trace_kernel_create_event_notifier_rule(
                struct lttng_trigger *trigger,
                uint64_t token,
+               uint64_t error_counter_index,
                struct ltt_kernel_event_notifier_rule **event_notifier_rule);
 struct ltt_kernel_context *trace_kernel_copy_context(
                struct ltt_kernel_context *ctx);
 enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule(
                const struct lttng_event_rule *rule,
                struct lttng_kernel_event_notifier *kernel_event_notifier);
+enum lttng_error_code trace_kernel_init_event_counter_from_event_rule(
+               const struct lttng_event_rule *rule,
+               struct lttng_kernel_counter_event *kernel_counter_event);
 
 /*
  * Destroy functions free() the data structure and remove from linked list if
@@ -181,10 +231,13 @@ enum lttng_error_code trace_kernel_init_event_notifier_from_event_rule(
 void trace_kernel_destroy_session(struct ltt_kernel_session *session);
 void trace_kernel_destroy_metadata(struct ltt_kernel_metadata *metadata);
 void trace_kernel_destroy_channel(struct ltt_kernel_channel *channel);
+void trace_kernel_destroy_map(struct ltt_kernel_map *map);
 void trace_kernel_destroy_event(struct ltt_kernel_event *event);
 void trace_kernel_destroy_stream(struct ltt_kernel_stream *stream);
 void trace_kernel_destroy_context(struct ltt_kernel_context *ctx);
 void trace_kernel_destroy_event_notifier_rule(struct ltt_kernel_event_notifier_rule *rule);
+void trace_kernel_destroy_event_counter(
+               struct ltt_kernel_event_counter *event_counter);
 void trace_kernel_free_session(struct ltt_kernel_session *session);
 
 #endif /* _LTT_TRACE_KERNEL_H */
index 527b354f1a5e5c287e17733202d57670e78ce687..3df0e65dc258cf143d9a97b1438ff4e717759f80 100644 (file)
 #include <common/trace-chunk.h>
 #include <common/utils.h>
 
+#include <lttng/map-key-internal.h>
+#include <lttng/map/map-internal.h>
+
 #include "buffer-registry.h"
+#include "map.h"
 #include "trace-ust.h"
 #include "utils.h"
 #include "ust-app.h"
@@ -73,7 +77,14 @@ int trace_ust_ht_match_event(struct cds_lfht_node *node, const void *_key)
        key = _key;
        ev_loglevel_value = event->attr.loglevel;
 
-       /* Match the 4 elements of the key: name, filter, loglevel, exclusions. */
+       /* Match the 6 elements of the key: tracer_token, map_key, name, filter, loglevel, exclusions. */
+       if (event->attr.token != key->tracer_token) {
+               goto no_match;
+       }
+
+       if (!lttng_map_key_is_equal(event->key, key->key)) {
+               goto no_match;
+       }
 
        /* Event name */
        if (strncmp(event->attr.name, key->name, sizeof(event->attr.name)) != 0) {
@@ -189,14 +200,44 @@ error:
        return NULL;
 }
 
+/*
+ * Find the map in the hashtable and return map pointer. RCU read side
+ * lock MUST be acquired before calling this.
+ */
+struct ltt_ust_map *trace_ust_find_map_by_name(struct lttng_ht *ht,
+               const char *name)
+{
+       struct lttng_ht_node_str *node;
+       struct lttng_ht_iter iter;
+
+       if (name[0] == '\0') {
+               goto error;
+       }
+
+       lttng_ht_lookup(ht, (void *)name, &iter);
+       node = lttng_ht_iter_get_node_str(&iter);
+       if (node == NULL) {
+               goto error;
+       }
+
+       DBG2("Trace UST map %s found by name", name);
+
+       return caa_container_of(node, struct ltt_ust_map, node);
+
+error:
+       DBG2("Trace UST map %s not found by name", name);
+       return NULL;
+}
+
 /*
  * Find the event in the hashtable and return event pointer. RCU read side lock
  * MUST be acquired before calling this.
  */
 struct ltt_ust_event *trace_ust_find_event(struct lttng_ht *ht,
-               char *name, struct lttng_bytecode *filter,
+               uint64_t tracer_token, char *name, struct lttng_bytecode *filter,
                enum lttng_ust_loglevel_type loglevel_type, int loglevel_value,
-               struct lttng_event_exclusion *exclusion)
+               struct lttng_event_exclusion *exclusion,
+               struct lttng_map_key *map_key)
 {
        struct lttng_ht_node_str *node;
        struct lttng_ht_iter iter;
@@ -205,11 +246,13 @@ struct ltt_ust_event *trace_ust_find_event(struct lttng_ht *ht,
        assert(name);
        assert(ht);
 
+       key.tracer_token = tracer_token;
        key.name = name;
        key.filter = filter;
        key.loglevel_type = loglevel_type;
        key.loglevel_value = loglevel_value;
        key.exclusion = exclusion;
+       key.key = map_key;
 
        cds_lfht_lookup(ht->ht, ht->hash_fct((void *) name, lttng_ht_seed),
                        trace_ust_ht_match_event, &key, &iter.iter);
@@ -301,6 +344,8 @@ struct ltt_ust_session *trace_ust_create_session(uint64_t session_id)
 
        /* Alloc UST global domain channels' HT */
        lus->domain_global.channels = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+       /* Alloc UST global domain maps' HT */
+       lus->domain_global.maps = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
        /* Alloc agent hash table. */
        lus->agents = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
 
@@ -330,6 +375,7 @@ error:
        process_attr_tracker_destroy(lus->tracker_vuid);
        process_attr_tracker_destroy(lus->tracker_vgid);
        ht_cleanup_push(lus->domain_global.channels);
+       ht_cleanup_push(lus->domain_global.maps);
        ht_cleanup_push(lus->agents);
        free(lus);
 error_alloc:
@@ -405,6 +451,67 @@ error:
        return luc;
 }
 
+/*
+ * Allocate and initialize a ust map data structure.
+ *
+ * Return pointer to structure or NULL.
+ */
+struct ltt_ust_map *trace_ust_create_map(const struct lttng_map *map)
+{
+       struct ltt_ust_map *umap = NULL;
+       enum lttng_map_status map_status;
+       const char *map_name = NULL;
+       unsigned int dimension_count;
+       uint64_t dimension_len;
+
+       umap = zmalloc(sizeof(*umap));
+       if (!umap) {
+               PERROR("ltt_ust_map zmalloc");
+               goto end;
+       }
+
+       map_status = lttng_map_get_name(map, &map_name);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Can't get map name");
+               umap = NULL;
+               goto end;
+       }
+
+       dimension_count = lttng_map_get_dimension_count(map);
+       assert(dimension_count == 1);
+
+       map_status = lttng_map_get_dimension_length(map, 0, &dimension_len);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Can't get map first dimension length");
+               umap = NULL;
+               goto end;
+       }
+       assert(dimension_len > 0);
+
+       strncpy(umap->name, map_name, sizeof(umap->name));
+
+       umap->enabled = 1;
+       umap->bucket_count = dimension_len;
+       umap->coalesce_hits = lttng_map_get_coalesce_hits(map);
+       umap->bitness = lttng_map_get_bitness(map);
+       umap->nr_cpu = ustctl_get_nr_cpu_per_counter();
+
+       umap->dead_app_kv_values.dead_app_kv_values_32bits = lttng_ht_new(0,
+                       LTTNG_HT_TYPE_STRING);
+       umap->dead_app_kv_values.dead_app_kv_values_64bits = lttng_ht_new(0,
+                       LTTNG_HT_TYPE_STRING);
+       pthread_mutex_init(&umap->dead_app_kv_values.lock, NULL);
+
+       umap->events = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+
+       /* Init node */
+       lttng_ht_node_init_str(&umap->node, umap->name);
+
+       DBG2("Trace UST map %s created", umap->name);
+end:
+       return umap;
+}
+
 /*
  * Validates an exclusion list.
  *
@@ -444,7 +551,12 @@ end:
  *
  * Return an lttng_error_code
  */
-enum lttng_error_code trace_ust_create_event(struct lttng_event *ev,
+enum lttng_error_code trace_ust_create_event(uint64_t tracer_token,
+               const char *ev_name,
+               struct lttng_map_key *key,
+               enum lttng_event_type ev_type,
+               enum lttng_loglevel_type ev_loglevel_type,
+               enum lttng_loglevel ev_loglevel,
                char *filter_expression,
                struct lttng_bytecode *filter,
                struct lttng_event_exclusion *exclusion,
@@ -454,8 +566,6 @@ enum lttng_error_code trace_ust_create_event(struct lttng_event *ev,
        struct ltt_ust_event *local_ust_event;
        enum lttng_error_code ret = LTTNG_OK;
 
-       assert(ev);
-
        if (exclusion && validate_exclusion(exclusion)) {
                ret = LTTNG_ERR_INVALID;
                goto error;
@@ -469,8 +579,9 @@ enum lttng_error_code trace_ust_create_event(struct lttng_event *ev,
        }
 
        local_ust_event->internal = internal_event;
+       local_ust_event->attr.token = tracer_token;
 
-       switch (ev->type) {
+       switch (ev_type) {
        case LTTNG_EVENT_PROBE:
                local_ust_event->attr.instrumentation = LTTNG_UST_PROBE;
                break;
@@ -484,44 +595,53 @@ enum lttng_error_code trace_ust_create_event(struct lttng_event *ev,
                local_ust_event->attr.instrumentation = LTTNG_UST_TRACEPOINT;
                break;
        default:
-               ERR("Unknown ust instrumentation type (%d)", ev->type);
+               ERR("Unknown ust instrumentation type (%d)", ev_type);
                ret = LTTNG_ERR_INVALID;
                goto error_free_event;
        }
 
        /* Copy event name */
-       strncpy(local_ust_event->attr.name, ev->name, LTTNG_UST_SYM_NAME_LEN);
+       strncpy(local_ust_event->attr.name, ev_name, LTTNG_UST_SYM_NAME_LEN);
        local_ust_event->attr.name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
 
-       switch (ev->loglevel_type) {
+       switch (ev_loglevel_type) {
        case LTTNG_EVENT_LOGLEVEL_ALL:
                local_ust_event->attr.loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
                local_ust_event->attr.loglevel = -1;    /* Force to -1 */
                break;
        case LTTNG_EVENT_LOGLEVEL_RANGE:
                local_ust_event->attr.loglevel_type = LTTNG_UST_LOGLEVEL_RANGE;
-               local_ust_event->attr.loglevel = ev->loglevel;
+               local_ust_event->attr.loglevel = ev_loglevel;
                break;
        case LTTNG_EVENT_LOGLEVEL_SINGLE:
                local_ust_event->attr.loglevel_type = LTTNG_UST_LOGLEVEL_SINGLE;
-               local_ust_event->attr.loglevel = ev->loglevel;
+               local_ust_event->attr.loglevel = ev_loglevel;
                break;
        default:
-               ERR("Unknown ust loglevel type (%d)", ev->loglevel_type);
+               ERR("Unknown ust loglevel type (%d)", ev_loglevel_type);
                ret = LTTNG_ERR_INVALID;
                goto error_free_event;
        }
 
        /* Same layout. */
+       local_ust_event->key = key;
        local_ust_event->filter_expression = filter_expression;
        local_ust_event->filter = filter;
        local_ust_event->exclusion = exclusion;
 
+       /* Take a reference on the lttng_map_key to bounds its lifetime to the
+        * ust_event.
+        */
+       if (key) {
+               lttng_map_key_get(key);
+       }
+
        /* Init node */
        lttng_ht_node_init_str(&local_ust_event->node, local_ust_event->attr.name);
 
-       DBG2("Trace UST event %s, loglevel (%d,%d) created",
-               local_ust_event->attr.name, local_ust_event->attr.loglevel_type,
+       DBG2("Trace UST event %s, tracer token %"PRIu64", loglevel (%d,%d) created",
+               local_ust_event->attr.name, local_ust_event->attr.token,
+               local_ust_event->attr.loglevel_type,
                local_ust_event->attr.loglevel);
 
        *ust_event = local_ust_event;
@@ -1242,6 +1362,7 @@ void trace_ust_destroy_event(struct ltt_ust_event *event)
        assert(event);
 
        DBG2("Trace destroy UST event %s", event->attr.name);
+       lttng_map_key_put(event->key);
        free(event->filter_expression);
        free(event->filter);
        free(event->exclusion);
@@ -1311,6 +1432,53 @@ static void _trace_ust_destroy_channel(struct ltt_ust_channel *channel)
        free(channel);
 }
 
+/*
+ * Cleanup ust map structure.
+ *
+ * Should _NOT_ be called with RCU read lock held.
+ */
+static void _trace_ust_destroy_map(struct ltt_ust_map *map)
+{
+       struct map_kv_ht_entry *kv_entry;
+       struct lttng_ht_iter ht_iter;
+       struct lttng_ht *dead_app_kv_ht;
+
+       assert(map);
+
+       DBG2("Trace destroy UST map %s", map->name);
+
+       /*
+        * Remove all the keys before destroying the hashtables.
+        */
+       dead_app_kv_ht = map->dead_app_kv_values.dead_app_kv_values_32bits;
+       cds_lfht_for_each_entry(dead_app_kv_ht->ht, &ht_iter.iter, kv_entry, node.node) {
+               struct lttng_ht_iter entry_iter;
+
+               entry_iter.iter.node = &kv_entry->node.node;
+               lttng_ht_del(dead_app_kv_ht, &entry_iter);
+
+               free(kv_entry->key);
+               free(kv_entry);
+       }
+       lttng_ht_destroy(map->dead_app_kv_values.dead_app_kv_values_32bits);
+
+       dead_app_kv_ht = map->dead_app_kv_values.dead_app_kv_values_64bits;
+       cds_lfht_for_each_entry(dead_app_kv_ht->ht, &ht_iter.iter, kv_entry, node.node) {
+               struct lttng_ht_iter entry_iter;
+
+               entry_iter.iter.node = &kv_entry->node.node;
+               lttng_ht_del(dead_app_kv_ht, &entry_iter);
+
+               free(kv_entry->key);
+               free(kv_entry);
+       }
+
+       lttng_ht_destroy(map->dead_app_kv_values.dead_app_kv_values_64bits);
+
+       lttng_map_put(map->map);
+       free(map);
+}
+
 /*
  * URCU intermediate call to complete destroy channel.
  */
@@ -1324,6 +1492,19 @@ static void destroy_channel_rcu(struct rcu_head *head)
        _trace_ust_destroy_channel(channel);
 }
 
+/*
+ * URCU intermediate call to complete destroy map.
+ */
+static void destroy_map_rcu(struct rcu_head *head)
+{
+       struct lttng_ht_node_str *node =
+               caa_container_of(head, struct lttng_ht_node_str, head);
+       struct ltt_ust_map *map =
+               caa_container_of(node, struct ltt_ust_map, node);
+
+       _trace_ust_destroy_map(map);
+}
+
 void trace_ust_destroy_channel(struct ltt_ust_channel *channel)
 {
        /* Destroying all events of the channel */
@@ -1334,6 +1515,14 @@ void trace_ust_destroy_channel(struct ltt_ust_channel *channel)
        call_rcu(&channel->node.head, destroy_channel_rcu);
 }
 
+void trace_ust_destroy_map(struct ltt_ust_map *map)
+{
+       /* Destroying all events of the map */
+       destroy_events(map->events);
+
+       call_rcu(&map->node.head, destroy_map_rcu);
+}
+
 /*
  * Remove an UST channel from a channel HT.
  */
@@ -1351,6 +1540,23 @@ void trace_ust_delete_channel(struct lttng_ht *ht,
        assert(!ret);
 }
 
+/*
+ * Remove an UST map from a map HT.
+ */
+void trace_ust_delete_map(struct lttng_ht *ht,
+               struct ltt_ust_map *map)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+
+       assert(ht);
+       assert(map);
+
+       iter.iter.node = &map->node.node;
+       ret = lttng_ht_del(ht, &iter);
+       assert(!ret);
+}
+
 /*
  * Iterate over a hash table containing channels and cleanup safely.
  */
@@ -1374,6 +1580,28 @@ static void destroy_channels(struct lttng_ht *channels)
        ht_cleanup_push(channels);
 }
 
+/*
+ * Iterate over a hash table containing maps and cleanup safely.
+ */
+static void destroy_maps(struct lttng_ht *maps)
+{
+       struct lttng_ht_node_str *node;
+       struct lttng_ht_iter iter;
+
+       assert(maps);
+
+       rcu_read_lock();
+       cds_lfht_for_each_entry(maps->ht, &iter.iter, node, node) {
+               struct ltt_ust_map *map =
+                       caa_container_of(node, struct ltt_ust_map, node);
+
+               trace_ust_delete_map(maps, map);
+               trace_ust_destroy_map(map);
+       }
+       rcu_read_unlock();
+
+       ht_cleanup_push(maps);
+}
 /*
  * Cleanup UST global domain.
  */
@@ -1382,6 +1610,7 @@ static void destroy_domain_global(struct ltt_ust_domain_global *dom)
        assert(dom);
 
        destroy_channels(dom->channels);
+       destroy_maps(dom->maps);
 }
 
 /*
index 53e1ab2b5b2a98836ff520e7bf025426c909f74b..b254ad05df64db52dc88b6d1e07f46fc3f3e3104 100644 (file)
 struct agent;
 
 struct ltt_ust_ht_key {
+       uint64_t tracer_token;
        const char *name;
        const struct lttng_bytecode *filter;
        enum lttng_ust_loglevel_type loglevel_type;
        int loglevel_value;
        const struct lttng_event_exclusion *exclusion;
+       struct lttng_map_key *key;
 };
 
 /* Context hash table nodes */
@@ -45,6 +47,9 @@ struct ltt_ust_event {
        char *filter_expression;
        struct lttng_bytecode *filter;
        struct lttng_event_exclusion *exclusion;
+
+       /* refcounted */
+       struct lttng_map_key *key;
        /*
         * An internal event is an event which was created by the session daemon
         * through which, for example, events emitted in Agent domains are
@@ -76,9 +81,31 @@ struct ltt_ust_channel {
        uint64_t monitor_timer_interval;
 };
 
+struct ltt_ust_map_dead_pid_kv_values {
+       pthread_mutex_t lock;
+       struct lttng_ht *dead_app_kv_values_32bits;
+       struct lttng_ht *dead_app_kv_values_64bits;
+};
+
+/* UST map */
+struct ltt_ust_map {
+       uint64_t id;    /* unique id per session. */
+       char name[LTTNG_UST_SYM_NAME_LEN];
+       unsigned int enabled;
+       size_t bucket_count;
+       bool coalesce_hits;
+       enum lttng_map_bitness bitness;
+       uint64_t nr_cpu;
+       struct lttng_ht_node_str node;
+       struct lttng_map *map;
+       struct lttng_ht *events;
+       struct ltt_ust_map_dead_pid_kv_values dead_app_kv_values;
+};
+
 /* UST domain global (LTTNG_DOMAIN_UST) */
 struct ltt_ust_domain_global {
        struct lttng_ht *channels;
+       struct lttng_ht *maps;
        struct cds_list_head registry_buffer_uid_list;
 };
 
@@ -182,11 +209,14 @@ int trace_ust_ht_match_event_by_name(struct cds_lfht_node *node,
  * Lookup functions. NULL is returned if not found.
  */
 struct ltt_ust_event *trace_ust_find_event(struct lttng_ht *ht,
-               char *name, struct lttng_bytecode *filter,
+               uint64_t tracer_token, char *name, struct lttng_bytecode *filter,
                enum lttng_ust_loglevel_type loglevel_type, int loglevel_value,
-               struct lttng_event_exclusion *exclusion);
+               struct lttng_event_exclusion *exclusion,
+               struct lttng_map_key *key);
 struct ltt_ust_channel *trace_ust_find_channel_by_name(struct lttng_ht *ht,
                const char *name);
+struct ltt_ust_map *trace_ust_find_map_by_name(struct lttng_ht *ht,
+               const char *name);
 struct agent *trace_ust_find_agent(struct ltt_ust_session *session,
                enum lttng_domain_type domain_type);
 
@@ -196,17 +226,26 @@ struct agent *trace_ust_find_agent(struct ltt_ust_session *session,
 struct ltt_ust_session *trace_ust_create_session(uint64_t session_id);
 struct ltt_ust_channel *trace_ust_create_channel(struct lttng_channel *attr,
                enum lttng_domain_type domain);
-enum lttng_error_code trace_ust_create_event(struct lttng_event *ev,
+struct ltt_ust_map *trace_ust_create_map(const struct lttng_map *map);
+enum lttng_error_code trace_ust_create_event(uint64_t tracer_token,
+               const char *ev_name,
+               struct lttng_map_key *key,
+               enum lttng_event_type ev_type,
+               enum lttng_loglevel_type ev_loglevel_type,
+               enum lttng_loglevel ev_loglevel,
                char *filter_expression,
                struct lttng_bytecode *filter,
                struct lttng_event_exclusion *exclusion,
-               bool internal_event, struct ltt_ust_event **ust_event);
+               bool internal_event,
+               struct ltt_ust_event **ust_event);
 struct ltt_ust_context *trace_ust_create_context(
                const struct lttng_event_context *ctx);
 int trace_ust_match_context(const struct ltt_ust_context *uctx,
                const struct lttng_event_context *ctx);
 void trace_ust_delete_channel(struct lttng_ht *ht,
                struct ltt_ust_channel *channel);
+void trace_ust_delete_map(struct lttng_ht *ht,
+               struct ltt_ust_map *map);
 
 /*
  * Destroy functions free() the data structure and remove from linked list if
@@ -214,6 +253,7 @@ void trace_ust_delete_channel(struct lttng_ht *ht,
  */
 void trace_ust_destroy_session(struct ltt_ust_session *session);
 void trace_ust_destroy_channel(struct ltt_ust_channel *channel);
+void trace_ust_destroy_map(struct ltt_ust_map *map);
 void trace_ust_destroy_event(struct ltt_ust_event *event);
 void trace_ust_destroy_context(struct ltt_ust_context *ctx);
 void trace_ust_free_session(struct ltt_ust_session *session);
@@ -255,7 +295,12 @@ struct ltt_ust_channel *trace_ust_find_channel_by_name(struct lttng_ht *ht,
 {
        return NULL;
 }
-
+static inline
+struct ltt_ust_map *trace_ust_find_map_by_name(struct lttng_ht *ht,
+               const char *name)
+{
+       return NULL;
+}
 static inline
 struct ltt_ust_session *trace_ust_create_session(unsigned int session_id)
 {
@@ -268,11 +313,22 @@ struct ltt_ust_channel *trace_ust_create_channel(struct lttng_channel *attr,
        return NULL;
 }
 static inline
-enum lttng_error_code trace_ust_create_event(struct lttng_event *ev,
-               const char *filter_expression,
+struct ltt_ust_map *trace_ust_create_map(const struct lttng_map *map)
+{
+       return NULL;
+}
+static inline
+enum lttng_error_code trace_ust_create_event(uint64_t tracer_token,
+               const char *ev_name,
+               struct lttng_map_key *key,
+               enum lttng_event_type ev_type,
+               enum lttng_loglevel_type ev_loglevel_type,
+               enum lttng_loglevel ev_loglevel,
+               char *filter_expression,
                struct lttng_bytecode *filter,
                struct lttng_event_exclusion *exclusion,
-               bool internal_event, struct ltt_ust_event **ust_event)
+               bool internal_event,
+               struct ltt_ust_event **ust_event)
 {
        return LTTNG_ERR_NO_UST;
 }
@@ -286,6 +342,11 @@ void trace_ust_destroy_channel(struct ltt_ust_channel *channel)
 {
 }
 
+static inline
+void trace_ust_destroy_map(struct ltt_ust_map *map)
+{
+}
+
 static inline
 void trace_ust_destroy_event(struct ltt_ust_event *event)
 {
@@ -310,9 +371,10 @@ int trace_ust_match_context(const struct ltt_ust_context *uctx,
 }
 static inline
 struct ltt_ust_event *trace_ust_find_event(struct lttng_ht *ht,
-               char *name, struct lttng_bytecode *filter,
+               uint64_t tracer_token, char *name, struct lttng_bytecode *filter,
                enum lttng_ust_loglevel_type loglevel_type, int loglevel_value,
-               struct lttng_event_exclusion *exclusion)
+               struct lttng_event_exclusion *exclusion,
+               struct lttng_map_key *key)
 {
        return NULL;
 }
index 0f12be08391cc750d0ced61b6b83cccbeb254c89..413302c3266d209345cf275a5f0fd38a65b0ab57 100644 (file)
@@ -95,6 +95,7 @@ struct lttng_ust_event {
 
        enum lttng_ust_loglevel_type loglevel_type;
        int loglevel;   /* value, -1: all */
+       uint64_t token;
        char padding[LTTNG_UST_EVENT_PADDING1];
 
        /* Per instrumentation type configuration */
@@ -109,9 +110,10 @@ struct lttng_ust_event_notifier {
        char padding[LTTNG_UST_EVENT_NOTIFIER_PADDING];
 } LTTNG_PACKED;
 
-#define LTTNG_UST_EVENT_NOTIFIER_NOTIFICATION_PADDING 34
+#define LTTNG_UST_EVENT_NOTIFIER_NOTIFICATION_PADDING 32
 struct lttng_ust_event_notifier_notification {
        uint64_t token;
+       uint16_t capture_buf_size;
        char padding[LTTNG_UST_EVENT_NOTIFIER_NOTIFICATION_PADDING];
 } LTTNG_PACKED;
 
index 43864bd0fc27d3bae0c759c2ac797ccca080869e..839a7143752b4cd340b826298a5daf4c431982b2 100644 (file)
@@ -7,11 +7,14 @@
  */
 
 #define _LGPL_SOURCE
+#include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <common/compat/errno.h>
 #include <common/common.h>
 #include <common/hashtable/utils.h>
+#include <common/shm.h>
+#include <lttng/lttng-error.h>
 #include <lttng/event-rule/event-rule.h>
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/event-rule/tracepoint.h>
 #include <lttng/condition/condition.h>
-#include <lttng/condition/event-rule-internal.h>
-#include <lttng/condition/event-rule.h>
+#include <lttng/condition/on-event-internal.h>
+#include <lttng/condition/on-event.h>
+#include <lttng/map/map.h>
+#include <lttng/map/map-internal.h>
+#include <lttng/map/map-query-internal.h>
+#include <lttng/map-key.h>
+#include <lttng/map-key-internal.h>
 #include <lttng/trigger/trigger-internal.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 
 #include "buffer-registry.h"
+#include "condition-internal.h"
 #include "fd-limit.h"
 #include "health-sessiond.h"
 #include "ust-app.h"
@@ -44,6 +55,9 @@
 #include "notification-thread-commands.h"
 #include "rotate.h"
 #include "event.h"
+#include "event-notifier-error-accounting.h"
+#include "map.h"
+
 
 struct lttng_ht *ust_app_ht;
 struct lttng_ht *ust_app_ht_by_sock;
@@ -56,6 +70,10 @@ int ust_app_flush_app_session(struct ust_app *app, struct ust_app_session *ua_se
 static uint64_t _next_channel_key;
 static pthread_mutex_t next_channel_key_lock = PTHREAD_MUTEX_INITIALIZER;
 
+/* Next available map key. Access under next_map_key_lock. */
+static uint64_t _next_map_key;
+static pthread_mutex_t next_map_key_lock = PTHREAD_MUTEX_INITIALIZER;
+
 /* Next available session ID. Access under next_session_id_lock. */
 static uint64_t _next_session_id;
 static pthread_mutex_t next_session_id_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -73,6 +91,19 @@ static uint64_t get_next_channel_key(void)
        return ret;
 }
 
+/*
+ * Return the incremented value of next_map_key.
+ */
+static uint64_t get_next_map_key(void)
+{
+       uint64_t ret;
+
+       pthread_mutex_lock(&next_map_key_lock);
+       ret = ++_next_map_key;
+       pthread_mutex_unlock(&next_map_key_lock);
+       return ret;
+}
+
 /*
  * Return the atomically incremented value of next_session_id.
  */
@@ -119,7 +150,14 @@ static int ht_match_ust_app_event(struct cds_lfht_node *node, const void *_key)
        key = _key;
        ev_loglevel_value = event->attr.loglevel;
 
-       /* Match the 4 elements of the key: name, filter, loglevel, exclusions */
+       /*
+        * Match the 5 elements of the key:
+        * tracer token, name, filter, loglevel, exclusions
+        */
+
+       if (event->attr.token != key->tracer_token) {
+               goto no_match;
+       }
 
        /* Event name */
        if (strncmp(event->attr.name, key->name, sizeof(event->attr.name)) != 0) {
@@ -182,25 +220,23 @@ no_match:
  * Unique add of an ust app event in the given ht. This uses the custom
  * ht_match_ust_app_event match function and the event name as hash.
  */
-static void add_unique_ust_app_event(struct ust_app_channel *ua_chan,
+static void add_unique_ust_app_event(struct lttng_ht *events_ht,
                struct ust_app_event *event)
 {
        struct cds_lfht_node *node_ptr;
        struct ust_app_ht_key key;
-       struct lttng_ht *ht;
 
-       assert(ua_chan);
-       assert(ua_chan->events);
+       assert(events_ht);
        assert(event);
 
-       ht = ua_chan->events;
        key.name = event->attr.name;
        key.filter = event->filter;
        key.loglevel_type = event->attr.loglevel;
        key.exclusion = event->exclusion;
+       key.tracer_token = event->attr.token;
 
-       node_ptr = cds_lfht_add_unique(ht->ht,
-                       ht->hash_fct(event->node.key, lttng_ht_seed),
+       node_ptr = cds_lfht_add_unique(events_ht->ht,
+                       events_ht->hash_fct(event->node.key, lttng_ht_seed),
                        ht_match_ust_app_event, &key, &event->node.node);
        assert(node_ptr == &event->node.node);
 }
@@ -395,6 +431,33 @@ static int release_ust_app_stream(int sock, struct ust_app_stream *stream,
        return ret;
 }
 
+/*
+ * Release ust data object of the given map_counter.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int release_ust_app_map_counter(int sock, struct ust_app_map_counter *map_counter,
+               struct ust_app *app)
+{
+       int ret = 0;
+
+       assert(map_counter);
+
+       if (map_counter->obj) {
+               pthread_mutex_lock(&app->sock_lock);
+               ret = ustctl_release_object(sock, map_counter->obj);
+               pthread_mutex_unlock(&app->sock_lock);
+               if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("UST app sock %d release map_counter obj failed with ret %d",
+                                       sock, ret);
+               }
+               lttng_fd_put(LTTNG_FD_APPS, 2);
+               free(map_counter->obj);
+       }
+
+       return ret;
+}
+
 /*
  * Delete ust app stream safely. RCU read lock must be held before calling
  * this function.
@@ -409,6 +472,20 @@ void delete_ust_app_stream(int sock, struct ust_app_stream *stream,
        free(stream);
 }
 
+/*
+ * Delete ust app map_counter safely. RCU read lock must be held before calling
+ * this function.
+ */
+static
+void delete_ust_app_map_counter(int sock, struct ust_app_map_counter *map_counter,
+               struct ust_app *app)
+{
+       assert(map_counter);
+
+       (void) release_ust_app_map_counter(sock, map_counter, app);
+       free(map_counter);
+}
+
 /*
  * We need to execute ht_destroy outside of RCU read-side critical
  * section and outside of call_rcu thread, so we postpone its execution
@@ -426,6 +503,22 @@ void delete_ust_app_channel_rcu(struct rcu_head *head)
        free(ua_chan);
 }
 
+/*
+ * We need to execute ht_destroy outside of RCU read-side critical
+ * section and outside of call_rcu thread, so we postpone its execution
+ * using ht_cleanup_push. It is simpler than to change the semantic of
+ * the many callers of delete_ust_app_session().
+ */
+static
+void delete_ust_app_map_rcu(struct rcu_head *head)
+{
+       struct ust_app_map *ua_map =
+               caa_container_of(head, struct ust_app_map, rcu_head);
+
+       ht_cleanup_push(ua_map->events);
+       free(ua_map);
+}
+
 /*
  * Extract the lost packet or discarded events counter when the channel is
  * being deleted and store the value in the parent channel so we can
@@ -555,7 +648,7 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan,
        if (ua_chan->obj != NULL) {
                /* Remove channel from application UST object descriptor. */
                iter.iter.node = &ua_chan->ust_objd_node.node;
-               ret = lttng_ht_del(app->ust_objd, &iter);
+               ret = lttng_ht_del(app->ust_chan_objd, &iter);
                assert(!ret);
                pthread_mutex_lock(&app->sock_lock);
                ret = ustctl_release_object(sock, ua_chan->obj);
@@ -570,6 +663,123 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan,
        call_rcu(&ua_chan->rcu_head, delete_ust_app_channel_rcu);
 }
 
+static
+void copy_ust_app_map_values(int sock, struct ust_app_map *ua_map,
+               struct ust_app *app)
+{
+       struct ltt_ust_map_dead_pid_kv_values *kv_pair_list = ua_map->dead_app_kv_values;
+       struct ust_registry_session *ust_reg_sess;
+       struct ust_registry_map *ust_reg_map;
+       struct ust_registry_map_index_ht_entry *map_index_entry;
+       struct lttng_ht_iter key_iter;
+       struct lttng_ht *dead_app_kv_values;
+
+       assert(app->buffer_type == LTTNG_BUFFER_PER_PID);
+       ust_reg_sess = get_session_registry(ua_map->session);
+
+       pthread_mutex_lock(&ust_reg_sess->lock);
+       ust_reg_map = ust_registry_map_find(ust_reg_sess, ua_map->key);
+       pthread_mutex_unlock(&ust_reg_sess->lock);
+       assert(ust_reg_map);
+
+       DBG("Aggregating dead map values");
+
+       pthread_mutex_lock(&kv_pair_list->lock);
+
+       if (app->bits_per_long == 32) {
+               dead_app_kv_values = kv_pair_list->dead_app_kv_values_32bits;
+       } else {
+               dead_app_kv_values = kv_pair_list->dead_app_kv_values_64bits;
+       }
+
+       /* Iterate over all the formated_key -> counter index */
+       cds_lfht_for_each_entry(ust_reg_map->key_string_to_bucket_index_ht->ht,
+               &key_iter.iter, map_index_entry, node.node) {
+               bool overflow = 0, underflow = 0;
+               int64_t local_value = 0;
+               int ret;
+               size_t dimension_indexes[1] = {map_index_entry->index};
+
+               ret = ustctl_counter_aggregate(ua_map->map_handle,
+                               dimension_indexes, &local_value, &overflow,
+                               &underflow);
+               if (ret) {
+                       ERR("Error getting counter value from the tracer: key = '%s'",
+                               map_index_entry->formated_key);
+                       ret = -1;
+                       goto end;
+               }
+
+               map_add_or_increment_map_values(dead_app_kv_values,
+                               map_index_entry->formated_key, local_value,
+                               underflow, overflow);
+
+       }
+
+end:
+       pthread_mutex_unlock(&kv_pair_list->lock);
+       return;
+}
+/*
+ * Delete ust app map safely. RCU read lock must be held before calling
+ * this function.
+ *
+ * The session list lock must be held by the caller.
+ */
+static
+void delete_ust_app_map(int sock, struct ust_app_map *ua_map,
+               struct ust_app *app)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+       struct ust_app_event *ua_event;
+       struct ust_app_map_counter *map_counter, *ctmp;
+       struct ust_registry_session *registry;
+
+       assert(ua_map);
+
+       DBG3("UST app deleting map %s", ua_map->name);
+
+       /* Wipe stream */
+       cds_list_for_each_entry_safe(map_counter, ctmp, &ua_map->counters.head, list) {
+               cds_list_del(&map_counter->list);
+               delete_ust_app_map_counter(sock, map_counter, app);
+       }
+
+       /* Wipe events */
+       cds_lfht_for_each_entry(ua_map->events->ht, &iter.iter, ua_event,
+                       node.node) {
+               ret = lttng_ht_del(ua_map->events, &iter);
+               assert(!ret);
+               delete_ust_app_event(sock, ua_event, app);
+       }
+
+       if (ua_map->session->buffer_type == LTTNG_BUFFER_PER_PID) {
+               /* Wipe and free registry from session registry. */
+               registry = get_session_registry(ua_map->session);
+               if (registry) {
+                       ust_registry_map_del_free(registry, ua_map->key);
+               }
+       }
+
+       if (ua_map->obj != NULL) {
+               /* Remove map from application UST object descriptor. */
+               iter.iter.node = &ua_map->ust_objd_node.node;
+               ret = lttng_ht_del(app->ust_map_objd, &iter);
+               assert(!ret);
+               pthread_mutex_lock(&app->sock_lock);
+               ret = ustctl_release_object(sock, ua_map->obj);
+               pthread_mutex_unlock(&app->sock_lock);
+               if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("UST app sock %d release map obj failed with ret %d",
+                                       sock, ret);
+               }
+               lttng_fd_put(LTTNG_FD_APPS, 1);
+               free(ua_map->obj);
+       }
+       call_rcu(&ua_map->rcu_head, delete_ust_app_map_rcu);
+}
+
 int ust_app_register_done(struct ust_app *app)
 {
        int ret;
@@ -858,6 +1068,7 @@ void delete_ust_app_session_rcu(struct rcu_head *head)
                caa_container_of(head, struct ust_app_session, rcu_head);
 
        ht_cleanup_push(ua_sess->channels);
+       ht_cleanup_push(ua_sess->maps);
        free(ua_sess);
 }
 
@@ -874,6 +1085,7 @@ void delete_ust_app_session(int sock, struct ust_app_session *ua_sess,
        int ret;
        struct lttng_ht_iter iter;
        struct ust_app_channel *ua_chan;
+       struct ust_app_map *ua_map;
        struct ust_registry_session *registry;
 
        assert(ua_sess);
@@ -908,6 +1120,16 @@ void delete_ust_app_session(int sock, struct ust_app_session *ua_sess,
                delete_ust_app_channel(sock, ua_chan, app);
        }
 
+       cds_lfht_for_each_entry(ua_sess->maps->ht, &iter.iter, ua_map,
+                       node.node) {
+               if (ua_sess->buffer_type == LTTNG_BUFFER_PER_PID) {
+                       copy_ust_app_map_values(sock, ua_map, app);
+               }
+               ret = lttng_ht_del(ua_sess->maps, &iter);
+               assert(!ret);
+               delete_ust_app_map(sock, ua_map, app);
+       }
+
        /* In case of per PID, the registry is kept in the session. */
        if (ua_sess->buffer_type == LTTNG_BUFFER_PER_PID) {
                struct buffer_reg_pid *reg_pid = buffer_reg_pid_find(ua_sess->id);
@@ -990,7 +1212,8 @@ void delete_ust_app(struct ust_app *app)
 
        ht_cleanup_push(app->sessions);
        ht_cleanup_push(app->ust_sessions_objd);
-       ht_cleanup_push(app->ust_objd);
+       ht_cleanup_push(app->ust_chan_objd);
+       ht_cleanup_push(app->ust_map_objd);
        ht_cleanup_push(app->token_to_event_notifier_rule_ht);
 
        /*
@@ -999,6 +1222,8 @@ void delete_ust_app(struct ust_app *app)
         */
        if (app->event_notifier_group.object) {
                enum lttng_error_code ret_code;
+               enum event_notifier_error_accounting_status status;
+
                const int event_notifier_read_fd = lttng_pipe_get_readfd(
                                app->event_notifier_group.event_pipe);
 
@@ -1009,6 +1234,11 @@ void delete_ust_app(struct ust_app *app)
                        ERR("Failed to remove application tracer event source from notification thread");
                }
 
+               status = event_notifier_error_accounting_unregister_app(app);
+               if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+                       ERR("Error unregistering app from event notifier error accounting");
+               }
+
                ustctl_release_object(sock, app->event_notifier_group.object);
                free(app->event_notifier_group.object);
        }
@@ -1110,6 +1340,7 @@ struct ust_app_session *alloc_ust_app_session(void)
        ua_sess->handle = -1;
        ua_sess->channels = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
        ua_sess->metadata_attr.type = LTTNG_UST_CHAN_METADATA;
+       ua_sess->maps = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
        pthread_mutex_init(&ua_sess->lock, NULL);
 
        return ua_sess;
@@ -1172,6 +1403,43 @@ error:
        return NULL;
 }
 
+/*
+ * Alloc new UST app map.
+ */
+static
+struct ust_app_map *alloc_ust_app_map(const char *name,
+               struct ust_app_session *ua_sess)
+{
+       struct ust_app_map *ua_map;
+
+       /* Init most of the default value by allocating and zeroing */
+       ua_map = zmalloc(sizeof(struct ust_app_map));
+       if (ua_map == NULL) {
+               PERROR("malloc");
+               goto error;
+       }
+
+       /* Setup map name */
+       strncpy(ua_map->name, name, sizeof(ua_map->name));
+       ua_map->name[sizeof(ua_map->name) - 1] = '\0';
+
+       ua_map->enabled = 1;
+       ua_map->handle = -1;
+       ua_map->session = ua_sess;
+       ua_map->key = get_next_map_key();
+       ua_map->events = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+       lttng_ht_node_init_str(&ua_map->node, ua_map->name);
+
+       CDS_INIT_LIST_HEAD(&ua_map->counters.head);
+
+       DBG3("UST app map %s allocated", ua_map->name);
+
+       return ua_map;
+
+error:
+       return NULL;
+}
+
 /*
  * Allocate and initialize a UST app stream.
  *
@@ -1194,6 +1462,28 @@ error:
        return stream;
 }
 
+/*
+ * Allocate and initialize a UST app map_counter.
+ *
+ * Return newly allocated map_counter pointer or NULL on error.
+ */
+struct ust_app_map_counter *ust_app_alloc_map_counter(void)
+{
+       struct ust_app_map_counter *map_counter = NULL;
+
+       map_counter = zmalloc(sizeof(*map_counter));
+       if (map_counter == NULL) {
+               PERROR("zmalloc ust app map_counter");
+               goto error;
+       }
+
+       /* Zero could be a valid value for a handle so flag it to -1. */
+       map_counter->handle = -1;
+
+error:
+       return map_counter;
+}
+
 /*
  * Alloc new UST app event.
  */
@@ -1228,6 +1518,7 @@ error:
        return NULL;
 }
 
+
 /*
  * Allocate a new UST app event notifier rule.
  */
@@ -1253,9 +1544,9 @@ static struct ust_app_event_notifier_rule *alloc_ust_app_event_notifier_rule(
 
        condition = lttng_trigger_get_condition(trigger);
        assert(condition);
-       assert(lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+       assert(lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_ON_EVENT);
 
-       assert(LTTNG_CONDITION_STATUS_OK == lttng_condition_event_rule_get_rule(condition, &event_rule));
+       assert(LTTNG_CONDITION_STATUS_OK == lttng_condition_on_event_get_rule(condition, &event_rule));
        assert(event_rule);
 
        /* Acquire the event notifier's reference to the trigger. */
@@ -1429,7 +1720,8 @@ error:
 static struct ust_app_event *find_ust_app_event(struct lttng_ht *ht,
                const char *name, const struct lttng_bytecode *filter,
                int loglevel_value,
-               const struct lttng_event_exclusion *exclusion)
+               const struct lttng_event_exclusion *exclusion,
+               uint64_t tracer_token)
 {
        struct lttng_ht_iter iter;
        struct lttng_ht_node_str *node;
@@ -1445,6 +1737,7 @@ static struct ust_app_event *find_ust_app_event(struct lttng_ht *ht,
        key.loglevel_type = loglevel_value;
        /* lttng_event_exclusion and lttng_ust_event_exclusion structures are similar */
        key.exclusion = exclusion;
+       key.tracer_token = tracer_token;
 
        /* Lookup using the event name as hash and a custom match fct. */
        cds_lfht_lookup(ht->ht, ht->hash_fct((void *) name, lttng_ht_seed),
@@ -1775,6 +2068,44 @@ error:
        return ret;
 }
 
+/*
+ * Disable the specified map on to UST tracer for the UST session.
+ */
+static int disable_ust_map(struct ust_app *app,
+               struct ust_app_session *ua_sess, struct ust_app_map *ua_map)
+{
+       int ret;
+
+       health_code_update();
+
+       pthread_mutex_lock(&app->sock_lock);
+       ret = ustctl_disable(app->sock, ua_map->obj);
+       pthread_mutex_unlock(&app->sock_lock);
+       if (ret < 0) {
+               if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("UST app map %s disable failed for app (pid: %d) "
+                                       "and session handle %d with ret %d",
+                                       ua_map->name, app->pid, ua_sess->handle, ret);
+               } else {
+                       /*
+                        * This is normal behavior, an application can die during the
+                        * creation process. Don't report an error so the execution can
+                        * continue normally.
+                        */
+                       ret = 0;
+                       DBG3("UST app disable map failed. Application is dead.");
+               }
+               goto error;
+       }
+
+       DBG2("UST app map %s disabled successfully for app (pid: %d)",
+                       ua_map->name, app->pid);
+
+error:
+       health_code_update();
+       return ret;
+}
+
 /*
  * Enable the specified channel on to UST tracer for the UST session.
  */
@@ -1815,6 +2146,46 @@ error:
        return ret;
 }
 
+/*
+ * Enable the specified map on to UST tracer for the UST session.
+ */
+static int enable_ust_map(struct ust_app *app,
+               struct ust_app_session *ua_sess, struct ust_app_map *ua_map)
+{
+       int ret;
+
+       health_code_update();
+
+       pthread_mutex_lock(&app->sock_lock);
+       ret = ustctl_enable(app->sock, ua_map->obj);
+       pthread_mutex_unlock(&app->sock_lock);
+       if (ret < 0) {
+               if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("UST app map %s enable failed for app (pid: %d) "
+                                       "and session handle %d with ret %d",
+                                       ua_map->name, app->pid, ua_sess->handle, ret);
+               } else {
+                       /*
+                        * This is normal behavior, an application can die during the
+                        * creation process. Don't report an error so the execution can
+                        * continue normally.
+                        */
+                       ret = 0;
+                       DBG3("UST app enable map failed. Application is dead.");
+               }
+               goto error;
+       }
+
+       ua_map->enabled = 1;
+
+       DBG2("UST app map %s enabled successfully for app (pid: %d)",
+                       ua_map->name, app->pid);
+
+error:
+       health_code_update();
+       return ret;
+}
+
 /*
  * Enable the specified event on to UST tracer for the UST session.
  */
@@ -1904,13 +2275,64 @@ error:
        return ret;
 }
 
+/*
+ * Send map and stream buffer to application.
+ *
+ * Return 0 on success. On error, a negative value is returned.
+ */
+static int send_map_pid_to_ust(struct ust_app *app,
+               struct ust_app_session *ua_sess, struct ust_app_map *ua_map)
+{
+       int ret;
+       struct ust_app_map_counter *counter, *ctmp;
+
+       assert(app);
+       assert(ua_sess);
+       assert(ua_map);
+
+       health_code_update();
+
+       DBG("UST app sending map %s to UST app sock %d", ua_map->name,
+                       app->sock);
+
+       /* Send map to the application. */
+       pthread_mutex_lock(&app->sock_lock);
+       ret = ustctl_send_counter_data_to_ust(app->sock,
+                       ua_sess->handle, ua_map->obj);
+       pthread_mutex_unlock(&app->sock_lock);
+       assert(ret == 0);
+
+       ua_map->handle = ua_map->obj->handle;
+
+       health_code_update();
+
+       /* Send all streams to application. */
+       cds_list_for_each_entry_safe(counter, ctmp, &ua_map->counters.head, list) {
+               pthread_mutex_lock(&app->sock_lock);
+               // Do send the per cpu counter here
+               ret = ustctl_send_counter_cpu_data_to_ust(app->sock,
+                               ua_map->obj, counter->obj);
+               pthread_mutex_unlock(&app->sock_lock);
+               assert(ret == 0);
+
+               /* We don't need the stream anymore once sent to the tracer. */
+               cds_list_del(&counter->list);
+               delete_ust_app_map_counter(-1, counter, app);
+       }
+       /* Flag the map that it is sent to the application. */
+       ua_map->is_sent = 1;
+
+       health_code_update();
+       return ret;
+}
+
 /*
  * Create the specified event onto the UST tracer for a UST session.
  *
  * Should be called with session mutex held.
  */
 static
-int create_ust_event(struct ust_app *app, struct ust_app_session *ua_sess,
+int create_ust_channel_event(struct ust_app *app, struct ust_app_session *ua_sess,
                struct ust_app_channel *ua_chan, struct ust_app_event *ua_event)
 {
        int ret = 0;
@@ -1995,13 +2417,173 @@ error:
        return ret;
 }
 
-static int init_ust_event_notifier_from_event_rule(
-               const struct lttng_event_rule *rule,
-               struct lttng_ust_event_notifier *event_notifier)
+static
+void add_key_token(struct lttng_ust_key_token *ust_key_token,
+               const struct lttng_map_key_token *key_token)
 {
-       enum lttng_event_rule_status status;
-       enum lttng_loglevel_type loglevel_type;
-       enum lttng_ust_loglevel_type ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
+       switch (key_token->type) {
+       case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
+       {
+               const struct lttng_map_key_token_string *str_token;
+               str_token = (typeof(str_token)) key_token;
+
+               ust_key_token->type = LTTNG_UST_KEY_TOKEN_STRING;
+               strncpy(ust_key_token->arg.string, str_token->string,
+                               LTTNG_UST_KEY_TOKEN_STRING_LEN_MAX);
+
+               break;
+       }
+       case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
+       {
+               const struct lttng_map_key_token_variable *var_token;
+               var_token = (typeof(var_token)) key_token;
+               switch (var_token->type) {
+               case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME:
+                       ust_key_token->type = LTTNG_UST_KEY_TOKEN_EVENT_NAME;
+                       break;
+               case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME:
+                       ust_key_token->type = LTTNG_UST_KEY_TOKEN_PROVIDER_NAME;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       default:
+               abort();
+       }
+}
+
+/*
+ * Create the specified event onto the UST tracer for a UST session.
+ *
+ * Should be called with session mutex held.
+ */
+static
+int create_ust_map_event(struct ust_app *app, struct ust_app_session *ua_sess,
+               struct ust_app_map *ua_map, const struct lttng_map_key *key,
+               struct ust_app_event *ua_event)
+{
+       int ret = 0;
+       unsigned int i, key_token_count;
+       enum lttng_map_key_status status;
+       struct lttng_ust_counter_event counter_event = {0};
+
+       health_code_update();
+
+       memcpy(&counter_event.event, &ua_event->attr, sizeof(struct lttng_ust_event));
+
+       status = lttng_map_key_get_token_count(key, &key_token_count);
+       if (status != LTTNG_MAP_KEY_STATUS_OK) {
+               ret = LTTNG_ERR_UNK;
+               goto error;
+       }
+
+       assert(key_token_count > 0);
+
+       counter_event.key.nr_dimensions = 1;
+       counter_event.key.key_dimensions[0].nr_key_tokens = key_token_count;
+
+       if (key_token_count > LTTNG_UST_NR_KEY_TOKEN) {
+               ERR("Too many key tokens for UST tracer: token count = %u token count max =%u",
+                       key_token_count, LTTNG_UST_NR_KEY_TOKEN);
+                       ret = LTTNG_ERR_INVALID;
+                       goto error;
+       }
+
+       for (i = 0; i < key_token_count; i++) {
+               const struct lttng_map_key_token *token =
+                               lttng_map_key_get_token_at_index(key, i);
+
+               add_key_token(&counter_event.key.key_dimensions[0].key_tokens[i],
+                               token);
+       }
+
+       /* Create UST event on tracer */
+       pthread_mutex_lock(&app->sock_lock);
+       ret = ustctl_counter_create_event(app->sock, &counter_event, ua_map->obj,
+                       &ua_event->obj);
+       pthread_mutex_unlock(&app->sock_lock);
+       if (ret < 0) {
+               if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       abort();
+                       ERR("Error ustctl counter create event %s for app pid: %d with ret %d",
+                                       ua_event->attr.name, app->pid, ret);
+               } else {
+                       /*
+                        * This is normal behavior, an application can die during the
+                        * creation process. Don't report an error so the execution can
+                        * continue normally.
+                        */
+                       ret = 0;
+                       DBG3("UST app counter create event failed. Application is dead.");
+               }
+               goto error;
+       }
+
+       ua_event->handle = ua_event->obj->handle;
+
+       DBG2("UST app map event %s created successfully for pid:%d object: %p",
+                       ua_event->attr.name, app->pid, ua_event->obj);
+
+       health_code_update();
+
+       /* Set filter if one is present. */
+       if (ua_event->filter) {
+               ret = set_ust_object_filter(app, ua_event->filter, ua_event->obj);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       /* Set exclusions for the event */
+       if (ua_event->exclusion) {
+               ret = set_ust_object_exclusions(app, ua_event->exclusion, ua_event->obj);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       /* If event not enabled, disable it on the tracer */
+       if (ua_event->enabled) {
+               /*
+                * We now need to explicitly enable the event, since it
+                * is now disabled at creation.
+                */
+               ret = enable_ust_object(app, ua_event->obj);
+               if (ret < 0) {
+                       /*
+                        * If we hit an EPERM, something is wrong with our enable call. If
+                        * we get an EEXIST, there is a problem on the tracer side since we
+                        * just created it.
+                        */
+                       switch (ret) {
+                       case -LTTNG_UST_ERR_PERM:
+                               /* Code flow problem */
+                               assert(0);
+                       case -LTTNG_UST_ERR_EXIST:
+                               /* It's OK for our use case. */
+                               ret = 0;
+                               break;
+                       default:
+                               break;
+                       }
+                       goto error;
+               }
+       }
+
+error:
+       health_code_update();
+       return ret;
+}
+
+static int init_ust_event_from_event_rule(
+               const struct lttng_event_rule *rule,
+               struct lttng_ust_event *event)
+{
+       enum lttng_event_rule_status status;
+       enum lttng_ust_loglevel_type ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
        int loglevel = -1, ret = 0;
        const char *pattern;
 
@@ -2009,8 +2591,6 @@ static int init_ust_event_notifier_from_event_rule(
        assert(lttng_event_rule_get_type(rule) ==
                        LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
 
-       memset(event_notifier, 0, sizeof(*event_notifier));
-
        if (lttng_event_rule_targets_agent_domain(rule)) {
                /*
                 * Special event for agents
@@ -2023,44 +2603,43 @@ static int init_ust_event_notifier_from_event_rule(
                loglevel = 0;
                ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
        } else {
-               status = lttng_event_rule_tracepoint_get_pattern(
-                               rule, &pattern);
-               if (status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       /* At this point, this is a fatal error. */
-                       abort();
-               }
+               const struct lttng_log_level_rule *log_level_rule;
 
-               status = lttng_event_rule_tracepoint_get_log_level_type(
-                               rule, &loglevel_type);
+               status = lttng_event_rule_tracepoint_get_pattern(rule, &pattern);
                if (status != LTTNG_EVENT_RULE_STATUS_OK) {
                        /* At this point, this is a fatal error. */
                        abort();
                }
 
-               switch (loglevel_type) {
-               case LTTNG_EVENT_LOGLEVEL_ALL:
+               status = lttng_event_rule_tracepoint_get_log_level_rule(
+                               rule, &log_level_rule);
+               if (status == LTTNG_EVENT_RULE_STATUS_UNSET) {
                        ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
-                       break;
-               case LTTNG_EVENT_LOGLEVEL_RANGE:
-                       ust_loglevel_type = LTTNG_UST_LOGLEVEL_RANGE;
-                       break;
-               case LTTNG_EVENT_LOGLEVEL_SINGLE:
-                       ust_loglevel_type = LTTNG_UST_LOGLEVEL_SINGLE;
-                       break;
-               default:
-                       /* Unknown log level specification type. */
-                       abort();
-               }
+               } else if (status == LTTNG_EVENT_RULE_STATUS_OK) {
+                       enum lttng_log_level_rule_status llr_status;
+
+                       switch (lttng_log_level_rule_get_type(log_level_rule)) {
+                       case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+                               ust_loglevel_type = LTTNG_UST_LOGLEVEL_SINGLE;
+                               llr_status = lttng_log_level_rule_exactly_get_level(log_level_rule, &loglevel);
+                               break;
+                       case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+                               ust_loglevel_type = LTTNG_UST_LOGLEVEL_RANGE;
+                               llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level(log_level_rule, &loglevel);
+                               break;
+                       default:
+                               abort();
+                       }
 
-               if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
-                       status = lttng_event_rule_tracepoint_get_log_level(
-                                       rule, &loglevel);
-                       assert(status == LTTNG_EVENT_RULE_STATUS_OK);
+                       assert(llr_status == LTTNG_LOG_LEVEL_RULE_STATUS_OK);
+               } else {
+                       /* At this point this is a fatal error */
+                       assert(0);
                }
        }
 
-       event_notifier->event.instrumentation = LTTNG_UST_TRACEPOINT;
-       ret = lttng_strncpy(event_notifier->event.name, pattern,
+       event->instrumentation = LTTNG_UST_TRACEPOINT;
+       ret = lttng_strncpy(event->name, pattern,
                        LTTNG_UST_SYM_NAME_LEN - 1);
        if (ret) {
                ERR("Failed to copy event rule pattern to notifier: pattern = '%s' ",
@@ -2068,8 +2647,8 @@ static int init_ust_event_notifier_from_event_rule(
                goto end;
        }
 
-       event_notifier->event.loglevel_type = ust_loglevel_type;
-       event_notifier->event.loglevel = loglevel;
+       event->loglevel_type = ust_loglevel_type;
+       event->loglevel = loglevel;
 end:
        return ret;
 }
@@ -2082,9 +2661,8 @@ static int create_ust_event_notifier(struct ust_app *app,
                struct ust_app_event_notifier_rule *ua_event_notifier_rule)
 {
        int ret = 0;
-       enum lttng_condition_status condition_status;
+       struct lttng_ust_event_notifier event_notifier = {0};
        const struct lttng_condition *condition = NULL;
-       struct lttng_ust_event_notifier event_notifier;
        const struct lttng_event_rule *event_rule = NULL;
        unsigned int capture_bytecode_count = 0, i;
        enum lttng_condition_status cond_status;
@@ -2095,15 +2673,15 @@ static int create_ust_event_notifier(struct ust_app *app,
        condition = lttng_trigger_get_const_condition(
                        ua_event_notifier_rule->trigger);
        assert(condition);
-       assert(lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+       assert(lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_ON_EVENT);
 
-       condition_status = lttng_condition_event_rule_get_rule(condition, &event_rule);
-       assert(condition_status == LTTNG_CONDITION_STATUS_OK);
+       lttng_condition_on_event_get_rule(condition, &event_rule);
        assert(event_rule);
        assert(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
 
-       init_ust_event_notifier_from_event_rule(event_rule, &event_notifier);
+       init_ust_event_from_event_rule(event_rule, &event_notifier.event);
        event_notifier.event.token = ua_event_notifier_rule->token;
+       event_notifier.error_counter_index = ua_event_notifier_rule->error_counter_index;
 
        /* Create UST event notifier against the tracer. */
        pthread_mutex_lock(&app->sock_lock);
@@ -2158,13 +2736,13 @@ static int create_ust_event_notifier(struct ust_app *app,
        }
 
        /* Set the capture bytecodes. */
-       cond_status = lttng_condition_event_rule_get_capture_descriptor_count(
+       cond_status = lttng_condition_on_event_get_capture_descriptor_count(
                        condition, &capture_bytecode_count);
        assert(cond_status == LTTNG_CONDITION_STATUS_OK);
 
        for (i = 0; i < capture_bytecode_count; i++) {
                const struct lttng_bytecode *capture_bytecode =
-                               lttng_condition_event_rule_get_capture_bytecode_at_index(
+                               lttng_condition_on_event_get_capture_bytecode_at_index(
                                                condition, i);
 
                ret = set_ust_capture(app, capture_bytecode, i,
@@ -2841,6 +3419,26 @@ error:
        return ret;
 }
 
+/*
+ * Lookup ust app map for session and disable it on the tracer side.
+ */
+static
+int disable_ust_app_map(struct ust_app_session *ua_sess,
+               struct ust_app_map *ua_map, struct ust_app *app)
+{
+       int ret;
+
+       ret = disable_ust_map(app, ua_sess, ua_map);
+       if (ret < 0) {
+               goto error;
+       }
+
+       ua_map->enabled = 0;
+
+error:
+       return ret;
+}
+
 /*
  * Lookup ust app channel for session and enable it on the tracer side. This
  * MUST be called with a RCU read side lock acquired.
@@ -2872,6 +3470,37 @@ error:
        return ret;
 }
 
+/*
+ * Lookup ust app map for session and enable it on the tracer side. This
+ * MUST be called with a RCU read side lock acquired.
+ */
+static int enable_ust_app_map(struct ust_app_session *ua_sess,
+               struct ltt_ust_map *umap, struct ust_app *app)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter;
+       struct lttng_ht_node_str *ua_map_node;
+       struct ust_app_map *ua_map;
+
+       lttng_ht_lookup(ua_sess->maps, (void *)umap->name, &iter);
+       ua_map_node = lttng_ht_iter_get_node_str(&iter);
+       if (ua_map_node == NULL) {
+               DBG2("Unable to find map %s in ust session id %" PRIu64,
+                               umap->name, ua_sess->tracing_id);
+               goto error;
+       }
+
+       ua_map = caa_container_of(ua_map_node, struct ust_app_map, node);
+
+       ret = enable_ust_map(app, ua_sess, ua_map);
+       if (ret < 0) {
+               goto error;
+       }
+
+error:
+       return ret;
+}
+
 /*
  * Ask the consumer to create a channel and get it if successful.
  *
@@ -2969,6 +3598,118 @@ error:
        return ret;
 }
 
+static int create_map_object(struct ltt_ust_session *usess,
+               struct ust_app_session *ua_sess, struct ust_app_map *ua_map)
+{
+       int i, ret, nr_counter_cpu;
+       struct ustctl_counter_dimension dimension[1] = {0};
+       struct ustctl_daemon_counter *daemon_counter;
+       struct lttng_ust_object_data **counter_cpus;
+       enum ustctl_counter_bitness bitness;
+       int *counter_cpu_fds;
+
+       assert(usess);
+       assert(ua_sess);
+       assert(ua_map);
+       assert(ua_map->bucket_count > 0);
+
+       DBG("Creating UST map \"%s\"", ua_map->name);
+
+       if (ua_map->bitness == LTTNG_MAP_BITNESS_32BITS) {
+               bitness = USTCTL_COUNTER_BITNESS_32;
+       } else {
+               bitness = USTCTL_COUNTER_BITNESS_64;
+       }
+
+       nr_counter_cpu = ustctl_get_nr_cpu_per_counter();
+       counter_cpu_fds = zmalloc(nr_counter_cpu * sizeof(*counter_cpu_fds));
+       if (!counter_cpu_fds) {
+               ret = -1;
+               goto end;
+       }
+
+       counter_cpus = zmalloc(nr_counter_cpu * sizeof(**counter_cpus));
+       if (!counter_cpus) {
+               ret = -1;
+               goto  free_cpu_fds;
+       }
+
+       /* Need one fd for each cpu counter of the map. */
+       ret = lttng_fd_get(LTTNG_FD_APPS, nr_counter_cpu);
+       if (ret < 0) {
+               ERR("Exhausted number of available FD upon create map");
+               goto free_cpu_counters;
+       }
+
+       for (i = 0; i < nr_counter_cpu; i++) {
+               counter_cpu_fds[i] = shm_create_anonymous("ust-map-counter");
+               if (counter_cpu_fds[i] < 0) {
+                       ERR("Error creating anonymous shared memory object");
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       dimension[0].size = ua_map->bucket_count;
+       dimension[0].has_underflow = false;
+       dimension[0].has_overflow = false;
+
+       daemon_counter = ustctl_create_counter(1, dimension, 0, -1,
+                       nr_counter_cpu, counter_cpu_fds,
+                       bitness,
+                       USTCTL_COUNTER_ARITHMETIC_MODULAR,
+                       USTCTL_COUNTER_ALLOC_PER_CPU,
+                       ua_map->coalesce_hits);
+       assert(daemon_counter);
+
+       DBG("Created daemon counter succesfully");
+
+       ua_map->map_handle = daemon_counter;
+
+       ret = ustctl_create_counter_data(daemon_counter, &ua_map->obj);
+       assert(ret == 0);
+       DBG("Created counter data succesfully");
+
+       for (i = 0; i < nr_counter_cpu; i++) {
+               struct ust_app_map_counter *counter;
+
+               /* Create UST counter */
+               counter = ust_app_alloc_map_counter();
+               if (counter == NULL) {
+                       ret = -ENOMEM;
+                       goto release_counters;
+               }
+
+               ret = ustctl_create_counter_cpu_data(daemon_counter, i,
+                               &counter->obj);
+               if (ret < 0) {
+                       ERR("Creating map counter cpu data");
+                       free(counter);
+                       goto error;
+               }
+
+               cds_list_add_tail(&counter->list, &ua_map->counters.head);
+               ua_map->counters.count++;
+
+               DBG2("UST app map counter %d created successfully",
+                               ua_map->counters.count);
+       }
+
+       ret = 0;
+       goto end;
+
+error:
+release_counters:
+       //TODO
+free_cpu_counters:
+       free(counter_cpus);
+
+free_cpu_fds:
+       free(counter_cpu_fds);
+end:
+       return ret;
+}
+
 /*
  * Duplicate the ust data object of the ust app stream and save it in the
  * buffer registry stream.
@@ -2983,7 +3724,7 @@ static int duplicate_stream_object(struct buffer_reg_stream *reg_stream,
        assert(reg_stream);
        assert(stream);
 
-       /* Reserve the amount of file descriptor we need. */
+       /* Duplicating a stream requires 2 new fds. Reserve them. */
        ret = lttng_fd_get(LTTNG_FD_APPS, 2);
        if (ret < 0) {
                ERR("Exhausted number of available FD upon duplicate stream");
@@ -3005,21 +3746,57 @@ error:
        return ret;
 }
 
+/*
+ * Duplicate the ust data object of the ust app map_counter and save it in the
+ * buffer registry map_counter.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int duplicate_map_counter_object(struct buffer_reg_map_counter *reg_map_counter,
+               struct ust_app_map_counter *map_counter)
+{
+       int ret;
+
+       assert(reg_map_counter);
+       assert(map_counter);
+
+       /* Duplicating a map_counter requires 2 new fds. Reserve them. */
+       ret = lttng_fd_get(LTTNG_FD_APPS, 2);
+       if (ret < 0) {
+               ERR("Exhausted number of available FD upon duplicate map_counter");
+               goto error;
+       }
+
+       /* Duplicate object for map_counter once the original is in the registry. */
+       ret = ustctl_duplicate_ust_object_data(&map_counter->obj,
+                       reg_map_counter->obj.ust);
+       if (ret < 0) {
+               ERR("Duplicate map_counter obj from %p to %p failed with ret %d",
+                               reg_map_counter->obj.ust, map_counter->obj, ret);
+               lttng_fd_put(LTTNG_FD_APPS, 2);
+               goto error;
+       }
+       map_counter->handle = map_counter->obj->handle;
+
+error:
+       return ret;
+}
+
 /*
  * Duplicate the ust data object of the ust app. channel and save it in the
  * buffer registry channel.
  *
  * Return 0 on success or else a negative value.
  */
-static int duplicate_channel_object(struct buffer_reg_channel *reg_chan,
+static int duplicate_channel_object(struct buffer_reg_channel *buf_reg_chan,
                struct ust_app_channel *ua_chan)
 {
        int ret;
 
-       assert(reg_chan);
+       assert(buf_reg_chan);
        assert(ua_chan);
 
-       /* Need two fds for the channel. */
+       /* Duplicating a channel requires 1 new fd. Reserve it. */
        ret = lttng_fd_get(LTTNG_FD_APPS, 1);
        if (ret < 0) {
                ERR("Exhausted number of available FD upon duplicate channel");
@@ -3027,10 +3804,10 @@ static int duplicate_channel_object(struct buffer_reg_channel *reg_chan,
        }
 
        /* Duplicate object for stream once the original is in the registry. */
-       ret = ustctl_duplicate_ust_object_data(&ua_chan->obj, reg_chan->obj.ust);
+       ret = ustctl_duplicate_ust_object_data(&ua_chan->obj, buf_reg_chan->obj.ust);
        if (ret < 0) {
                ERR("Duplicate channel obj from %p to %p failed with ret: %d",
-                               reg_chan->obj.ust, ua_chan->obj, ret);
+                               buf_reg_chan->obj.ust, ua_chan->obj, ret);
                goto error;
        }
        ua_chan->handle = ua_chan->obj->handle;
@@ -3044,22 +3821,60 @@ error_fd_get:
 }
 
 /*
- * For a given channel buffer registry, setup all streams of the given ust
- * application channel.
+ * Duplicate the ust data object of the ust app. map and save it in the
+ * buffer registry map.
  *
  * Return 0 on success or else a negative value.
  */
-static int setup_buffer_reg_streams(struct buffer_reg_channel *reg_chan,
-               struct ust_app_channel *ua_chan,
-               struct ust_app *app)
+static int duplicate_map_object(struct buffer_reg_map *buf_reg_map,
+               struct ust_app_map *ua_map)
 {
-       int ret = 0;
-       struct ust_app_stream *stream, *stmp;
+       int ret;
 
-       assert(reg_chan);
-       assert(ua_chan);
+       assert(buf_reg_map);
+       assert(ua_map);
 
-       DBG2("UST app setup buffer registry stream");
+       /* Duplicating a map requires 1 new fd. Reserve it. */
+       ret = lttng_fd_get(LTTNG_FD_APPS, 1);
+       if (ret < 0) {
+               ERR("Exhausted number of available FD upon duplicate map");
+               goto error_fd_get;
+       }
+
+       /* Duplicate object for stream once the original is in the registry. */
+       ret = ustctl_duplicate_ust_object_data(&ua_map->obj, buf_reg_map->obj.ust);
+       if (ret < 0) {
+               ERR("Duplicate map obj from %p to %p failed with ret: %d",
+                               buf_reg_map->obj.ust, ua_map->obj, ret);
+               goto error;
+       }
+       ua_map->handle = ua_map->obj->handle;
+
+       return 0;
+
+error:
+       lttng_fd_put(LTTNG_FD_APPS, 1);
+error_fd_get:
+       return ret;
+}
+
+/*
+ * For a given channel buffer registry, setup all streams of the given ust
+ * application channel.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int setup_buffer_reg_streams(struct buffer_reg_channel *buf_reg_chan,
+               struct ust_app_channel *ua_chan,
+               struct ust_app *app)
+{
+       int ret = 0;
+       struct ust_app_stream *stream, *stmp;
+
+       assert(buf_reg_chan);
+       assert(ua_chan);
+
+       DBG2("UST app setup buffer registry stream");
 
        /* Send all streams to application. */
        cds_list_for_each_entry_safe(stream, stmp, &ua_chan->streams.head, list) {
@@ -3076,7 +3891,7 @@ static int setup_buffer_reg_streams(struct buffer_reg_channel *reg_chan,
                 */
                reg_stream->obj.ust = stream->obj;
                stream->obj = NULL;
-               buffer_reg_stream_add(reg_stream, reg_chan);
+               buffer_reg_stream_add(reg_stream, buf_reg_chan);
 
                /* We don't need the streams anymore. */
                cds_list_del(&stream->list);
@@ -3087,6 +3902,50 @@ error:
        return ret;
 }
 
+/*
+ * For a given map buffer registry, setup all counters of the given ust
+ * application map.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int setup_buffer_reg_map_counters(struct buffer_reg_map *buf_reg_map,
+               struct ust_app_map *ua_map,
+               struct ust_app *app)
+{
+       int ret = 0;
+       struct ust_app_map_counter *counter, *stmp;
+
+       assert(buf_reg_map);
+       assert(ua_map);
+
+       DBG2("UST app setup buffer registry counter");
+
+       /* Send all counters to application. */
+       cds_list_for_each_entry_safe(counter, stmp, &ua_map->counters.head, list) {
+               struct buffer_reg_map_counter *reg_counter;
+
+               ret = buffer_reg_map_counter_create(&reg_counter);
+               if (ret < 0) {
+                       goto error;
+               }
+
+               /*
+                * Keep original pointer and nullify it in the counter so the delete
+                * counter call does not release the object.
+                */
+               reg_counter->obj.ust = counter->obj;
+               counter->obj = NULL;
+               buffer_reg_map_counter_add(reg_counter, buf_reg_map);
+
+               /* We don't need the counters anymore. */
+               cds_list_del(&counter->list);
+               delete_ust_app_map_counter(-1, counter, app);
+       }
+
+error:
+       return ret;
+}
+
 /*
  * Create a buffer registry channel for the given session registry and
  * application channel object. If regp pointer is valid, it's set with the
@@ -3099,7 +3958,7 @@ static int create_buffer_reg_channel(struct buffer_reg_session *reg_sess,
                struct ust_app_channel *ua_chan, struct buffer_reg_channel **regp)
 {
        int ret;
-       struct buffer_reg_channel *reg_chan = NULL;
+       struct buffer_reg_channel *buf_reg_chan = NULL;
 
        assert(reg_sess);
        assert(ua_chan);
@@ -3107,14 +3966,14 @@ static int create_buffer_reg_channel(struct buffer_reg_session *reg_sess,
        DBG2("UST app creating buffer registry channel for %s", ua_chan->name);
 
        /* Create buffer registry channel. */
-       ret = buffer_reg_channel_create(ua_chan->tracing_channel_id, &reg_chan);
+       ret = buffer_reg_channel_create(ua_chan->tracing_channel_id, &buf_reg_chan);
        if (ret < 0) {
                goto error_create;
        }
-       assert(reg_chan);
-       reg_chan->consumer_key = ua_chan->key;
-       reg_chan->subbuf_size = ua_chan->attr.subbuf_size;
-       reg_chan->num_subbuf = ua_chan->attr.num_subbuf;
+       assert(buf_reg_chan);
+       buf_reg_chan->consumer_key = ua_chan->key;
+       buf_reg_chan->subbuf_size = ua_chan->attr.subbuf_size;
+       buf_reg_chan->num_subbuf = ua_chan->attr.num_subbuf;
 
        /* Create and add a channel registry to session. */
        ret = ust_registry_channel_add(reg_sess->reg.ust,
@@ -3122,17 +3981,63 @@ static int create_buffer_reg_channel(struct buffer_reg_session *reg_sess,
        if (ret < 0) {
                goto error;
        }
-       buffer_reg_channel_add(reg_sess, reg_chan);
+       buffer_reg_channel_add(reg_sess, buf_reg_chan);
 
        if (regp) {
-               *regp = reg_chan;
+               *regp = buf_reg_chan;
        }
 
        return 0;
 
 error:
        /* Safe because the registry channel object was not added to any HT. */
-       buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST);
+       buffer_reg_channel_destroy(buf_reg_chan, LTTNG_DOMAIN_UST);
+error_create:
+       return ret;
+}
+
+/*
+ * Create a buffer registry map for the given session registry and
+ * application map object. If regp pointer is valid, it's set with the
+ * created object. Important, the created object is NOT added to the session
+ * registry hash table.
+ *
+ * Return 0 on success else a negative value.
+ */
+static int create_buffer_reg_map(struct buffer_reg_session *reg_sess,
+               struct ust_app_map *ua_map, struct buffer_reg_map **regp)
+{
+       int ret;
+       struct buffer_reg_map *buf_reg_map = NULL;
+
+       assert(reg_sess);
+       assert(ua_map);
+
+       DBG2("UST app creating buffer registry map for %s", ua_map->name);
+
+       /* Create buffer registry map. */
+       ret = buffer_reg_map_create(ua_map->tracing_map_id, &buf_reg_map);
+       if (ret < 0) {
+               goto error_create;
+       }
+       assert(buf_reg_map);
+
+       /* Create and add a map registry to session. */
+       ret = ust_registry_map_add(reg_sess->reg.ust, ua_map->tracing_map_id);
+       if (ret < 0) {
+               goto error;
+       }
+       buffer_reg_map_add(reg_sess, buf_reg_map);
+
+       if (regp) {
+               *regp = buf_reg_map;
+       }
+
+       return 0;
+
+error:
+       /* Safe because the registry map object was not added to any HT. */
+       buffer_reg_map_destroy(buf_reg_map, LTTNG_DOMAIN_UST);
 error_create:
        return ret;
 }
@@ -3144,32 +4049,70 @@ error_create:
  * Return 0 on success else a negative value.
  */
 static int setup_buffer_reg_channel(struct buffer_reg_session *reg_sess,
-               struct ust_app_channel *ua_chan, struct buffer_reg_channel *reg_chan,
+               struct ust_app_channel *ua_chan, struct buffer_reg_channel *buf_reg_chan,
                struct ust_app *app)
 {
        int ret;
 
        assert(reg_sess);
-       assert(reg_chan);
+       assert(buf_reg_chan);
        assert(ua_chan);
        assert(ua_chan->obj);
 
        DBG2("UST app setup buffer registry channel for %s", ua_chan->name);
 
        /* Setup all streams for the registry. */
-       ret = setup_buffer_reg_streams(reg_chan, ua_chan, app);
+       ret = setup_buffer_reg_streams(buf_reg_chan, ua_chan, app);
        if (ret < 0) {
                goto error;
        }
 
-       reg_chan->obj.ust = ua_chan->obj;
+       buf_reg_chan->obj.ust = ua_chan->obj;
        ua_chan->obj = NULL;
 
        return 0;
 
 error:
-       buffer_reg_channel_remove(reg_sess, reg_chan);
-       buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST);
+       buffer_reg_channel_remove(reg_sess, buf_reg_chan);
+       buffer_reg_channel_destroy(buf_reg_chan, LTTNG_DOMAIN_UST);
+       return ret;
+}
+
+/*
+ * Setup buffer registry map for the given session registry and application
+ * map object. If regp pointer is valid, it's set with the created object.
+ *
+ * Return 0 on success else a negative value.
+ */
+static int setup_buffer_reg_map(struct buffer_reg_session *reg_sess,
+               struct ust_app_map *ua_map, struct buffer_reg_map *buf_reg_map,
+               struct ust_app *app)
+{
+       int ret;
+
+       assert(reg_sess);
+       assert(buf_reg_map);
+       assert(ua_map);
+       assert(ua_map->obj);
+
+       DBG2("UST app setup buffer registry map for %s", ua_map->name);
+
+       /* Setup all counters for the registry. */
+       ret = setup_buffer_reg_map_counters(buf_reg_map, ua_map, app);
+       if (ret < 0) {
+               goto error;
+       }
+
+       buf_reg_map->obj.ust = ua_map->obj;
+       ua_map->obj = NULL;
+       buf_reg_map->daemon_counter = ua_map->map_handle;
+       ua_map->map_handle = NULL;
+
+       return 0;
+
+error:
+       buffer_reg_map_remove(reg_sess, buf_reg_map);
+       buffer_reg_map_destroy(buf_reg_map, LTTNG_DOMAIN_UST);
        return ret;
 }
 
@@ -3178,21 +4121,21 @@ error:
  *
  * Return 0 on success else a negative value.
  */
-static int send_channel_uid_to_ust(struct buffer_reg_channel *reg_chan,
+static int send_channel_uid_to_ust(struct buffer_reg_channel *buf_reg_chan,
                struct ust_app *app, struct ust_app_session *ua_sess,
                struct ust_app_channel *ua_chan)
 {
        int ret;
        struct buffer_reg_stream *reg_stream;
 
-       assert(reg_chan);
+       assert(buf_reg_chan);
        assert(app);
        assert(ua_sess);
        assert(ua_chan);
 
        DBG("UST app sending buffer registry channel to ust sock %d", app->sock);
 
-       ret = duplicate_channel_object(reg_chan, ua_chan);
+       ret = duplicate_channel_object(buf_reg_chan, ua_chan);
        if (ret < 0) {
                goto error;
        }
@@ -3209,8 +4152,8 @@ static int send_channel_uid_to_ust(struct buffer_reg_channel *reg_chan,
        health_code_update();
 
        /* Send all streams to application. */
-       pthread_mutex_lock(&reg_chan->stream_list_lock);
-       cds_list_for_each_entry(reg_stream, &reg_chan->streams, lnode) {
+       pthread_mutex_lock(&buf_reg_chan->stream_list_lock);
+       cds_list_for_each_entry(reg_stream, &buf_reg_chan->streams, lnode) {
                struct ust_app_stream stream;
 
                ret = duplicate_stream_object(reg_stream, &stream);
@@ -3236,7 +4179,87 @@ static int send_channel_uid_to_ust(struct buffer_reg_channel *reg_chan,
        ua_chan->is_sent = 1;
 
 error_stream_unlock:
-       pthread_mutex_unlock(&reg_chan->stream_list_lock);
+       pthread_mutex_unlock(&buf_reg_chan->stream_list_lock);
+error:
+       return ret;
+}
+
+/*
+ * Send buffer registry map to the application.
+ *
+ * Return 0 on success else a negative value.
+ */
+static int send_map_uid_to_ust(struct buffer_reg_map *buf_reg_map,
+               struct ust_app *app, struct ust_app_session *ua_sess,
+               struct ust_app_map *ua_map)
+{
+       int ret;
+       struct buffer_reg_map_counter *reg_map_counter;
+
+       assert(buf_reg_map);
+       assert(app);
+       assert(ua_sess);
+       assert(ua_map);
+
+       DBG("UST app sending buffer registry map to ust sock %d", app->sock);
+
+       ret = duplicate_map_object(buf_reg_map, ua_map);
+       if (ret < 0) {
+               goto error;
+       }
+
+       /* Send map to the application. */
+
+       pthread_mutex_lock(&app->sock_lock);
+       ret = ustctl_send_counter_data_to_ust(app->sock,
+                       ua_sess->handle, ua_map->obj);
+       pthread_mutex_unlock(&app->sock_lock);
+       assert(ret == 0);
+       if (ret < 0) {
+               if (ret == -EPIPE || ret == -LTTNG_UST_ERR_EXITING) {
+                       ret = -ENOTCONN; /* Caused by app exiting. */
+               }
+               goto error_map_counter_unlock;
+       }
+
+       ua_map->handle = ua_map->obj->handle;
+
+       health_code_update();
+
+       /* Send all map_counters to application. */
+       pthread_mutex_lock(&buf_reg_map->counter_list_lock);
+       cds_list_for_each_entry(reg_map_counter, &buf_reg_map->counters, lnode) {
+               struct ust_app_map_counter map_counter;
+
+               ret = duplicate_map_counter_object(reg_map_counter, &map_counter);
+               if (ret < 0) {
+                       goto error_map_counter_unlock;
+               }
+
+               pthread_mutex_lock(&app->sock_lock);
+               // Do send the per cpu counter here
+               ret = ustctl_send_counter_cpu_data_to_ust(app->sock,
+                               ua_map->obj, map_counter.obj);
+               pthread_mutex_unlock(&app->sock_lock);
+               assert(ret == 0);
+               if (ret < 0) {
+                       (void) release_ust_app_map_counter(-1, &map_counter, app);
+                       if (ret == -EPIPE || ret == -LTTNG_UST_ERR_EXITING) {
+                               ret = -ENOTCONN; /* Caused by app exiting. */
+                       }
+                       goto error_map_counter_unlock;
+               }
+
+               /*
+                * The return value is not important here. This function will
+                * output an error if needed.
+                */
+               (void) release_ust_app_map_counter(-1, &map_counter, app);
+       }
+       ua_map->is_sent = 1;
+
+error_map_counter_unlock:
+       pthread_mutex_unlock(&buf_reg_map->counter_list_lock);
 error:
        return ret;
 }
@@ -3255,10 +4278,10 @@ static int create_channel_per_uid(struct ust_app *app,
 {
        int ret;
        struct buffer_reg_uid *reg_uid;
-       struct buffer_reg_channel *reg_chan;
+       struct buffer_reg_channel *buf_reg_chan;
        struct ltt_session *session = NULL;
        enum lttng_error_code notification_ret;
-       struct ust_registry_channel *chan_reg;
+       struct ust_registry_channel *ust_reg_chan;
 
        assert(app);
        assert(usess);
@@ -3275,14 +4298,14 @@ static int create_channel_per_uid(struct ust_app *app,
         */
        assert(reg_uid);
 
-       reg_chan = buffer_reg_channel_find(ua_chan->tracing_channel_id,
+       buf_reg_chan = buffer_reg_channel_find(ua_chan->tracing_channel_id,
                        reg_uid);
-       if (reg_chan) {
+       if (buf_reg_chan) {
                goto send_channel;
        }
 
        /* Create the buffer registry channel object. */
-       ret = create_buffer_reg_channel(reg_uid->registry, ua_chan, &reg_chan);
+       ret = create_buffer_reg_channel(reg_uid->registry, ua_chan, &buf_reg_chan);
        if (ret < 0) {
                ERR("Error creating the UST channel \"%s\" registry instance",
                                ua_chan->name);
@@ -3311,8 +4334,8 @@ static int create_channel_per_uid(struct ust_app *app,
                 */
                ust_registry_channel_del_free(reg_uid->registry->reg.ust,
                                ua_chan->tracing_channel_id, false);
-               buffer_reg_channel_remove(reg_uid->registry, reg_chan);
-               buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST);
+               buffer_reg_channel_remove(reg_uid->registry, buf_reg_chan);
+               buffer_reg_channel_destroy(buf_reg_chan, LTTNG_DOMAIN_UST);
                goto error;
        }
 
@@ -3320,7 +4343,7 @@ static int create_channel_per_uid(struct ust_app *app,
         * Setup the streams and add it to the session registry.
         */
        ret = setup_buffer_reg_channel(reg_uid->registry,
-                       ua_chan, reg_chan, app);
+                       ua_chan, buf_reg_chan, app);
        if (ret < 0) {
                ERR("Error setting up UST channel \"%s\"", ua_chan->name);
                goto error;
@@ -3328,11 +4351,11 @@ static int create_channel_per_uid(struct ust_app *app,
 
        /* Notify the notification subsystem of the channel's creation. */
        pthread_mutex_lock(&reg_uid->registry->reg.ust->lock);
-       chan_reg = ust_registry_channel_find(reg_uid->registry->reg.ust,
+       ust_reg_chan = ust_registry_channel_find(reg_uid->registry->reg.ust,
                        ua_chan->tracing_channel_id);
-       assert(chan_reg);
-       chan_reg->consumer_key = ua_chan->key;
-       chan_reg = NULL;
+       assert(ust_reg_chan);
+       ust_reg_chan->consumer_key = ua_chan->key;
+       ust_reg_chan = NULL;
        pthread_mutex_unlock(&reg_uid->registry->reg.ust->lock);
 
        notification_ret = notification_thread_command_add_channel(
@@ -3350,7 +4373,7 @@ static int create_channel_per_uid(struct ust_app *app,
 
 send_channel:
        /* Send buffers to the application. */
-       ret = send_channel_uid_to_ust(reg_chan, app, ua_sess, ua_chan);
+       ret = send_channel_uid_to_ust(buf_reg_chan, app, ua_sess, ua_chan);
        if (ret < 0) {
                if (ret != -ENOTCONN) {
                        ERR("Error sending channel to application");
@@ -3365,6 +4388,142 @@ error:
        return ret;
 }
 
+/*
+ * Create and send to the application the created buffers with per UID buffers.
+ *
+ * This MUST be called with a RCU read side lock acquired.
+ * The session list lock and the session's lock must be acquired.
+ *
+ * Return 0 on success else a negative value.
+ */
+static int create_map_per_uid(struct ust_app *app,
+               struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+               struct ust_app_map *ua_map)
+{
+       int ret;
+       struct buffer_reg_uid *buffer_reg_uid;
+       struct buffer_reg_map *buffer_reg_map;
+       struct ltt_session *session = NULL;
+       struct ust_registry_map *ust_reg_map;
+
+       assert(app);
+       assert(usess);
+       assert(ua_sess);
+       assert(ua_map);
+
+       DBG("UST app creating map %s with per UID buffers", ua_map->name);
+
+       buffer_reg_uid = buffer_reg_uid_find(usess->id, app->bits_per_long, app->uid);
+       /*
+        * The session creation handles the creation of this global registry
+        * object. If none can be find, there is a code flow problem or a
+        * teardown race.
+        */
+       assert(buffer_reg_uid);
+
+       buffer_reg_map = buffer_reg_map_find(ua_map->tracing_map_id,
+                       buffer_reg_uid);
+       if (buffer_reg_map) {
+               goto send_map;
+       }
+
+       /* Create the buffer registry map object. */
+       ret = create_buffer_reg_map(buffer_reg_uid->registry, ua_map,
+                       &buffer_reg_map);
+       if (ret < 0) {
+               ERR("Error creating the UST map \"%s\" registry instance",
+                               ua_map->name);
+               goto error;
+       }
+
+       session = session_find_by_id(ua_sess->tracing_id);
+       assert(session);
+       assert(pthread_mutex_trylock(&session->lock));
+       assert(session_trylock_list());
+
+       /*
+        */
+       ret = create_map_object(usess, ua_sess, ua_map);
+       assert(ret == 0);
+       if (ret < 0) {
+               ERR("Error creating UST map object: map_name = \"%s\"", ua_map->name);
+               goto error;
+       }
+
+       /*
+        * Setup the streams and add it to the session registry.
+        */
+       ret = setup_buffer_reg_map(buffer_reg_uid->registry, ua_map,
+                       buffer_reg_map, app);
+       if (ret < 0) {
+               ERR("Error setting up UST map \"%s\"", ua_map->name);
+               goto error;
+       }
+
+       /* Notify the notification subsystem of the map's creation. */
+       pthread_mutex_lock(&buffer_reg_uid->registry->reg.ust->lock);
+       ust_reg_map = ust_registry_map_find(buffer_reg_uid->registry->reg.ust,
+                       ua_map->tracing_map_id);
+       assert(ust_reg_map);
+       ust_reg_map = NULL;
+       pthread_mutex_unlock(&buffer_reg_uid->registry->reg.ust->lock);
+
+send_map:
+       /* Send buffers to the application. */
+       ret = send_map_uid_to_ust(buffer_reg_map, app, ua_sess, ua_map);
+       if (ret < 0) {
+               if (ret != -ENOTCONN) {
+                       ERR("Error sending map to application");
+               }
+               goto error;
+       }
+
+error:
+       if (session) {
+               session_put(session);
+       }
+       return ret;
+}
+
+//static int destroy_map_per_uid(struct ust_app *app,
+//             struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+//             struct ust_app_map *ua_map)
+//{
+//     int ret;
+//     struct buffer_reg_uid *buffer_reg_uid;
+//     struct buffer_reg_map *buffer_reg_map;
+//
+//     assert(app);
+//     assert(usess);
+//     assert(ua_sess);
+//     assert(ua_map);
+//
+//     DBG("UST app destroy map %s with per UID buffers", ua_map->name);
+//
+//     buffer_reg_uid = buffer_reg_uid_find(usess->id, app->bits_per_long, app->uid);
+//     /*
+//      * The session creation handles the creation of this global registry
+//      * object. If none can be find, there is a code flow problem or a
+//      * teardown race.
+//      */
+//     assert(buffer_reg_uid);
+//
+//     buffer_reg_map = buffer_reg_map_find(ua_map->tracing_map_id,
+//                     buffer_reg_uid);
+//     if (!buffer_reg_map) {
+//             ERR("Can't find map in buffer registry: map-name = '%s', uid = %d",
+//                             ua_map->name, app->uid);
+//             ret = -1;
+//             goto end;
+//     }
+//
+//     buffer_reg_map_destroy(buffer_reg_map, LTTNG_DOMAIN_UST);
+//
+//     ret = 0;
+//end:
+//     return ret;
+//}
+
 /*
  * Create and send to the application the created buffers with per PID buffers.
  *
@@ -3382,7 +4541,7 @@ static int create_channel_per_pid(struct ust_app *app,
        enum lttng_error_code cmd_ret;
        struct ltt_session *session = NULL;
        uint64_t chan_reg_key;
-       struct ust_registry_channel *chan_reg;
+       struct ust_registry_channel *ust_reg_chan;
 
        assert(app);
        assert(usess);
@@ -3431,9 +4590,9 @@ static int create_channel_per_pid(struct ust_app *app,
 
        chan_reg_key = ua_chan->key;
        pthread_mutex_lock(&registry->lock);
-       chan_reg = ust_registry_channel_find(registry, chan_reg_key);
-       assert(chan_reg);
-       chan_reg->consumer_key = ua_chan->key;
+       ust_reg_chan = ust_registry_channel_find(registry, chan_reg_key);
+       assert(ust_reg_chan);
+       ust_reg_chan->consumer_key = ua_chan->key;
        pthread_mutex_unlock(&registry->lock);
 
        cmd_ret = notification_thread_command_add_channel(
@@ -3462,54 +4621,133 @@ error:
 }
 
 /*
- * From an already allocated ust app channel, create the channel buffers if
- * needed and send them to the application. This MUST be called with a RCU read
- * side lock acquired.
+ * Create and send to the application the created buffers with per PID buffers.
  *
  * Called with UST app session lock held.
+ * The session list lock and the session's lock must be acquired.
  *
- * Return 0 on success or else a negative value. Returns -ENOTCONN if
- * the application exited concurrently.
+ * Return 0 on success else a negative value.
  */
-static int ust_app_channel_send(struct ust_app *app,
+static int create_map_per_pid(struct ust_app *app,
                struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
-               struct ust_app_channel *ua_chan)
+               struct ust_app_map *ua_map)
 {
        int ret;
+       struct ust_registry_session *registry;
+       struct ltt_session *session = NULL;
+       uint64_t map_reg_key;
+       struct ust_registry_map *ust_reg_map;
 
        assert(app);
        assert(usess);
-       assert(usess->active);
        assert(ua_sess);
-       assert(ua_chan);
+       assert(ua_map);
 
-       /* Handle buffer type before sending the channel to the application. */
-       switch (usess->buffer_type) {
-       case LTTNG_BUFFER_PER_UID:
-       {
-               ret = create_channel_per_uid(app, usess, ua_sess, ua_chan);
-               if (ret < 0) {
-                       goto error;
-               }
-               break;
-       }
-       case LTTNG_BUFFER_PER_PID:
-       {
-               ret = create_channel_per_pid(app, usess, ua_sess, ua_chan);
-               if (ret < 0) {
-                       goto error;
-               }
-               break;
-       }
-       default:
-               assert(0);
-               ret = -EINVAL;
-               goto error;
-       }
+       DBG("UST app creating map %s with per PID buffers", ua_map->name);
 
-       /* Initialize ust objd object using the received handle and add it. */
-       lttng_ht_node_init_ulong(&ua_chan->ust_objd_node, ua_chan->handle);
-       lttng_ht_add_unique_ulong(app->ust_objd, &ua_chan->ust_objd_node);
+       rcu_read_lock();
+
+       registry = get_session_registry(ua_sess);
+       /* The UST app session lock is held, registry shall not be null. */
+       assert(registry);
+
+       /* Create and add a new map registry to session. */
+       ret = ust_registry_map_add(registry, ua_map->key);
+       if (ret < 0) {
+               ERR("Error creating the UST map \"%s\" registry instance",
+                       ua_map->name);
+               goto error;
+       }
+
+       session = session_find_by_id(ua_sess->tracing_id);
+       assert(session);
+
+       assert(pthread_mutex_trylock(&session->lock));
+       assert(session_trylock_list());
+
+       /* Create and get map. */
+       ret = create_map_object(usess, ua_sess, ua_map);
+       if (ret < 0) {
+               ERR("Error creating UST map object: map_name = \"%s\" ",
+                       ua_map->name);
+               goto error_remove_from_registry;
+       }
+
+       ret = send_map_pid_to_ust(app, ua_sess, ua_map);
+       if (ret < 0) {
+               if (ret != -ENOTCONN) {
+                       ERR("Error sending map to application");
+               }
+               goto error_remove_from_registry;
+       }
+
+       map_reg_key = ua_map->key;
+       pthread_mutex_lock(&registry->lock);
+       ust_reg_map = ust_registry_map_find(registry, map_reg_key);
+       assert(ust_reg_map);
+       pthread_mutex_unlock(&registry->lock);
+
+error_remove_from_registry:
+       if (ret) {
+               ust_registry_map_del_free(registry, ua_map->key);
+       }
+error:
+       rcu_read_unlock();
+       if (session) {
+               session_put(session);
+       }
+       return ret;
+}
+
+/*
+ * From an already allocated ust app channel, create the channel buffers if
+ * needed and send them to the application. This MUST be called with a RCU read
+ * side lock acquired.
+ *
+ * Called with UST app session lock held.
+ *
+ * Return 0 on success or else a negative value. Returns -ENOTCONN if
+ * the application exited concurrently.
+ */
+static int ust_app_channel_send(struct ust_app *app,
+               struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+               struct ust_app_channel *ua_chan)
+{
+       int ret;
+
+       assert(app);
+       assert(usess);
+       assert(usess->active);
+       assert(ua_sess);
+       assert(ua_chan);
+
+       /* Handle buffer type before sending the channel to the application. */
+       switch (usess->buffer_type) {
+       case LTTNG_BUFFER_PER_UID:
+       {
+               ret = create_channel_per_uid(app, usess, ua_sess, ua_chan);
+               if (ret < 0) {
+                       goto error;
+               }
+               break;
+       }
+       case LTTNG_BUFFER_PER_PID:
+       {
+               ret = create_channel_per_pid(app, usess, ua_sess, ua_chan);
+               if (ret < 0) {
+                       goto error;
+               }
+               break;
+       }
+       default:
+               assert(0);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* Initialize ust objd object using the received handle and add it. */
+       lttng_ht_node_init_ulong(&ua_chan->ust_objd_node, ua_chan->handle);
+       lttng_ht_add_unique_ulong(app->ust_chan_objd, &ua_chan->ust_objd_node);
 
        /* If channel is not enabled, disable it on the tracer */
        if (!ua_chan->enabled) {
@@ -3523,6 +4761,68 @@ error:
        return ret;
 }
 
+/*
+ * From an already allocated ust app map, create the map buffers if
+ * needed and send them to the application. This MUST be called with a RCU read
+ * side lock acquired.
+ *
+ * Called with UST app session lock held.
+ *
+ * Return 0 on success or else a negative value. Returns -ENOTCONN if
+ * the application exited concurrently.
+ */
+static int ust_app_map_send(struct ust_app *app,
+               struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+               struct ust_app_map *ua_map)
+{
+       int ret;
+
+       assert(app);
+       assert(usess);
+       assert(usess->active);
+       assert(ua_sess);
+       assert(ua_map);
+
+       /* Handle buffer type before sending the map to the application. */
+       switch (usess->buffer_type) {
+       case LTTNG_BUFFER_PER_UID:
+       {
+               ret = create_map_per_uid(app, usess, ua_sess, ua_map);
+               if (ret < 0) {
+                       goto error;
+               }
+               break;
+       }
+       case LTTNG_BUFFER_PER_PID:
+       {
+               ret = create_map_per_pid(app, usess, ua_sess, ua_map);
+               if (ret < 0) {
+                       goto error;
+               }
+               break;
+       }
+       default:
+               assert(0);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* Initialize ust objd object using the received handle and add it. */
+       lttng_ht_node_init_ulong(&ua_map->ust_objd_node, ua_map->handle);
+       lttng_ht_add_unique_ulong(app->ust_map_objd, &ua_map->ust_objd_node);
+
+       /* If map is not enabled, disable it on the tracer */
+       if (!ua_map->enabled) {
+               ret = disable_ust_map(app, ua_sess, ua_map);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+error:
+       return ret;
+}
+
 /*
  * Create UST app channel and return it through ua_chanp if not NULL.
  *
@@ -3573,6 +4873,63 @@ error:
        return ret;
 }
 
+/*
+ * Create UST app map and return it through ua_mapp if not NULL.
+ *
+ * Called with UST app session lock and RCU read-side lock held.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int ust_app_map_allocate(struct ust_app_session *ua_sess,
+               struct ltt_ust_map *umap,
+               enum lttng_ust_chan_type type, struct ltt_ust_session *usess,
+               struct ust_app_map **ua_mapp)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter;
+       struct lttng_ht_node_str *ua_map_node;
+       struct ust_app_map *ua_map;
+
+       DBG("Allocating map id = %"PRIu64, umap->id);
+
+       /* Lookup map in the ust app session */
+       lttng_ht_lookup(ua_sess->maps, (void *)umap->name, &iter);
+       ua_map_node = lttng_ht_iter_get_node_str(&iter);
+       if (ua_map_node != NULL) {
+               ua_map = caa_container_of(ua_map_node, struct ust_app_map, node);
+               goto end;
+       }
+
+       ua_map = alloc_ust_app_map(umap->name, ua_sess);
+       if (ua_map == NULL) {
+               /* Only malloc can fail here */
+               ret = -ENOMEM;
+               goto error;
+       }
+       //shadow_copy_map(ua_map, umap);
+       ua_map->tracing_map_id = umap->id;
+       ua_map->coalesce_hits = umap->coalesce_hits;
+       ua_map->dead_app_kv_values = &umap->dead_app_kv_values;
+       ua_map->bitness = umap->bitness;
+
+       /* Set map type. */
+       //ua_map->attr.type = type;
+       ua_map->bucket_count = umap->bucket_count;
+
+       /* Only add the map if successful on the tracer side. */
+       lttng_ht_add_unique_str(ua_sess->maps, &ua_map->node);
+end:
+       if (ua_mapp) {
+               *ua_mapp = ua_map;
+       }
+
+       /* Everything went well. */
+       return 0;
+
+error:
+       return ret;
+}
+
 /*
  * Create UST app event and create it on the tracer side.
  *
@@ -3580,7 +4937,7 @@ error:
  * Called with ust app session mutex held.
  */
 static
-int create_ust_app_event(struct ust_app_session *ua_sess,
+int create_ust_app_channel_event(struct ust_app_session *ua_sess,
                struct ust_app_channel *ua_chan, struct ltt_ust_event *uevent,
                struct ust_app *app)
 {
@@ -3596,7 +4953,7 @@ int create_ust_app_event(struct ust_app_session *ua_sess,
        shadow_copy_event(ua_event, uevent);
 
        /* Create it on the tracer side */
-       ret = create_ust_event(app, ua_sess, ua_chan, ua_event);
+       ret = create_ust_channel_event(app, ua_sess, ua_chan, ua_event);
        if (ret < 0) {
                /*
                 * Not found previously means that it does not exist on the
@@ -3614,7 +4971,7 @@ int create_ust_app_event(struct ust_app_session *ua_sess,
                goto error;
        }
 
-       add_unique_ust_app_event(ua_chan, ua_event);
+       add_unique_ust_app_event(ua_chan->events, ua_event);
 
        DBG2("UST app create event completed: app = '%s' (ppid: %d)",
                        app->name, app->ppid);
@@ -3628,6 +4985,86 @@ error:
        return ret;
 }
 
+/*
+ * Create UST app event and create it on the tracer side.
+ *
+ * Must be called with the RCU read side lock held.
+ * Called with ust app session mutex held.
+ */
+static
+int create_ust_app_map_event(struct ust_app_session *ua_sess,
+               struct ust_app_map *ua_map, struct ltt_ust_event *uevent,
+               struct ust_app *app)
+{
+       int ret = 0;
+       uint64_t map_reg_key;
+       struct ust_app_event *ua_event;
+       struct ust_registry_session *registry;
+
+       ua_event = alloc_ust_app_event(uevent->attr.name, &uevent->attr);
+       if (ua_event == NULL) {
+               /* Only failure mode of alloc_ust_app_event(). */
+               ret = -ENOMEM;
+               goto end;
+       }
+       shadow_copy_event(ua_event, uevent);
+
+       registry = get_session_registry(ua_sess);
+       if (!registry) {
+               DBG("Application session is being torn down. Abort event notify");
+               ret = 0;
+               goto error;
+       }
+
+       if (ua_sess->buffer_type == LTTNG_BUFFER_PER_UID) {
+               map_reg_key = ua_map->tracing_map_id;
+       } else {
+               map_reg_key = ua_map->key;
+       }
+
+       pthread_mutex_lock(&registry->lock);
+       ret = ust_registry_map_add_token_key_mapping(registry, map_reg_key,
+                       uevent->attr.token, uevent->key);
+       assert(ret == 0);
+       pthread_mutex_unlock(&registry->lock);
+
+       /* Create it on the tracer side */
+       ret = create_ust_map_event(app, ua_sess, ua_map, uevent->key, ua_event);
+       if (ret < 0) {
+               /*
+                * Not found previously means that it does not exist on the
+                * tracer. If the application reports that the event existed,
+                * it means there is a bug in the sessiond or lttng-ust
+                * (or corruption, etc.)
+                */
+               if (ret == -LTTNG_UST_ERR_EXIST) {
+                       ERR("Tracer for application reported that an event being created already existed: "
+                                       "event_name = \"%s\", pid = %d, ppid = %d, uid = %d, gid = %d",
+                                       uevent->attr.name,
+                                       app->pid, app->ppid, app->uid,
+                                       app->gid);
+               }
+
+               /*
+                * FIXME: frdeso: remove key from tokey->key mapping.
+                */
+               goto error;
+       }
+
+       add_unique_ust_app_event(ua_map->events, ua_event);
+
+       DBG2("UST app create event completed: app = '%s', tracer token = %"PRIu64" (ppid: %d)",
+                       app->name, uevent->attr.token, app->ppid);
+
+end:
+       return ret;
+
+error:
+       /* Valid. Calling here is already in a read side lock */
+       delete_ust_app_event(-1, ua_event, app);
+       return ret;
+}
+
 /*
  * Create UST app event notifier rule and create it on the tracer side.
  *
@@ -3672,12 +5109,12 @@ int create_ust_app_event_notifier_rule(struct lttng_trigger *trigger,
        DBG2("UST app create token event rule completed: app = '%s' (ppid: %d), token = %" PRIu64,
                        app->name, app->ppid, lttng_trigger_get_tracer_token(trigger));
 
-end:
-       return ret;
+       goto end;
 
 error:
        /* The RCU read side lock is already being held by the caller. */
        delete_ust_app_event_notifier_rule(-1, ua_event_notifier_rule, app);
+end:
        return ret;
 }
 
@@ -3885,7 +5322,8 @@ struct ust_app *ust_app_create(struct ust_register_msg *msg, int sock)
        lta->v_major = msg->major;
        lta->v_minor = msg->minor;
        lta->sessions = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
-       lta->ust_objd = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+       lta->ust_chan_objd = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+       lta->ust_map_objd = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
        lta->ust_sessions_objd = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
        lta->notify_sock = -1;
        lta->token_to_event_notifier_rule_ht = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
@@ -3992,6 +5430,7 @@ int ust_app_setup_event_notifier_group(struct ust_app *app)
        int event_pipe_write_fd;
        struct lttng_ust_object_data *event_notifier_group = NULL;
        enum lttng_error_code lttng_ret;
+       enum event_notifier_error_accounting_status event_notifier_error_accounting_status;
 
        assert(app);
 
@@ -4040,6 +5479,14 @@ int ust_app_setup_event_notifier_group(struct ust_app *app)
 
        /* Assign handle only when the complete setup is valid. */
        app->event_notifier_group.object = event_notifier_group;
+
+       event_notifier_error_accounting_status = event_notifier_error_accounting_register_app(app);
+       if (event_notifier_error_accounting_status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+               ERR("Failed to setup event notifier error accounting for app");
+               ret = -1;
+               goto error;
+       }
+
        return ret;
 
 error:
@@ -4575,24 +6022,27 @@ int ust_app_disable_channel_glb(struct ltt_ust_session *usess,
 }
 
 /*
- * For a specific UST session, enable the channel for all registered apps.
+ * For a specific UST session, disable the channel for all registered apps.
  */
-int ust_app_enable_channel_glb(struct ltt_ust_session *usess,
-               struct ltt_ust_channel *uchan)
+int ust_app_disable_map_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap)
 {
        int ret = 0;
        struct lttng_ht_iter iter;
+       struct lttng_ht_node_str *ua_map_node;
        struct ust_app *app;
        struct ust_app_session *ua_sess;
+       struct ust_app_map *ua_map;
 
        assert(usess->active);
-       DBG2("UST app enabling channel %s to global domain for session id %" PRIu64,
-                       uchan->name, usess->id);
+       DBG2("UST app disabling map %s from global domain for session id %" PRIu64,
+                       umap->name, usess->id);
 
        rcu_read_lock();
 
        /* For every registered applications */
        cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+               struct lttng_ht_iter uiter;
                if (!app->compatible) {
                        /*
                         * TODO: In time, we should notice the caller of this error by
@@ -4605,8 +6055,104 @@ int ust_app_enable_channel_glb(struct ltt_ust_session *usess,
                        continue;
                }
 
-               /* Enable channel onto application */
-               ret = enable_ust_app_channel(ua_sess, uchan, app);
+               /* Get map */
+               lttng_ht_lookup(ua_sess->maps, (void *)umap->name, &uiter);
+               ua_map_node = lttng_ht_iter_get_node_str(&uiter);
+               /* If the session if found for the app, the map must be there */
+               assert(ua_map_node);
+
+               ua_map = caa_container_of(ua_map_node, struct ust_app_map, node);
+               /* The map must not be already disabled */
+               assert(ua_map->enabled == 1);
+
+               /* Disable map onto application */
+               ret = disable_ust_app_map(ua_sess, ua_map, app);
+               if (ret < 0) {
+                       /* XXX: We might want to report this error at some point... */
+                       continue;
+               }
+       }
+
+       rcu_read_unlock();
+       return ret;
+}
+
+/*
+ * For a specific UST session, enable the channel for all registered apps.
+ */
+int ust_app_enable_channel_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_channel *uchan)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter;
+       struct ust_app *app;
+       struct ust_app_session *ua_sess;
+
+       assert(usess->active);
+       DBG2("UST app enabling channel %s to global domain for session id %" PRIu64,
+                       uchan->name, usess->id);
+
+       rcu_read_lock();
+
+       /* For every registered applications */
+       cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+               if (!app->compatible) {
+                       /*
+                        * TODO: In time, we should notice the caller of this error by
+                        * telling him that this is a version error.
+                        */
+                       continue;
+               }
+               ua_sess = lookup_session_by_app(usess, app);
+               if (ua_sess == NULL) {
+                       continue;
+               }
+
+               /* Enable channel onto application */
+               ret = enable_ust_app_channel(ua_sess, uchan, app);
+               if (ret < 0) {
+                       /* XXX: We might want to report this error at some point... */
+                       continue;
+               }
+       }
+
+       rcu_read_unlock();
+       return ret;
+}
+
+/*
+ * For a specific UST session, enable the map for all registered apps.
+ */
+int ust_app_enable_map_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter;
+       struct ust_app *app;
+       struct ust_app_session *ua_sess;
+
+       assert(usess->active);
+       DBG2("UST app enabling map %s to global domain for session id %" PRIu64,
+                       umap->name, usess->id);
+
+       rcu_read_lock();
+
+       /* For every registered applications */
+       cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+               if (!app->compatible) {
+                       /*
+                        * TODO: In time, we should notice the caller of this error by
+                        * telling him that this is a version error.
+                        */
+                       continue;
+               }
+               ua_sess = lookup_session_by_app(usess, app);
+               if (ua_sess == NULL) {
+                       continue;
+               }
+
+               /* Enable map onto application */
+               ret = enable_ust_app_map(ua_sess, umap, app);
                if (ret < 0) {
                        /* XXX: We might want to report this error at some point... */
                        continue;
@@ -4620,7 +6166,7 @@ int ust_app_enable_channel_glb(struct ltt_ust_session *usess,
 /*
  * Disable an event in a channel and for a specific session.
  */
-int ust_app_disable_event_glb(struct ltt_ust_session *usess,
+int ust_app_disable_channel_event_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent)
 {
        int ret = 0;
@@ -4665,7 +6211,7 @@ int ust_app_disable_event_glb(struct ltt_ust_session *usess,
 
                ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
                                uevent->filter, uevent->attr.loglevel,
-                               uevent->exclusion);
+                               uevent->exclusion, uevent->attr.token);
                if (ua_event == NULL) {
                        DBG2("Event %s not found in channel %s for app pid %d."
                                        "Skipping", uevent->attr.name, uchan->name, app->pid);
@@ -4683,6 +6229,72 @@ int ust_app_disable_event_glb(struct ltt_ust_session *usess,
        return ret;
 }
 
+/*
+ * Disable an event in a map and for a specific session.
+ */
+int ust_app_disable_map_event_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap, struct ltt_ust_event *uevent)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter, uiter;
+       struct lttng_ht_node_str *ua_map_node;
+       struct ust_app *app;
+       struct ust_app_session *ua_sess;
+       struct ust_app_map *ua_map;
+       struct ust_app_event *ua_event;
+
+       assert(usess->active);
+       DBG("UST app disabling event %s for all apps in map "
+                       "%s for session id %" PRIu64,
+                       uevent->attr.name, umap->name, usess->id);
+
+       rcu_read_lock();
+
+       /* For all registered applications */
+       cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+               if (!app->compatible) {
+                       /*
+                        * TODO: In time, we should notice the caller of this error by
+                        * telling him that this is a version error.
+                        */
+                       continue;
+               }
+               ua_sess = lookup_session_by_app(usess, app);
+               if (ua_sess == NULL) {
+                       /* Next app */
+                       continue;
+               }
+
+               /* Lookup map in the ust app session */
+               lttng_ht_lookup(ua_sess->maps, (void *)umap->name, &uiter);
+               ua_map_node = lttng_ht_iter_get_node_str(&uiter);
+               if (ua_map_node == NULL) {
+                       DBG2("map %s not found in session id %" PRIu64 " for app pid %d."
+                                       "Skipping", umap->name, usess->id, app->pid);
+                       continue;
+               }
+               ua_map = caa_container_of(ua_map_node, struct ust_app_map, node);
+
+               ua_event = find_ust_app_event(ua_map->events, uevent->attr.name,
+                               uevent->filter, uevent->attr.loglevel,
+                               uevent->exclusion, uevent->attr.token);
+               if (ua_event == NULL) {
+                       DBG2("Event %s not found in map %s for app pid %d."
+                                       "Skipping", uevent->attr.name, umap->name, app->pid);
+                       continue;
+               }
+
+               ret = disable_ust_app_event(ua_sess, ua_event, app);
+               if (ret < 0) {
+                       /* XXX: Report error someday... */
+                       continue;
+               }
+       }
+
+       rcu_read_unlock();
+       return ret;
+}
+
 /* The ua_sess lock must be held by the caller.  */
 static
 int ust_app_channel_create(struct ltt_ust_session *usess,
@@ -4759,10 +6371,67 @@ error:
        return ret;
 }
 
+/* The ua_sess lock must be held by the caller.  */
+static
+int ust_app_map_create(struct ltt_ust_session *usess,
+               struct ust_app_session *ua_sess,
+               struct ltt_ust_map *umap, struct ust_app *app,
+               struct ust_app_map **_ua_map)
+{
+       int ret = 0;
+       struct ust_app_map *ua_map = NULL;
+
+       assert(ua_sess);
+       ASSERT_LOCKED(ua_sess->lock);
+
+       /*
+        * Create map onto application and synchronize its
+        * configuration.
+        */
+       ret = ust_app_map_allocate(ua_sess, umap,
+               LTTNG_UST_CHAN_PER_CPU, usess,
+               &ua_map);
+       if (ret < 0) {
+               goto error;
+       }
+
+       ret = ust_app_map_send(app, usess, ua_sess, ua_map);
+       if (ret) {
+               goto error;
+       }
+
+error:
+       if (ret < 0) {
+               switch (ret) {
+               case -ENOTCONN:
+                       /*
+                        * The application's socket is not valid. Either a bad socket
+                        * or a timeout on it. We can't inform the caller that for a
+                        * specific app, the session failed so lets continue here.
+                        */
+                       ret = 0;        /* Not an error. */
+                       break;
+               case -ENOMEM:
+               default:
+                       break;
+               }
+       }
+
+       if (ret == 0 && _ua_map) {
+               /*
+                * Only return the application's map on success. Note
+                * that the map can still be part of the application's
+                * map hashtable on error.
+                */
+               *_ua_map = ua_map;
+       }
+       return ret;
+}
+
 /*
  * Enable event for a specific session and channel on the tracer.
  */
-int ust_app_enable_event_glb(struct ltt_ust_session *usess,
+int ust_app_enable_channel_event_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent)
 {
        int ret = 0;
@@ -4800,68 +6469,747 @@ int ust_app_enable_event_glb(struct ltt_ust_session *usess,
                        continue;
                }
 
-               pthread_mutex_lock(&ua_sess->lock);
+               pthread_mutex_lock(&ua_sess->lock);
+
+               if (ua_sess->deleted) {
+                       pthread_mutex_unlock(&ua_sess->lock);
+                       continue;
+               }
+
+               /* Lookup channel in the ust app session */
+               lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &uiter);
+               ua_chan_node = lttng_ht_iter_get_node_str(&uiter);
+               /*
+                * It is possible that the channel cannot be found is
+                * the channel/event creation occurs concurrently with
+                * an application exit.
+                */
+               if (!ua_chan_node) {
+                       pthread_mutex_unlock(&ua_sess->lock);
+                       continue;
+               }
+
+               ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+
+               /* Get event node */
+               ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
+                               uevent->filter, uevent->attr.loglevel, uevent->exclusion,
+                               uevent->attr.token);
+               if (ua_event == NULL) {
+                       DBG3("UST app enable event %s not found for app PID %d."
+                                       "Skipping app", uevent->attr.name, app->pid);
+                       goto next_app;
+               }
+
+               ret = enable_ust_app_event(ua_sess, ua_event, app);
+               if (ret < 0) {
+                       pthread_mutex_unlock(&ua_sess->lock);
+                       goto error;
+               }
+       next_app:
+               pthread_mutex_unlock(&ua_sess->lock);
+       }
+
+error:
+       rcu_read_unlock();
+       return ret;
+}
+
+/*
+ * Enable event for a specific session and map on the tracer.
+ */
+int ust_app_enable_map_event_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap, struct ltt_ust_event *uevent)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter, uiter;
+       struct lttng_ht_node_str *ua_map_node;
+       struct ust_app *app;
+       struct ust_app_session *ua_sess;
+       struct ust_app_map *ua_map;
+       struct ust_app_event *ua_event;
+
+       assert(usess->active);
+       DBG("UST app enabling event %s for all apps for session id %" PRIu64,
+                       uevent->attr.name, usess->id);
+
+       /*
+        * NOTE: At this point, this function is called only if the session and
+        * map passed are already created for all apps. and enabled on the
+        * tracer also.
+        */
+
+       rcu_read_lock();
+
+       /* For all registered applications */
+       cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+               if (!app->compatible) {
+                       /*
+                        * TODO: In time, we should notice the caller of this error by
+                        * telling him that this is a version error.
+                        */
+                       continue;
+               }
+               ua_sess = lookup_session_by_app(usess, app);
+               if (!ua_sess) {
+                       /* The application has problem or is probably dead. */
+                       continue;
+               }
+
+               pthread_mutex_lock(&ua_sess->lock);
+
+               if (ua_sess->deleted) {
+                       pthread_mutex_unlock(&ua_sess->lock);
+                       continue;
+               }
+
+               /* Lookup map in the ust app session */
+               lttng_ht_lookup(ua_sess->maps, (void *)umap->name, &uiter);
+               ua_map_node = lttng_ht_iter_get_node_str(&uiter);
+               /*
+                * It is possible that the map cannot be found is
+                * the map/event creation occurs concurrently with
+                * an application exit.
+                */
+               if (!ua_map_node) {
+                       pthread_mutex_unlock(&ua_sess->lock);
+                       continue;
+               }
+
+               ua_map = caa_container_of(ua_map_node, struct ust_app_map, node);
+
+               /* Get event node */
+               ua_event = find_ust_app_event(ua_map->events, uevent->attr.name,
+                               uevent->filter, uevent->attr.loglevel, uevent->exclusion,
+                               uevent->attr.token);
+               if (ua_event == NULL) {
+                       DBG3("UST app enable event %s not found for app PID %d."
+                                       "Skipping app", uevent->attr.name, app->pid);
+                       goto next_app;
+               }
+
+               ret = enable_ust_app_event(ua_sess, ua_event, app);
+               if (ret < 0) {
+                       pthread_mutex_unlock(&ua_sess->lock);
+                       goto error;
+               }
+       next_app:
+               pthread_mutex_unlock(&ua_sess->lock);
+       }
+
+error:
+       rcu_read_unlock();
+       return ret;
+}
+
+/*
+ * For a specific existing UST session and UST channel, creates the event for
+ * all registered apps.
+ */
+int ust_app_create_channel_event_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter, uiter;
+       struct lttng_ht_node_str *ua_chan_node;
+       struct ust_app *app;
+       struct ust_app_session *ua_sess;
+       struct ust_app_channel *ua_chan;
+
+       assert(usess->active);
+       DBG("UST app creating event %s for all apps for session id %" PRIu64,
+                       uevent->attr.name, usess->id);
+
+       rcu_read_lock();
+
+       /* For all registered applications */
+       cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+               if (!app->compatible) {
+                       /*
+                        * TODO: In time, we should notice the caller of this error by
+                        * telling him that this is a version error.
+                        */
+                       continue;
+               }
+               ua_sess = lookup_session_by_app(usess, app);
+               if (!ua_sess) {
+                       /* The application has problem or is probably dead. */
+                       continue;
+               }
+
+               pthread_mutex_lock(&ua_sess->lock);
+
+               if (ua_sess->deleted) {
+                       pthread_mutex_unlock(&ua_sess->lock);
+                       continue;
+               }
+
+               /* Lookup channel in the ust app session */
+               lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &uiter);
+               ua_chan_node = lttng_ht_iter_get_node_str(&uiter);
+               /* If the channel is not found, there is a code flow error */
+               assert(ua_chan_node);
+
+               ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+
+               ret = create_ust_app_channel_event(ua_sess, ua_chan, uevent, app);
+               pthread_mutex_unlock(&ua_sess->lock);
+               if (ret < 0) {
+                       if (ret != -LTTNG_UST_ERR_EXIST) {
+                               /* Possible value at this point: -ENOMEM. If so, we stop! */
+                               break;
+                       }
+                       DBG2("UST app event %s already exist on app PID %d",
+                                       uevent->attr.name, app->pid);
+                       continue;
+               }
+       }
+
+       rcu_read_unlock();
+       return ret;
+}
+
+static
+int snapshot_key_values(struct ustctl_daemon_counter *map_handle,
+               struct lttng_ht *key_to_bucket_index_ht, int cpu,
+               const char *key_filter, struct lttng_ht *values)
+{
+       int ret;
+       struct lttng_ht_iter key_iter;
+       struct ust_registry_map_index_ht_entry *map_index_entry;
+
+       /* Iterate over all the formated_key -> counter index */
+       cds_lfht_for_each_entry(key_to_bucket_index_ht->ht,
+               &key_iter.iter, map_index_entry, node.node) {
+               bool overflow = 0, underflow = 0;
+               int64_t local_value = 0;
+               size_t dimension_indexes[1] = {map_index_entry->index};
+
+               if (key_filter && strcmp(key_filter,
+                               map_index_entry->formated_key) != 0) {
+                       continue;
+               }
+
+               ret = ustctl_counter_read(map_handle,
+                       dimension_indexes, cpu, &local_value,
+                       &overflow, &underflow);
+               if (ret) {
+                       ERR("Error getting counter value from the tracer: key = '%s'",
+                               map_index_entry->formated_key);
+                       ret = -1;
+                       goto end;
+               }
+
+               map_add_or_increment_map_values(values,
+                               map_index_entry->formated_key, local_value,
+                               underflow, overflow);
+       }
+       ret = 0;
+end:
+       return ret;
+}
+
+static
+int ust_app_map_list_values_per_uid_with_bitness_and_cpu(
+               const struct ltt_ust_session *usess,
+               const struct ltt_ust_map *umap,
+               uint32_t app_bitness,
+               uint32_t cpu,
+               const char *key_filter,
+               struct lttng_ht *values)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter;
+       struct buffer_reg_uid *buf_reg_uid;
+       struct buffer_reg_map *buf_reg_map;
+       struct ust_registry_session *ust_reg_sess;
+       struct lttng_ht_node_u64 *ust_reg_map_node;
+       struct ust_registry_map *ust_reg_map;
+
+       buf_reg_uid = buffer_reg_uid_find(usess->id, app_bitness, usess->uid);
+       if (!buf_reg_uid) {
+               /*
+                * Buffer registry entry for uid not found. Probably no app for
+                * this UID at the moment.
+                */
+               DBG("No buffer registry entry found for uid: ust-sess-id = %"PRIu64", bitness = %"PRIu32", uid = %d",
+                               usess->id, app_bitness, usess->uid);
+               /*
+                * Not an error. Leave the key value pair unchanged and return.
+                */
+               ret = 0;
+               goto end;
+       }
+
+       buf_reg_map = buffer_reg_map_find(umap->id, buf_reg_uid);
+       if (!buf_reg_uid) {
+               ERR("Error getting per-uid map buffer registry entry: map-id = %"PRIu64,
+                               umap->id);
+               ret = -1;
+               goto end;
+       }
+
+       ust_reg_sess = buf_reg_uid->registry->reg.ust;
+
+       /* Get the ust_reg map object from the registry */
+       // FIXME: frdeso: This can be changed to ust_registry_map_find() right?
+
+       lttng_ht_lookup(ust_reg_sess->maps, (void *) &umap->id, &iter);
+       ust_reg_map_node = lttng_ht_iter_get_node_u64(&iter);
+       if (!ust_reg_map_node) {
+               ERR("Error getting per-uid map buffer registry entry: map-id = %"PRIu64,
+                               umap->id);
+               ret = -1;
+               goto end;
+       }
+       ust_reg_map = caa_container_of(ust_reg_map_node,
+                       struct ust_registry_map, node);
+
+       ret = snapshot_key_values(buf_reg_map->daemon_counter,
+                       ust_reg_map->key_string_to_bucket_index_ht,
+                       cpu, key_filter, values);
+       if (ret) {
+               abort();
+       }
+
+
+       ret = 0;
+end:
+       return ret;
+}
+
+static
+int ust_app_map_list_values_per_uid(const struct ltt_ust_session *usess,
+               const struct ltt_ust_map *umap,
+               const struct lttng_map_query *query,
+               struct lttng_map_content *map_content)
+{
+       int i, ret = 0;
+       enum lttng_map_query_status map_query_status;
+       const char *key_filter;
+       struct lttng_ht *values = NULL;
+       bool sum_cpus = lttng_map_query_get_config_sum_by_cpu(query);
+       enum lttng_map_query_config_buffer config_buffer;
+       enum lttng_map_query_config_cpu config_cpu;
+       int selected_cpu;
+
+       map_query_status = lttng_map_query_get_key_filter(query, &key_filter);
+       if (map_query_status == LTTNG_MAP_QUERY_STATUS_NONE) {
+               key_filter = NULL;
+       } else if (map_query_status != LTTNG_MAP_QUERY_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       config_cpu = lttng_map_query_get_config_cpu(query);
+       if (config_cpu == LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+               unsigned int count;
+               map_query_status = lttng_map_query_get_cpu_count(query, &count);
+               assert(map_query_status == LTTNG_MAP_QUERY_STATUS_OK);
+               assert(count == 1);
+
+               map_query_status = lttng_map_query_get_cpu_at_index(query, 0,
+                               &selected_cpu);
+               assert(map_query_status == LTTNG_MAP_QUERY_STATUS_OK);
+       }
+
+       config_buffer = lttng_map_query_get_config_buffer(query);
+       if (config_buffer == LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET) {
+               unsigned int count;
+               uid_t selected_uid;
+
+               map_query_status = lttng_map_query_get_uid_count(query, &count);
+               assert(map_query_status == LTTNG_MAP_QUERY_STATUS_OK);
+               assert(count == 1);
+
+               map_query_status = lttng_map_query_get_uid_at_index(query, 0,
+                               &selected_uid);
+               assert(map_query_status == LTTNG_MAP_QUERY_STATUS_OK);
+
+               if (selected_uid != usess->uid) {
+                       ret = 0;
+                       goto end;
+               }
+       }
+
+       if (sum_cpus) {
+               values = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+       }
+
+       for (i = 0; i < umap->nr_cpu; i++) {
+               if (config_cpu == LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+                       if (selected_cpu != i) {
+                               continue;
+                       }
+               }
+
+               if (!sum_cpus) {
+                       values = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+               }
+
+               ret = ust_app_map_list_values_per_uid_with_bitness_and_cpu(
+                               usess, umap, 32, i, key_filter,
+                               values);
+               if (ret) {
+                       abort();
+               }
+
+               ret = ust_app_map_list_values_per_uid_with_bitness_and_cpu(
+                               usess, umap, 64, i, key_filter,
+                               values);
+               if (ret) {
+                       abort();
+               }
+               if (!sum_cpus) {
+                       ret = map_new_content_section(map_content,
+                                       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID,
+                                       sum_cpus, usess->uid, i, values);
+                       if (ret) {
+                               abort();
+                       }
+
+                       lttng_ht_destroy(values);
+               }
+       }
+
+       if (sum_cpus) {
+               ret = map_new_content_section(map_content,
+                               LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID,
+                               sum_cpus, usess->uid, 0, values);
+               if (ret) {
+                       abort();
+               }
+               lttng_ht_destroy(values);
+       }
+
+end:
+       return ret;
+}
+
+static
+int append_dead_app_kv(struct ltt_ust_map *umap,
+               const char *key_filter,
+               struct lttng_map_content *map_content)
+{
+       int ret;
+       struct lttng_ht *dead_app_kv_ht;
+       struct map_kv_ht_entry *kv_entry;
+       struct lttng_ht_iter key_iter;
+
+       struct lttng_ht *values = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+
+       pthread_mutex_lock(&(umap->dead_app_kv_values.lock));
+
+       assert(umap->dead_app_kv_values.dead_app_kv_values_64bits);
+       dead_app_kv_ht = umap->dead_app_kv_values.dead_app_kv_values_64bits;
+
+       cds_lfht_for_each_entry(dead_app_kv_ht->ht, &key_iter.iter, kv_entry,
+                       node.node) {
+               if (key_filter && strcmp(key_filter, kv_entry->key) != 0) {
+                       continue;
+               }
+               map_add_or_increment_map_values(values, kv_entry->key,
+                               kv_entry->value, kv_entry->has_underflowed,
+                               kv_entry->has_overflowed);
+       }
+
+       assert(umap->dead_app_kv_values.dead_app_kv_values_32bits);
+
+       dead_app_kv_ht = umap->dead_app_kv_values.dead_app_kv_values_32bits;
+       cds_lfht_for_each_entry(dead_app_kv_ht->ht, &key_iter.iter, kv_entry,
+                       node.node) {
+               if (key_filter && strcmp(key_filter, kv_entry->key) != 0) {
+                       continue;
+               }
+               map_add_or_increment_map_values(values, kv_entry->key,
+                               kv_entry->value, kv_entry->has_underflowed,
+                               kv_entry->has_overflowed);
+       }
+
+       pthread_mutex_unlock(&umap->dead_app_kv_values.lock);
+
+       ret = map_new_content_section(map_content,
+                       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID_AGGREGATED,
+                       true, 0, 0, values);
+
+       lttng_ht_destroy(values);
+       if (ret) {
+               ERR("Error appending deadapp kv");
+               goto end;
+       }
+
+
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static
+int ust_app_map_list_values_per_pid_with_bitness_and_cpu(
+               const struct ltt_ust_session *usess,
+               struct ust_app *app,
+               struct ltt_ust_map *umap,
+               uint32_t app_bitness,
+               uint32_t cpu,
+               const char *key_filter,
+               struct lttng_ht *values)
+{
+       int ret = 0;
+
+       struct lttng_ht_iter map_iter;
+       struct lttng_ht_node_str *ua_map_node;
+       struct ust_app_map *ua_map;
+       struct ust_app_session *ua_sess;
+       struct ust_registry_session *ust_reg_sess;
+       struct ust_registry_map *ust_reg_map;
+
+       if (app->bits_per_long != app_bitness) {
+               ret = 0;
+               goto end;;
+       }
+
+       ua_sess = lookup_session_by_app(usess, app);
+       if (!ua_sess) {
+               /* Session not associated with this app. */
+               ret = 0;
+               goto end;;
+       }
+
+       ust_reg_sess = get_session_registry(ua_sess);
+       if (!ust_reg_sess) {
+               DBG("Application session is being torn down. Skip application.");
+               ret = 0;
+               goto end;;
+       }
+
+       /* Lookup map in the ust app session */
+       lttng_ht_lookup(ua_sess->maps, (void *)umap->name, &map_iter);
+       ua_map_node = lttng_ht_iter_get_node_str(&map_iter);
+
+       assert(ua_map_node != NULL);
+       ua_map = caa_container_of(ua_map_node, struct ust_app_map, node);
+
+       pthread_mutex_lock(&ust_reg_sess->lock);
+       ust_reg_map = ust_registry_map_find(ust_reg_sess, ua_map->key);
+       pthread_mutex_unlock(&ust_reg_sess->lock);
+       assert(ust_reg_map);
+
+       ret = snapshot_key_values(ua_map->map_handle,
+                       ust_reg_map->key_string_to_bucket_index_ht,
+                       cpu, key_filter, values);
+       if (ret) {
+               ERR("Error snapshoting the content of map");
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int ust_app_map_list_values_per_pid(const struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap,
+               const struct lttng_map_query *query,
+               struct lttng_map_content *map_content)
+{
+       enum lttng_map_query_status map_query_status;
+       const char *key_filter;
+       struct lttng_ht *values;
+       bool sum_cpus = lttng_map_query_get_config_sum_by_cpu(query);
+       bool sum_pids = lttng_map_query_get_config_sum_by_pid(query);
+       enum lttng_map_query_config_cpu config_cpu;
+       int selected_cpu, i, ret = 0;
+       struct lttng_ht_iter app_iter;
+       struct ust_app *app;
+
+       values = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+
+       map_query_status = lttng_map_query_get_key_filter(query, &key_filter);
+       if (map_query_status == LTTNG_MAP_QUERY_STATUS_NONE) {
+               key_filter = NULL;
+       } else if (map_query_status != LTTNG_MAP_QUERY_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       config_cpu = lttng_map_query_get_config_cpu(query);
+       if (config_cpu == LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+               unsigned int count;
+               map_query_status = lttng_map_query_get_cpu_count(query, &count);
+               assert(map_query_status == LTTNG_MAP_QUERY_STATUS_OK);
+               assert(count == 1);
+
+               map_query_status = lttng_map_query_get_cpu_at_index(query, 0,
+                               &selected_cpu);
+               assert(map_query_status == LTTNG_MAP_QUERY_STATUS_OK);
+       }
+
+       /* Sum all cpus and pids on the same table. */
+       if (sum_cpus && sum_pids) {
+               values = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+       }
+
+       if (!sum_cpus && sum_pids) {
+               /* Iterate over all currently registered apps. */
+               for (i = 0; i < umap->nr_cpu; i++) {
+                       values = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+                       cds_lfht_for_each_entry(ust_app_ht->ht, &app_iter.iter, app, pid_n.node) {
+                               ret = ust_app_map_list_values_per_pid_with_bitness_and_cpu(
+                                               usess, app, umap, 32, i, key_filter, values);
+                               if (ret) {
+                                       abort();
+                               }
+                               ret = ust_app_map_list_values_per_pid_with_bitness_and_cpu(
+                                               usess, app, umap, 64, i, key_filter, values);
+                               if (ret) {
+                                       abort();
+                               }
+                       }
+                       ret = map_new_content_section(map_content,
+                                       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID,
+                                       sum_cpus, app->pid, i, values);
+                       if (ret) {
+                               abort();
+                       }
+
+                       lttng_ht_destroy(values);
+               }
+       } else {
+               /* Iterate over all currently registered apps. */
+               cds_lfht_for_each_entry(ust_app_ht->ht, &app_iter.iter, app, pid_n.node) {
+
+                       if (sum_cpus && !sum_pids) {
+                               values = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+                       }
+
+                       for (i = 0; i < umap->nr_cpu; i++) {
+
+                               if (config_cpu == LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+                                       if (selected_cpu != i) {
+                                               continue;
+                                       }
+                               }
+
+                               if (!sum_cpus && !sum_pids) {
+                                       values = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+                               }
+
+                               ret = ust_app_map_list_values_per_pid_with_bitness_and_cpu(
+                                               usess, app, umap, 32, i, key_filter, values);
+                               if (ret) {
+                                       abort();
+                               }
+                               ret = ust_app_map_list_values_per_pid_with_bitness_and_cpu(
+                                               usess, app, umap, 64, i, key_filter, values);
+                               if (ret) {
+                                       abort();
+                               }
+
+                               if (!sum_cpus && !sum_pids) {
+                                       ret = map_new_content_section(map_content,
+                                                       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID,
+                                                       sum_cpus, app->pid, i, values);
+                                       if (ret) {
+                                               abort();
+                                       }
 
-               if (ua_sess->deleted) {
-                       pthread_mutex_unlock(&ua_sess->lock);
-                       continue;
+                                       lttng_ht_destroy(values);
+                               }
+                       }
+                       if (sum_cpus && !sum_pids) {
+                               ret = map_new_content_section(map_content,
+                                               LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID,
+                                               sum_cpus, app->pid, i, values);
+                               if (ret) {
+                                       abort();
+                               }
+
+                               lttng_ht_destroy(values);
+                       }
                }
+       }
 
-               /* Lookup channel in the ust app session */
-               lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &uiter);
-               ua_chan_node = lttng_ht_iter_get_node_str(&uiter);
-               /*
-                * It is possible that the channel cannot be found is
-                * the channel/event creation occurs concurrently with
-                * an application exit.
-                */
-               if (!ua_chan_node) {
-                       pthread_mutex_unlock(&ua_sess->lock);
-                       continue;
+       if (sum_cpus && sum_pids) {
+               ret = map_new_content_section(map_content,
+                       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID,
+                       sum_cpus, 0, 0, values);
+               if (ret) {
+                       abort();
                }
+               lttng_ht_destroy(values);
+       }
 
-               ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+       /* Append dead app aggregated key-value pairs. */
+       ret = append_dead_app_kv(umap, key_filter, map_content);
+       if (ret) {
+               ERR("Error appending values from dead apps map");
+               goto end;
+       }
 
-               /* Get event node */
-               ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
-                               uevent->filter, uevent->attr.loglevel, uevent->exclusion);
-               if (ua_event == NULL) {
-                       DBG3("UST app enable event %s not found for app PID %d."
-                                       "Skipping app", uevent->attr.name, app->pid);
-                       goto next_app;
-               }
+end:
+       return ret;
+}
 
-               ret = enable_ust_app_event(ua_sess, ua_event, app);
-               if (ret < 0) {
-                       pthread_mutex_unlock(&ua_sess->lock);
-                       goto error;
+int ust_app_map_list_values(const struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap,
+               const struct lttng_map_query *query,
+               struct lttng_map_content **map_content)
+{
+       int ret;
+       struct lttng_map_content *local_map_content = NULL;
+
+       local_map_content = lttng_map_content_create(usess->buffer_type);
+       if (!local_map_content) {
+               ERR("Error creating a map content list");
+               ret = -1;
+               goto end;
+       }
+       rcu_read_lock();
+       if (usess->buffer_type == LTTNG_BUFFER_PER_UID) {
+               ret = ust_app_map_list_values_per_uid(usess, umap, query,
+                               local_map_content);
+               if (ret) {
+                       ERR("Error adding per-uid map value");
+                       ret = -1;
+                       goto end;
+               }
+       } else {
+               ret = ust_app_map_list_values_per_pid(usess, umap, query,
+                               local_map_content);
+               if (ret) {
+                       ERR("Error adding per-pid map value");
+                       ret = -1;
+                       goto end;
                }
-       next_app:
-               pthread_mutex_unlock(&ua_sess->lock);
        }
-
-error:
+       *map_content = local_map_content;
+       local_map_content = NULL;
+       ret = 0;
+end:
        rcu_read_unlock();
+
+       lttng_map_content_destroy(local_map_content);
        return ret;
 }
 
 /*
- * For a specific existing UST session and UST channel, creates the event for
+ * For a specific existing UST session and UST map, creates the event for
  * all registered apps.
  */
-int ust_app_create_event_glb(struct ltt_ust_session *usess,
-               struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent)
+int ust_app_create_map_event_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap, struct ltt_ust_event *uevent)
 {
        int ret = 0;
        struct lttng_ht_iter iter, uiter;
-       struct lttng_ht_node_str *ua_chan_node;
+       struct lttng_ht_node_str *ua_map_node;
        struct ust_app *app;
        struct ust_app_session *ua_sess;
-       struct ust_app_channel *ua_chan;
+       struct ust_app_map *ua_map;
 
        assert(usess->active);
-       DBG("UST app creating event %s for all apps for session id %" PRIu64,
-                       uevent->attr.name, usess->id);
+       DBG("UST app creating event %s in map %s for all apps for session id %" PRIu64,
+                       uevent->attr.name, umap->name, usess->id);
 
        rcu_read_lock();
 
@@ -4887,15 +7235,16 @@ int ust_app_create_event_glb(struct ltt_ust_session *usess,
                        continue;
                }
 
-               /* Lookup channel in the ust app session */
-               lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &uiter);
-               ua_chan_node = lttng_ht_iter_get_node_str(&uiter);
-               /* If the channel is not found, there is a code flow error */
-               assert(ua_chan_node);
+               /* Lookup map in the ust app session */
+               lttng_ht_lookup(ua_sess->maps, (void *)umap->name, &uiter);
+               ua_map_node = lttng_ht_iter_get_node_str(&uiter);
+               /* If the map is not found, there is a code flow error */
+               assert(ua_map_node);
 
-               ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+               ua_map = caa_container_of(ua_map_node, struct ust_app_map, node);
 
-               ret = create_ust_app_event(ua_sess, ua_chan, uevent, app);
+               ret = create_ust_app_map_event(ua_sess, ua_map, uevent, app);
+               assert(!ret);
                pthread_mutex_unlock(&ua_sess->lock);
                if (ret < 0) {
                        if (ret != -LTTNG_UST_ERR_EXIST) {
@@ -5190,7 +7539,7 @@ int ust_app_flush_session(struct ltt_ust_session *usess)
                /* Flush all per UID buffers associated to that session. */
                cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
                        struct ust_registry_session *ust_session_reg;
-                       struct buffer_reg_channel *reg_chan;
+                       struct buffer_reg_channel *buf_reg_chan;
                        struct consumer_socket *socket;
 
                        /* Get consumer socket to use to push the metadata.*/
@@ -5202,13 +7551,13 @@ int ust_app_flush_session(struct ltt_ust_session *usess)
                        }
 
                        cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
-                                       reg_chan, node.node) {
+                                       buf_reg_chan, node.node) {
                                /*
                                 * The following call will print error values so the return
                                 * code is of little importance because whatever happens, we
                                 * have to try them all.
                                 */
-                               (void) consumer_flush_channel(socket, reg_chan->consumer_key);
+                               (void) consumer_flush_channel(socket, buf_reg_chan->consumer_key);
                        }
 
                        ust_session_reg = reg->registry->reg.ust;
@@ -5337,7 +7686,7 @@ int ust_app_clear_quiescent_session(struct ltt_ust_session *usess)
                 */
                cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
                        struct consumer_socket *socket;
-                       struct buffer_reg_channel *reg_chan;
+                       struct buffer_reg_channel *buf_reg_chan;
 
                        /* Get associated consumer socket.*/
                        socket = consumer_find_socket_by_bitness(
@@ -5351,7 +7700,7 @@ int ust_app_clear_quiescent_session(struct ltt_ust_session *usess)
                        }
 
                        cds_lfht_for_each_entry(reg->registry->channels->ht,
-                                       &iter.iter, reg_chan, node.node) {
+                                       &iter.iter, buf_reg_chan, node.node) {
                                /*
                                 * The following call will print error values so
                                 * the return code is of little importance
@@ -5359,7 +7708,7 @@ int ust_app_clear_quiescent_session(struct ltt_ust_session *usess)
                                 * all.
                                 */
                                (void) consumer_clear_quiescent_channel(socket,
-                                               reg_chan->consumer_key);
+                                               buf_reg_chan->consumer_key);
                        }
                }
                break;
@@ -5562,6 +7911,36 @@ end:
        return ret;
 }
 
+/* The ua_sess lock must be held by the caller. */
+static
+int find_or_create_ust_app_map(
+               struct ltt_ust_session *usess,
+               struct ust_app_session *ua_sess,
+               struct ust_app *app,
+               struct ltt_ust_map *umap,
+               struct ust_app_map **ua_map)
+{
+       int ret = 0;
+       struct lttng_ht_iter iter;
+       struct lttng_ht_node_str *ua_map_node;
+
+       lttng_ht_lookup(ua_sess->maps, (void *) umap->name, &iter);
+       ua_map_node = lttng_ht_iter_get_node_str(&iter);
+       if (ua_map_node) {
+               *ua_map = caa_container_of(ua_map_node,
+                       struct ust_app_map, node);
+               goto end;
+       }
+
+       DBG("UST map id = %"PRIu64" not found. Creating it.", umap->id);
+       ret = ust_app_map_create(usess, ua_sess, umap, app, ua_map);
+       if (ret) {
+               goto end;
+       }
+end:
+       return ret;
+}
+
 static
 int ust_app_channel_synchronize_event(struct ust_app_channel *ua_chan,
                struct ltt_ust_event *uevent, struct ust_app_session *ua_sess,
@@ -5571,9 +7950,11 @@ int ust_app_channel_synchronize_event(struct ust_app_channel *ua_chan,
        struct ust_app_event *ua_event = NULL;
 
        ua_event = find_ust_app_event(ua_chan->events, uevent->attr.name,
-               uevent->filter, uevent->attr.loglevel, uevent->exclusion);
+               uevent->filter, uevent->attr.loglevel, uevent->exclusion,
+               uevent->attr.token);
        if (!ua_event) {
-               ret = create_ust_app_event(ua_sess, ua_chan, uevent, app);
+               ret = create_ust_app_channel_event(ua_sess, ua_chan, uevent, app);
+
                if (ret < 0) {
                        goto end;
                }
@@ -5590,6 +7971,34 @@ end:
 }
 
 /* Called with RCU read-side lock held. */
+static
+int ust_app_map_synchronize_event(struct ust_app_map *ua_map,
+               struct ltt_ust_event *uevent, struct ust_app_session *ua_sess,
+               struct ust_app *app)
+{
+       int ret = 0;
+       struct ust_app_event *ua_event = NULL;
+
+       ua_event = find_ust_app_event(ua_map->events, uevent->attr.name,
+               uevent->filter, uevent->attr.loglevel, uevent->exclusion,
+               uevent->attr.token);
+       if (!ua_event) {
+               ret = create_ust_app_map_event(ua_sess, ua_map, uevent, app);
+               if (ret < 0) {
+                       goto end;
+               }
+       } else {
+               if (ua_event->enabled != uevent->enabled) {
+                       ret = uevent->enabled ?
+                               enable_ust_app_event(ua_sess, ua_event, app) :
+                               disable_ust_app_event(ua_sess, ua_event, app);
+               }
+       }
+
+end:
+       return ret;
+}
+
 static
 void ust_app_synchronize_event_notifier_rules(struct ust_app *app)
 {
@@ -5635,8 +8044,8 @@ void ust_app_synchronize_event_notifier_rules(struct ust_app *app)
        }
 
        for (i = 0; i < count; i++) {
-               struct lttng_condition *condition;
-               struct lttng_event_rule *event_rule;
+               const struct lttng_condition *condition;
+               const struct lttng_event_rule *event_rule;
                struct lttng_trigger *trigger;
                const struct ust_app_event_notifier_rule *looked_up_event_notifier_rule;
                enum lttng_condition_status condition_status;
@@ -5646,14 +8055,13 @@ void ust_app_synchronize_event_notifier_rules(struct ust_app *app)
                assert(trigger);
 
                token = lttng_trigger_get_tracer_token(trigger);
-               condition = lttng_trigger_get_condition(trigger);
+               condition = lttng_trigger_get_const_condition(trigger);
 
-               if (lttng_condition_get_type(condition) != LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
-                       /* Does not apply */
+               if (!lttng_trigger_needs_tracer_notifier(trigger)) {
                        continue;
                }
 
-               condition_status = lttng_condition_event_rule_borrow_rule_mutable(condition, &event_rule);
+               condition_status = lttng_condition_on_event_get_rule(condition, &event_rule);
                assert(condition_status == LTTNG_CONDITION_STATUS_OK);
 
                if (lttng_event_rule_get_domain_type(event_rule) == LTTNG_DOMAIN_KERNEL) {
@@ -5733,38 +8141,20 @@ end:
 }
 
 /*
- * The caller must ensure that the application is compatible and is tracked
- * by the process attribute trackers.
+ * Called with RCU read-side lock held.
  */
 static
-void ust_app_synchronize(struct ltt_ust_session *usess,
+void ust_app_synchronize_all_channels(struct ltt_ust_session *usess,
+               struct ust_app_session *ua_sess,
                struct ust_app *app)
 {
        int ret = 0;
        struct cds_lfht_iter uchan_iter;
        struct ltt_ust_channel *uchan;
-       struct ust_app_session *ua_sess = NULL;
-
-       /*
-        * The application's configuration should only be synchronized for
-        * active sessions.
-        */
-       assert(usess->active);
 
-       ret = find_or_create_ust_app_session(usess, app, &ua_sess, NULL);
-       if (ret < 0) {
-               /* Tracer is probably gone or ENOMEM. */
-               goto error;
-       }
+       assert(usess);
        assert(ua_sess);
-
-       pthread_mutex_lock(&ua_sess->lock);
-       if (ua_sess->deleted) {
-               pthread_mutex_unlock(&ua_sess->lock);
-               goto end;
-       }
-
-       rcu_read_lock();
+       assert(app);
 
        cds_lfht_for_each_entry(usess->domain_global.channels->ht, &uchan_iter,
                        uchan, node.node) {
@@ -5783,7 +8173,7 @@ void ust_app_synchronize(struct ltt_ust_session *usess,
                        app, uchan, &ua_chan);
                if (ret) {
                        /* Tracer is probably gone or ENOMEM. */
-                       goto error_unlock;
+                       goto end;
                }
 
                if (!ua_chan) {
@@ -5796,7 +8186,7 @@ void ust_app_synchronize(struct ltt_ust_session *usess,
                        ret = ust_app_channel_synchronize_event(ua_chan,
                                uevent, ua_sess, app);
                        if (ret) {
-                               goto error_unlock;
+                               goto end;
                        }
                }
 
@@ -5805,10 +8195,106 @@ void ust_app_synchronize(struct ltt_ust_session *usess,
                                enable_ust_app_channel(ua_sess, uchan, app) :
                                disable_ust_app_channel(ua_sess, ua_chan, app);
                        if (ret) {
-                               goto error_unlock;
+                               goto end;
+                       }
+               }
+       }
+end:
+       return;
+}
+
+/*
+ * Called with RCU read-side lock held.
+ */
+static
+void ust_app_synchronize_all_maps(struct ltt_ust_session *usess,
+               struct ust_app_session *ua_sess,
+               struct ust_app *app)
+{
+       int ret = 0;
+       struct cds_lfht_iter umap_iter;
+       struct ltt_ust_map *umap;
+
+       assert(usess);
+       assert(ua_sess);
+       assert(app);
+
+       cds_lfht_for_each_entry(usess->domain_global.maps->ht, &umap_iter,
+                       umap, node.node) {
+               struct ust_app_map *ua_map;
+               struct cds_lfht_iter uevent_iter;
+               struct ltt_ust_event *uevent;
+
+               DBG("Synchronizing UST map id = %"PRIu64, umap->id);
+
+               ret = find_or_create_ust_app_map(usess, ua_sess,
+                               app, umap, &ua_map);
+               if (ret) {
+                       /* Tracer is probably gone or ENOMEM. */
+                       goto end;
+               }
+
+               DBG("Synchronizing all events of UST map id = %"PRIu64, umap->id);
+               cds_lfht_for_each_entry(umap->events->ht, &uevent_iter, uevent,
+                               node.node) {
+                       ret = ust_app_map_synchronize_event(ua_map,
+                                       uevent, ua_sess, app);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               if (ua_map->enabled != umap->enabled) {
+                       if (umap->enabled) {
+                               DBG("Map disabled on the tracer side but shouldn't");
+                               ret = enable_ust_app_map(ua_sess, umap, app);
+                       } else {
+                               DBG("Map enabled on the tracer side but shouldn't");
+                               ret = disable_ust_app_map(ua_sess, ua_map, app);
+                       }
+                       if (ret) {
+                               goto end;
                        }
                }
        }
+end:
+       return;
+}
+
+/*
+ * The caller must ensure that the application is compatible and is tracked
+ * by the process attribute trackers.
+ */
+static
+void ust_app_synchronize(struct ltt_ust_session *usess,
+               struct ust_app *app)
+{
+       int ret = 0;
+       struct ust_app_session *ua_sess = NULL;
+
+       /*
+        * The application's configuration should only be synchronized for
+        * active sessions.
+        */
+       assert(usess->active);
+
+       ret = find_or_create_ust_app_session(usess, app, &ua_sess, NULL);
+       if (ret < 0) {
+               /* Tracer is probably gone or ENOMEM. */
+               goto error;
+       }
+       assert(ua_sess);
+
+
+       rcu_read_lock();
+
+       pthread_mutex_lock(&ua_sess->lock);
+       if (ua_sess->deleted) {
+               pthread_mutex_unlock(&ua_sess->lock);
+               goto end;
+       }
+       ust_app_synchronize_all_channels(usess, ua_sess, app);
+       ust_app_synchronize_all_maps(usess, ua_sess, app);
 
        /*
         * Create the metadata for the application. This returns gracefully if a
@@ -5941,6 +8427,20 @@ void ust_app_global_update_all_event_notifier_rules(void)
        rcu_read_unlock();
 }
 
+void ust_app_update_event_notifier_error_count(struct lttng_trigger *trigger)
+{
+       uint64_t error_count = 0;
+       enum event_notifier_error_accounting_status status;
+       struct lttng_condition *condition = lttng_trigger_get_condition(trigger);
+
+       status = event_notifier_error_accounting_get_count(trigger, &error_count);
+       if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
+               ERR("Error getting trigger error count.");
+       }
+
+       lttng_condition_on_event_set_error_count(condition, error_count);
+}
+
 /*
  * Add context to a specific channel for global UST domain.
  */
@@ -6070,34 +8570,61 @@ static struct ust_app_session *find_session_by_objd(struct ust_app *app,
        ua_sess = caa_container_of(node, struct ust_app_session, ust_objd_node);
 
 error:
-       return ua_sess;
+       return ua_sess;
+}
+
+/*
+ * Return a ust app channel object using the application object and the channel
+ * object descriptor has a key. If not found, NULL is returned. A RCU read side
+ * lock MUST be acquired before calling this function.
+ */
+static struct ust_app_channel *find_channel_by_objd(struct ust_app *app,
+               int objd)
+{
+       struct lttng_ht_node_ulong *node;
+       struct lttng_ht_iter iter;
+       struct ust_app_channel *ua_chan = NULL;
+
+       assert(app);
+
+       lttng_ht_lookup(app->ust_chan_objd, (void *)((unsigned long) objd), &iter);
+       node = lttng_ht_iter_get_node_ulong(&iter);
+       if (node == NULL) {
+               DBG2("UST app channel find by objd %d not found", objd);
+               goto error;
+       }
+
+       ua_chan = caa_container_of(node, struct ust_app_channel, ust_objd_node);
+
+error:
+       return ua_chan;
 }
 
 /*
- * Return a ust app channel object using the application object and the channel
+ * Return a ust app map object using the application object and the map
  * object descriptor has a key. If not found, NULL is returned. A RCU read side
  * lock MUST be acquired before calling this function.
  */
-static struct ust_app_channel *find_channel_by_objd(struct ust_app *app,
+static struct ust_app_map *find_map_by_objd(struct ust_app *app,
                int objd)
 {
        struct lttng_ht_node_ulong *node;
        struct lttng_ht_iter iter;
-       struct ust_app_channel *ua_chan = NULL;
+       struct ust_app_map *ua_map = NULL;
 
        assert(app);
 
-       lttng_ht_lookup(app->ust_objd, (void *)((unsigned long) objd), &iter);
+       lttng_ht_lookup(app->ust_map_objd, (void *)((unsigned long) objd), &iter);
        node = lttng_ht_iter_get_node_ulong(&iter);
        if (node == NULL) {
-               DBG2("UST app channel find by objd %d not found", objd);
+               DBG2("UST app map find by objd %d not found", objd);
                goto error;
        }
 
-       ua_chan = caa_container_of(node, struct ust_app_channel, ust_objd_node);
+       ua_map = caa_container_of(node, struct ust_app_map, ust_objd_node);
 
 error:
-       return ua_chan;
+       return ua_map;
 }
 
 /*
@@ -6119,7 +8646,7 @@ static int reply_ust_register_channel(int sock, int cobjd,
        struct ust_app_channel *ua_chan;
        struct ust_app_session *ua_sess;
        struct ust_registry_session *registry;
-       struct ust_registry_channel *chan_reg;
+       struct ust_registry_channel *ust_reg_chan;
 
        rcu_read_lock();
 
@@ -6160,30 +8687,30 @@ static int reply_ust_register_channel(int sock, int cobjd,
 
        pthread_mutex_lock(&registry->lock);
 
-       chan_reg = ust_registry_channel_find(registry, chan_reg_key);
-       assert(chan_reg);
+       ust_reg_chan = ust_registry_channel_find(registry, chan_reg_key);
+       assert(ust_reg_chan);
 
-       if (!chan_reg->register_done) {
+       if (!ust_reg_chan->register_done) {
                /*
                 * TODO: eventually use the registry event count for
                 * this channel to better guess header type for per-pid
                 * buffers.
                 */
                type = USTCTL_CHANNEL_HEADER_LARGE;
-               chan_reg->nr_ctx_fields = nr_fields;
-               chan_reg->ctx_fields = fields;
+               ust_reg_chan->nr_ctx_fields = nr_fields;
+               ust_reg_chan->ctx_fields = fields;
                fields = NULL;
-               chan_reg->header_type = type;
+               ust_reg_chan->header_type = type;
        } else {
                /* Get current already assigned values. */
-               type = chan_reg->header_type;
+               type = ust_reg_chan->header_type;
        }
        /* Channel id is set during the object creation. */
-       chan_id = chan_reg->chan_id;
+       chan_id = ust_reg_chan->chan_id;
 
        /* Append to metadata */
-       if (!chan_reg->metadata_dumped) {
-               ret_code = ust_metadata_channel_statedump(registry, chan_reg);
+       if (!ust_reg_chan->metadata_dumped) {
+               ret_code = ust_metadata_channel_statedump(registry, ust_reg_chan);
                if (ret_code) {
                        ERR("Error appending channel metadata (errno = %d)", ret_code);
                        goto reply;
@@ -6206,7 +8733,7 @@ reply:
        }
 
        /* This channel registry registration is completed. */
-       chan_reg->register_done = 1;
+       ust_reg_chan->register_done = 1;
 
 error:
        pthread_mutex_unlock(&registry->lock);
@@ -6216,45 +8743,21 @@ error_rcu_unlock:
        return ret;
 }
 
-/*
- * Add event to the UST channel registry. When the event is added to the
- * registry, the metadata is also created. Once done, this replies to the
- * application with the appropriate error code.
- *
- * The session UST registry lock is acquired in the function.
- *
- * On success 0 is returned else a negative value.
- */
-static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name,
+static int add_event_ust_chan_registry(int sock, struct ust_app *ua,
+               struct ust_app_channel *ua_chan, int sobjd, int cobjd, char *name,
                char *sig, size_t nr_fields, struct ustctl_field *fields,
                int loglevel_value, char *model_emf_uri)
 {
        int ret, ret_code;
        uint32_t event_id = 0;
        uint64_t chan_reg_key;
-       struct ust_app *app;
-       struct ust_app_channel *ua_chan;
        struct ust_app_session *ua_sess;
        struct ust_registry_session *registry;
-
-       rcu_read_lock();
-
-       /* Lookup application. If not found, there is a code flow error. */
-       app = find_app_by_notify_sock(sock);
-       if (!app) {
-               DBG("Application socket %d is being torn down. Abort event notify",
-                               sock);
-               ret = 0;
-               goto error_rcu_unlock;
-       }
-
-       /* Lookup channel by UST object descriptor. */
-       ua_chan = find_channel_by_objd(app, cobjd);
-       if (!ua_chan) {
-               DBG("Application channel is being torn down. Abort event notify");
-               ret = 0;
-               goto error_rcu_unlock;
-       }
+       /*
+        * The counter index is unused for channel events. It's only used for
+        * map events.
+        */
+       uint64_t counter_index = 0;
 
        assert(ua_chan->session);
        ua_sess = ua_chan->session;
@@ -6263,7 +8766,7 @@ static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name,
        if (!registry) {
                DBG("Application session is being torn down. Abort event notify");
                ret = 0;
-               goto error_rcu_unlock;
+               goto error;
        }
 
        if (ua_sess->buffer_type == LTTNG_BUFFER_PER_UID) {
@@ -6279,10 +8782,10 @@ static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name,
         * and model_emf_uri meaning any free are done inside it if needed. These
         * three variables MUST NOT be read/write after this.
         */
-       ret_code = ust_registry_create_event(registry, chan_reg_key,
+       ret_code = ust_registry_chan_create_event(registry, chan_reg_key,
                        sobjd, cobjd, name, sig, nr_fields, fields,
                        loglevel_value, model_emf_uri, ua_sess->buffer_type,
-                       &event_id, app);
+                       &event_id, ua);
        sig = NULL;
        fields = NULL;
        model_emf_uri = NULL;
@@ -6292,7 +8795,7 @@ static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name,
         * application can be notified. In case of an error, it's important not to
         * return a negative error or else the application will get closed.
         */
-       ret = ustctl_reply_register_event(sock, event_id, ret_code);
+       ret = ustctl_reply_register_event(sock, event_id, counter_index, ret_code);
        if (ret < 0) {
                if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
                        ERR("UST app reply event failed with ret %d", ret);
@@ -6311,11 +8814,148 @@ static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name,
 
 error:
        pthread_mutex_unlock(&registry->lock);
-error_rcu_unlock:
+       return ret;
+}
+
+static int add_event_ust_map_registry(int sock, struct ust_app *ua,
+               struct ust_app_map *ua_map, int sobjd, int cobjd, char *name,
+               char *sig, size_t nr_fields, struct ustctl_field *fields,
+               int loglevel_value, char *model_emf_uri, uint64_t tracer_token)
+{
+       int ret, ret_code;
+       uint64_t map_reg_key, counter_index;
+       struct ust_app_session *ua_sess;
+       struct ust_registry_session *registry;
+
+       assert(ua_map->session);
+       ua_sess = ua_map->session;
+
+       registry = get_session_registry(ua_sess);
+       if (!registry) {
+               DBG("Application session is being torn down. Abort event notify");
+               ret = 0;
+               goto error;
+       }
+
+       if (ua_sess->buffer_type == LTTNG_BUFFER_PER_UID) {
+               map_reg_key = ua_map->tracing_map_id;
+       } else {
+               map_reg_key = ua_map->key;
+       }
+
+       pthread_mutex_lock(&registry->lock);
+
+       /*
+        * From this point on, this call acquires the ownership of the sig, fields
+        * and model_emf_uri meaning any free are done inside it if needed. These
+        * three variables MUST NOT be read/write after this.
+        */
+       DBG("Registry_map_create_event on map=%"PRIu64" with token=%"PRIu64,
+                       map_reg_key, tracer_token);
+       ret_code = ust_registry_map_create_event(registry, map_reg_key,
+                       sobjd, cobjd, name, sig, nr_fields, fields,
+                       loglevel_value, model_emf_uri, ua_sess->buffer_type,
+                       tracer_token, &counter_index, ua);
+       assert(!ret_code);
+
+       sig = NULL;
+       fields = NULL;
+       model_emf_uri = NULL;
+
+       /*
+        * The return value is returned to ustctl so in case of an error, the
+        * application can be notified. In case of an error, it's important not to
+        * return a negative error or else the application will get closed.
+        */
+       ret = ustctl_reply_register_event(sock, counter_index, counter_index,
+                       ret_code);
+       if (ret < 0) {
+               if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+                       ERR("UST app reply event failed with ret %d", ret);
+               } else {
+                       DBG3("UST app reply event failed. Application died");
+               }
+               /*
+                * No need to wipe the create event since the application socket will
+                * get close on error hence cleaning up everything by itself.
+                */
+               goto error;
+       }
+
+       DBG3("UST registry map event %s with counter index %" PRIu64 " added successfully",
+                       name, counter_index);
+
+error:
+       pthread_mutex_unlock(&registry->lock);
+       return ret;
+}
+
+
+/*
+ * Add event to the UST channel registry. When the event is added to the
+ * registry, the metadata is also created. Once done, this replies to the
+ * application with the appropriate error code.
+ *
+ * The session UST registry lock is acquired in the function.
+ *
+ * On success 0 is returned else a negative value.
+ */
+static int add_event_ust_registry(int sock, int sobjd, int cobjd, char *name,
+               char *sig, size_t nr_fields, struct ustctl_field *fields,
+               int loglevel_value, char *model_emf_uri, uint64_t tracer_token)
+{
+       int ret;
+       struct ust_app *app;
+       struct ust_app_channel *ua_chan = NULL;
+       struct ust_app_map *ua_map = NULL;
+
+       rcu_read_lock();
+
+       /* Lookup application. If not found, there is a code flow error. */
+       app = find_app_by_notify_sock(sock);
+       if (!app) {
+               DBG("Application socket %d is being torn down. Abort event notify",
+                               sock);
+               ret = 0;
+               goto end;
+       }
+
+       /* Lookup channel by UST object descriptor. */
+       ua_chan = find_channel_by_objd(app, cobjd);
+       if (ua_chan) {
+               ret = add_event_ust_chan_registry(sock, app, ua_chan, sobjd, cobjd,
+                               name, sig, nr_fields, fields, loglevel_value,
+                               model_emf_uri);
+               if (ret) {
+                       ERR("Error adding channel event to registry: event_name = '%s'", name);
+               }
+               goto found;
+       }
+
+       /* Lookup map by UST object descriptor. */
+       ua_map = find_map_by_objd(app, cobjd);
+       if (ua_map) {
+               ret = add_event_ust_map_registry(sock, app, ua_map, sobjd, cobjd,
+                               name, sig, nr_fields, fields, loglevel_value,
+                               model_emf_uri, tracer_token);
+               if (ret) {
+                       ERR("Error adding map event to registry: event_name = '%s'", name);
+                       goto end;
+               }
+               goto found;
+       }
+
+       if (!ua_chan && !ua_map) {
+               DBG("Application event container is being torn down. Abort event notify");
+               ret = 0;
+               goto end;
+       }
+
+found:
+       ret = 0;
+
+end:
        rcu_read_unlock();
-       free(sig);
-       free(fields);
-       free(model_emf_uri);
        return ret;
 }
 
@@ -6431,13 +9071,14 @@ int ust_app_recv_notify(int sock)
                int sobjd, cobjd, loglevel_value;
                char name[LTTNG_UST_SYM_NAME_LEN], *sig, *model_emf_uri;
                size_t nr_fields;
+               uint64_t tracer_token = 0;
                struct ustctl_field *fields;
 
                DBG2("UST app ustctl register event received");
 
                ret = ustctl_recv_register_event(sock, &sobjd, &cobjd, name,
                                &loglevel_value, &sig, &nr_fields, &fields,
-                               &model_emf_uri);
+                               &model_emf_uri, &tracer_token);
                if (ret < 0) {
                        if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
                                ERR("UST app recv event failed with ret %d", ret);
@@ -6454,7 +9095,7 @@ int ust_app_recv_notify(int sock)
                 * to the this function.
                 */
                ret = add_event_ust_registry(sock, sobjd, cobjd, name, sig, nr_fields,
-                               fields, loglevel_value, model_emf_uri);
+                               fields, loglevel_value, model_emf_uri, tracer_token);
                if (ret < 0) {
                        goto error;
                }
@@ -6648,7 +9289,7 @@ enum lttng_error_code ust_app_snapshot_record(
                struct buffer_reg_uid *reg;
 
                cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
-                       struct buffer_reg_channel *reg_chan;
+                       struct buffer_reg_channel *buf_reg_chan;
                        struct consumer_socket *socket;
                        char pathname[PATH_MAX];
                        size_t consumer_path_offset = 0;
@@ -6685,9 +9326,9 @@ enum lttng_error_code ust_app_snapshot_record(
                        }
                        /* Add the UST default trace dir to path. */
                        cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
-                                       reg_chan, node.node) {
+                                       buf_reg_chan, node.node) {
                                status = consumer_snapshot_channel(socket,
-                                               reg_chan->consumer_key,
+                                               buf_reg_chan->consumer_key,
                                                output, 0, usess->uid,
                                                usess->gid, &trace_path[consumer_path_offset], wait,
                                                nb_packets_per_stream);
@@ -6815,19 +9456,19 @@ uint64_t ust_app_get_size_one_more_packet_per_stream(
                struct buffer_reg_uid *reg;
 
                cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
-                       struct buffer_reg_channel *reg_chan;
+                       struct buffer_reg_channel *buf_reg_chan;
 
                        rcu_read_lock();
                        cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
-                                       reg_chan, node.node) {
-                               if (cur_nr_packets >= reg_chan->num_subbuf) {
+                                       buf_reg_chan, node.node) {
+                               if (cur_nr_packets >= buf_reg_chan->num_subbuf) {
                                        /*
                                         * Don't take channel into account if we
                                         * already grab all its packets.
                                         */
                                        continue;
                                }
-                               tot_size += reg_chan->subbuf_size * reg_chan->stream_count;
+                               tot_size += buf_reg_chan->subbuf_size * buf_reg_chan->stream_count;
                        }
                        rcu_read_unlock();
                }
@@ -7051,7 +9692,7 @@ enum lttng_error_code ust_app_rotate_session(struct ltt_session *session)
                struct buffer_reg_uid *reg;
 
                cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
-                       struct buffer_reg_channel *reg_chan;
+                       struct buffer_reg_channel *buf_reg_chan;
                        struct consumer_socket *socket;
 
                        if (!reg->registry->reg.ust->metadata_key) {
@@ -7069,9 +9710,9 @@ enum lttng_error_code ust_app_rotate_session(struct ltt_session *session)
 
                        /* Rotate the data channels. */
                        cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
-                                       reg_chan, node.node) {
+                                       buf_reg_chan, node.node) {
                                ret = consumer_rotate_channel(socket,
-                                               reg_chan->consumer_key,
+                                               buf_reg_chan->consumer_key,
                                                usess->uid, usess->gid,
                                                usess->consumer,
                                                /* is_metadata_channel */ false);
@@ -7284,7 +9925,8 @@ error:
  *
  * Return LTTNG_OK on success or else an LTTng error code.
  */
-enum lttng_error_code ust_app_clear_session(struct ltt_session *session)
+static
+enum lttng_error_code ust_app_clear_session_channels(struct ltt_session *session)
 {
        int ret;
        enum lttng_error_code cmd_ret = LTTNG_OK;
@@ -7308,7 +9950,7 @@ enum lttng_error_code ust_app_clear_session(struct ltt_session *session)
                struct buffer_reg_uid *reg;
 
                cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) {
-                       struct buffer_reg_channel *reg_chan;
+                       struct buffer_reg_channel *buf_reg_chan;
                        struct consumer_socket *socket;
 
                        /* Get consumer socket to use to push the metadata.*/
@@ -7321,9 +9963,9 @@ enum lttng_error_code ust_app_clear_session(struct ltt_session *session)
 
                        /* Clear the data channels. */
                        cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
-                                       reg_chan, node.node) {
+                                       buf_reg_chan, node.node) {
                                ret = consumer_clear_channel(socket,
-                                               reg_chan->consumer_key);
+                                               buf_reg_chan->consumer_key);
                                if (ret < 0) {
                                        goto error;
                                }
@@ -7427,6 +10069,228 @@ end:
        return cmd_ret;
 }
 
+static
+enum lttng_error_code ust_app_clear_session_maps_per_uid(
+               struct ltt_ust_session *usess, struct ltt_ust_map *umap,
+               uint32_t app_bitness)
+{
+       struct lttng_ht_iter iter;
+       struct buffer_reg_uid *buf_reg_uid;
+       struct buffer_reg_map *buf_reg_map;
+       struct ust_registry_session *ust_reg_sess;
+       struct lttng_ht_node_u64 *ust_reg_map_node;
+       struct ust_registry_map *ust_reg_map;
+       struct ust_registry_map_index_ht_entry *map_index_entry;
+       enum lttng_error_code status;
+
+       buf_reg_uid = buffer_reg_uid_find(usess->id, app_bitness, usess->uid);
+       if (!buf_reg_uid) {
+               /*
+                * Buffer registry entry for uid not found. Probably no app for
+                * this UID at the moment.
+                */
+               DBG("No buffer registry entry found for uid: ust-sess-id = %"PRIu64", bitness = %"PRIu32", uid = %d",
+                               usess->id, app_bitness, usess->uid);
+               /*
+                * Not an error. Leave the key value pair unchanged and return.
+                */
+               status = LTTNG_OK;
+               goto end;
+       }
+
+       buf_reg_map = buffer_reg_map_find(umap->id, buf_reg_uid);
+       if (!buf_reg_uid) {
+               ERR("Error getting per-uid map buffer registry entry: map-id = %"PRIu64,
+                               umap->id);
+               status = LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       ust_reg_sess = buf_reg_uid->registry->reg.ust;
+
+       /* Get the ust_reg map object from the registry */
+       // FIXME: frdeso: This can be changed to ust_registry_map_find() right?
+
+       lttng_ht_lookup(ust_reg_sess->maps, (void *) &umap->id, &iter);
+       ust_reg_map_node = lttng_ht_iter_get_node_u64(&iter);
+       if (!ust_reg_map_node) {
+               ERR("Error getting per-uid map buffer registry entry: map-id = %"PRIu64,
+                               umap->id);
+               status = LTTNG_ERR_UNK;
+               goto end;
+       }
+       ust_reg_map = caa_container_of(ust_reg_map_node,
+                       struct ust_registry_map, node);
+
+       cds_lfht_for_each_entry(ust_reg_map->key_string_to_bucket_index_ht->ht,
+                       &iter.iter, map_index_entry, node.node) {
+               int ret;
+               size_t dimension_indexes[1] = {map_index_entry->index};
+
+               ret = ustctl_counter_clear(buf_reg_map->daemon_counter, dimension_indexes);
+               if (ret) {
+                       ERR("clearing counter index %"PRIu64, map_index_entry->index);
+                       //fixme: frdeso: convert ust errors to tools errors
+                       status = LTTNG_ERR_UNK;
+                       goto end;
+               }
+       }
+
+       status = LTTNG_OK;
+
+end:
+       return status;
+}
+
+static
+enum lttng_error_code ust_app_clear_session_maps_per_pid(
+               struct ltt_ust_session *usess, struct ltt_ust_map *umap,
+               uint32_t app_bitness)
+{
+       struct lttng_ht_iter app_iter;
+       enum lttng_error_code status;
+       struct ust_app *app;
+       struct map_kv_ht_entry *kv_entry;
+       struct lttng_ht_iter iter;
+
+       cds_lfht_for_each_entry(ust_app_ht->ht, &app_iter.iter, app, pid_n.node) {
+               struct lttng_ht_iter map_iter, key_iter;
+               struct lttng_ht_node_str *ua_map_node;
+               struct ust_app_map *ua_map;
+               struct ust_app_session *ua_sess;
+               struct ust_registry_session *ust_reg_sess;
+               struct ust_registry_map *ust_reg_map;
+               struct ust_registry_map_index_ht_entry *map_index_entry;
+
+               if (app->bits_per_long != app_bitness) {
+                       continue;
+               }
+
+               ua_sess = lookup_session_by_app(usess, app);
+               if (!ua_sess) {
+                       /* Session not associated with this app. */
+                       continue;
+               }
+
+               ust_reg_sess = get_session_registry(ua_sess);
+               if (!ust_reg_sess) {
+                       DBG("Application session is being torn down. Skip application.");
+                       continue;
+               }
+
+               /* Lookup map in the ust app session */
+               lttng_ht_lookup(ua_sess->maps, (void *)umap->name, &map_iter);
+               ua_map_node = lttng_ht_iter_get_node_str(&map_iter);
+
+               assert(ua_map_node != NULL);
+               ua_map = caa_container_of(ua_map_node, struct ust_app_map, node);
+
+               pthread_mutex_lock(&ust_reg_sess->lock);
+               ust_reg_map = ust_registry_map_find(ust_reg_sess, ua_map->key);
+               pthread_mutex_unlock(&ust_reg_sess->lock);
+               assert(ust_reg_map);
+
+               /* Iterate over all the formated_key -> counter index */
+               cds_lfht_for_each_entry(ust_reg_map->key_string_to_bucket_index_ht->ht,
+                               &key_iter.iter, map_index_entry, node.node) {
+
+                       int ret;
+                       size_t dimension_indexes[1] = {map_index_entry->index};
+
+                       ret = ustctl_counter_clear(ua_map->map_handle,
+                                       dimension_indexes);
+                       if (ret) {
+                               ERR("clearing counter index %"PRIu64, map_index_entry->index);
+                               //fixme: frdeso: convert ust errors to tools errors
+                               status = LTTNG_ERR_UNK;
+                               goto end;
+                       }
+               }
+       }
+
+       /*
+        * Emptying the dead app key values.
+        */
+       pthread_mutex_lock(&umap->dead_app_kv_values.lock);
+
+       if (app_bitness == 32) {
+               cds_lfht_for_each_entry(umap->dead_app_kv_values.dead_app_kv_values_32bits->ht,
+                               &iter.iter, kv_entry, node.node) {
+                       kv_entry->value = 0;
+               }
+       } else {
+
+               cds_lfht_for_each_entry(umap->dead_app_kv_values.dead_app_kv_values_64bits->ht,
+                               &iter.iter, kv_entry, node.node) {
+                       kv_entry->value = 0;
+               }
+       }
+
+       pthread_mutex_unlock(&umap->dead_app_kv_values.lock);
+
+       status = LTTNG_OK;
+end:
+       return status;
+}
+
+static
+enum lttng_error_code ust_app_clear_session_maps(struct ltt_session *session)
+{
+       struct ltt_ust_session *usess = session->ust_session;
+       enum lttng_error_code status;
+       struct lttng_ht_iter iter;
+       struct ltt_ust_map *umap;
+
+       cds_lfht_for_each_entry(usess->domain_global.maps->ht, &iter.iter,
+                       umap, node.node) {
+
+               if (usess->buffer_type == LTTNG_BUFFER_PER_UID) {
+                       status = ust_app_clear_session_maps_per_uid(session->ust_session,
+                                       umap, 32);
+                       assert(status == LTTNG_OK);
+
+                       status = ust_app_clear_session_maps_per_uid(session->ust_session,
+                                       umap, 64);
+                       assert(status == LTTNG_OK);
+                       //fixme:frdeso:error handling
+               } else  {
+                       status = ust_app_clear_session_maps_per_pid(session->ust_session,
+                                       umap, 32);
+                       assert(status == LTTNG_OK);
+
+                       status = ust_app_clear_session_maps_per_pid(session->ust_session,
+                                       umap, 64);
+                       assert(status == LTTNG_OK);
+                       //fixme:frdeso:error handling
+                       //
+                       //
+               }
+
+       }
+
+       return LTTNG_OK;
+}
+
+enum lttng_error_code ust_app_clear_session(struct ltt_session *session)
+{
+       enum lttng_error_code cmd_ret;
+
+
+       cmd_ret = ust_app_clear_session_channels(session);
+       if (cmd_ret != LTTNG_OK) {
+               ERR("Clearing session's channels");
+               goto end;
+       }
+
+       cmd_ret = ust_app_clear_session_maps(session);
+       if (cmd_ret != LTTNG_OK) {
+               ERR("Clearing session's maps");
+               goto end;
+       }
+end:
+       return cmd_ret;
+}
+
 /*
  * This function skips the metadata channel as the begin/end timestamps of a
  * metadata packet are useless.
@@ -7460,7 +10324,7 @@ enum lttng_error_code ust_app_open_packets(struct ltt_session *session)
 
                cds_list_for_each_entry (
                                reg, &usess->buffer_reg_uid_list, lnode) {
-                       struct buffer_reg_channel *reg_chan;
+                       struct buffer_reg_channel *buf_reg_chan;
                        struct consumer_socket *socket;
 
                        socket = consumer_find_socket_by_bitness(
@@ -7471,11 +10335,11 @@ enum lttng_error_code ust_app_open_packets(struct ltt_session *session)
                        }
 
                        cds_lfht_for_each_entry(reg->registry->channels->ht,
-                                       &iter.iter, reg_chan, node.node) {
+                                       &iter.iter, buf_reg_chan, node.node) {
                                const int open_ret =
                                                consumer_open_channel_packets(
                                                        socket,
-                                                       reg_chan->consumer_key);
+                                                       buf_reg_chan->consumer_key);
 
                                if (open_ret < 0) {
                                        ret = LTTNG_ERR_UNK;
index 29024b4de897872dd33637b2f36d78220027e031..5325c64fcc08c9839ecdedc26181ded343718d81 100644 (file)
@@ -11,7 +11,9 @@
 
 #include <stdint.h>
 
+#include <common/index-allocator.h>
 #include <common/uuid.h>
+#include <lttng/map/map.h>
 
 #include "trace-ust.h"
 #include "ust-registry.h"
@@ -42,6 +44,7 @@ struct ust_app_ht_key {
        const struct lttng_bytecode *filter;
        enum lttng_ust_loglevel_type loglevel_type;
        const struct lttng_event_exclusion *exclusion;
+       uint64_t tracer_token;
 };
 
 /*
@@ -93,6 +96,12 @@ struct ust_app_stream_list {
        struct cds_list_head head;
 };
 
+/* counter list containing ust_app_counter. */
+struct ust_app_counter_list {
+       unsigned int count;
+       struct cds_list_head head;
+};
+
 struct ust_app_ctx {
        int handle;
        struct lttng_ust_context_attr ctx;
@@ -114,6 +123,7 @@ struct ust_app_event {
 
 struct ust_app_event_notifier_rule {
        int enabled;
+       uint64_t error_counter_index;
        int handle;
        struct lttng_ust_object_data *obj;
        /* Holds a strong reference. */
@@ -139,6 +149,13 @@ struct ust_app_stream {
        struct cds_list_head list;
 };
 
+struct ust_app_map_counter {
+       int handle;
+       struct lttng_ust_object_data *obj;
+       /* Using a list of counters to keep order. */
+       struct cds_list_head list;
+};
+
 struct ust_app_channel {
        int enabled;
        int handle;
@@ -185,6 +202,43 @@ struct ust_app_channel {
        struct rcu_head rcu_head;
 };
 
+struct ust_app_map {
+       int enabled;
+       int handle;
+       /* Counters were sent to the UST tracer. */
+       int is_sent;
+       /*
+        * FIXME frdeso: what is difference between key and tracing_map_id
+        * Unique key used to identify the map.
+        */
+       uint64_t key;
+       /* Id of the tracing map set on creation. */
+       uint64_t tracing_map_id;
+       bool coalesce_hits;
+       enum lttng_map_bitness bitness;
+       char name[LTTNG_UST_SYM_NAME_LEN];
+       struct lttng_ust_object_data *obj;
+       struct ust_app_counter_list counters;
+       /* Session pointer that owns this object. */
+       struct ust_app_session *session;
+       struct lttng_ht *events;
+       struct ltt_ust_map_dead_pid_kv_values *dead_app_kv_values;
+
+       size_t bucket_count;
+       struct ustctl_daemon_counter *map_handle;
+       /*
+        * Node indexed by channel name in the channels' hash table of a session.
+        */
+       struct lttng_ht_node_str node;
+       /*
+        * Node indexed by UST channel object descriptor (handle). Stored in the
+        * ust_objd hash table in the ust_app object.
+        */
+       struct lttng_ht_node_ulong ust_objd_node;
+       /* For delayed reclaim */
+       struct rcu_head rcu_head;
+};
+
 struct ust_app_session {
        /*
         * Lock protecting this session's ust app interaction. Held
@@ -207,6 +261,7 @@ struct ust_app_session {
        uint64_t tracing_id;
        uint64_t id;    /* Unique session identifier */
        struct lttng_ht *channels; /* Registered channels */
+       struct lttng_ht *maps; /* Registered maps */
        struct lttng_ht_node_u64 node;
        /*
         * Node indexed by UST session object descriptor (handle). Stored in the
@@ -291,7 +346,11 @@ struct ust_app {
        /*
         * Hash table containing ust_app_channel indexed by channel objd.
         */
-       struct lttng_ht *ust_objd;
+       struct lttng_ht *ust_chan_objd;
+       /*
+        * Hash table containing ust_app_map indexed by map objd.
+        */
+       struct lttng_ht *ust_map_objd;
        /*
         * Hash table containing ust_app_session indexed by objd.
         */
@@ -319,6 +378,9 @@ struct ust_app {
                 */
                struct lttng_ust_object_data *object;
                struct lttng_pipe *event_pipe;
+               struct lttng_ust_object_data *counter;
+               struct lttng_ust_object_data **counter_cpu;
+               int nr_counter_cpu;
        } event_notifier_group;
        /*
         * Hashtable indexing the application's event notifier rule's
@@ -338,16 +400,31 @@ int ust_app_stop_trace_all(struct ltt_ust_session *usess);
 int ust_app_destroy_trace_all(struct ltt_ust_session *usess);
 int ust_app_list_events(struct lttng_event **events);
 int ust_app_list_event_fields(struct lttng_event_field **fields);
-int ust_app_create_event_glb(struct ltt_ust_session *usess,
+int ust_app_create_channel_event_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent);
 int ust_app_disable_channel_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan);
 int ust_app_enable_channel_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan);
-int ust_app_enable_event_glb(struct ltt_ust_session *usess,
+int ust_app_enable_channel_event_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent);
-int ust_app_disable_event_glb(struct ltt_ust_session *usess,
+int ust_app_disable_channel_event_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent);
+int ust_app_map_list_values(const struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap,
+               const struct lttng_map_query *query,
+               struct lttng_map_content **map_content);
+int ust_app_enable_map_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap);
+int ust_app_disable_map_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap);
+int ust_app_create_map_event_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap, struct ltt_ust_event *uevent);
+int ust_app_enable_map_event_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap, struct ltt_ust_event *uevent);
+int ust_app_disable_map_event_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap, struct ltt_ust_event *uevent);
+
 int ust_app_add_ctx_channel_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_context *uctx);
 void ust_app_global_update(struct ltt_ust_session *usess, struct ust_app *app);
@@ -355,10 +432,13 @@ void ust_app_global_update_all(struct ltt_ust_session *usess);
 void ust_app_global_update_event_notifier_rules(struct ust_app *app);
 void ust_app_global_update_all_event_notifier_rules(void);
 
+void ust_app_update_event_notifier_error_count(struct lttng_trigger *trigger);
+
 void ust_app_clean_list(void);
 int ust_app_ht_alloc(void);
 struct ust_app *ust_app_find_by_pid(pid_t pid);
 struct ust_app_stream *ust_app_alloc_stream(void);
+struct ust_app_map_counter *ust_app_alloc_map_counter(void);
 int ust_app_recv_registration(int sock, struct ust_register_msg *msg);
 int ust_app_recv_notify(int sock);
 void ust_app_add(struct ust_app *app);
@@ -504,24 +584,62 @@ int ust_app_enable_channel_glb(struct ltt_ust_session *usess,
        return 0;
 }
 static inline
-int ust_app_create_event_glb(struct ltt_ust_session *usess,
+int ust_app_create_channel_event_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent)
 {
        return 0;
 }
 static inline
-int ust_app_disable_event_glb(struct ltt_ust_session *usess,
+int ust_app_disable_channel_event_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent)
 {
        return 0;
 }
 static inline
-int ust_app_enable_event_glb(struct ltt_ust_session *usess,
+int ust_app_enable_channel_event_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent)
 {
        return 0;
 }
 static inline
+int ust_app_disable_map_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap)
+{
+       return 0;
+}
+static inline
+int ust_app_map_list_values(const struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap,
+               const struct lttng_map_query *query,
+               struct lttng_map_content **map_content)
+{
+       return 0;
+}
+static inline
+int ust_app_enable_map_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap)
+{
+       return 0;
+}
+static inline
+int ust_app_create_map_event_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap, struct ltt_ust_event *uevent)
+{
+       return 0;
+}
+static inline
+int ust_app_disable_map_event_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap, struct ltt_ust_event *uevent)
+{
+       return 0;
+}
+static inline
+int ust_app_enable_map_event_glb(struct ltt_ust_session *usess,
+               struct ltt_ust_map *umap, struct ltt_ust_event *uevent)
+{
+       return 0;
+}
+static inline
 int ust_app_add_ctx_channel_glb(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct ltt_ust_context *uctx)
 {
@@ -579,7 +697,12 @@ unsigned int ust_app_get_nb_stream(struct ltt_ust_session *usess)
 {
        return 0;
 }
-
+static inline
+void ust_app_update_event_notifier_error_count(
+               struct lttng_trigger *lttng_trigger)
+{
+       return;
+}
 static inline
 int ust_app_supported(void)
 {
index cd6b53ee1d2232db570f51ba97ca712f6862b720..158f727f2e9423b272780b92a59044124ec335dd 100644 (file)
@@ -42,7 +42,7 @@ static int ask_channel_creation(struct ust_app_session *ua_sess,
        uint64_t key, chan_reg_key;
        char *pathname = NULL;
        struct lttcomm_consumer_msg msg;
-       struct ust_registry_channel *chan_reg;
+       struct ust_registry_channel *ust_reg_chan;
        char shm_path[PATH_MAX] = "";
        char root_shm_path[PATH_MAX] = "";
        bool is_local_trace;
@@ -105,9 +105,9 @@ static int ask_channel_creation(struct ust_app_session *ua_sess,
                 * those buffer files.
                 */
        } else {
-               chan_reg = ust_registry_channel_find(registry, chan_reg_key);
-               assert(chan_reg);
-               chan_id = chan_reg->chan_id;
+               ust_reg_chan = ust_registry_channel_find(registry, chan_reg_key);
+               assert(ust_reg_chan);
+               chan_id = ust_reg_chan->chan_id;
                if (ua_sess->shm_path[0]) {
                        strncpy(shm_path, ua_sess->shm_path, sizeof(shm_path));
                        shm_path[sizeof(shm_path) - 1] = '\0';
index 7a89dbc26ab75eac10c6e6323a3922461b197f12..af380bc870cd87c0bbca0c29aa5a3e2befe7eff1 100644 (file)
@@ -9,8 +9,9 @@
 #ifndef LTTNG_UST_CTL_INTERNAL_H
 #define LTTNG_UST_CTL_INTERNAL_H
 
-#include <sys/types.h>
 #include <limits.h>
+#include <stdbool.h>
+#include <sys/types.h>
 
 #include "lttng-ust-abi.h"
 
index 1b1e65eba1327f06e90344020e490784363ec694..384d8030eb1682099c429aaa7327e0f609ac30bb 100644 (file)
@@ -5,6 +5,7 @@
  *
  */
 
+#include "bin/lttng-sessiond/event-notifier-error-accounting.h"
 #define _LGPL_SOURCE
 #include <assert.h>
 #include <inttypes.h>
@@ -12,6 +13,8 @@
 #include <common/common.h>
 #include <common/hashtable/utils.h>
 #include <lttng/lttng.h>
+#include <lttng/map-key.h>
+#include <lttng/map-key-internal.h>
 
 #include "ust-registry.h"
 #include "ust-app.h"
@@ -284,7 +287,7 @@ int validate_event_fields(size_t nr_fields, struct ustctl_field *fields,
  * registry.
  */
 static struct ust_registry_event *alloc_event(int session_objd,
-               int channel_objd, char *name, char *sig, size_t nr_fields,
+               int container_objd, char *name, char *sig, size_t nr_fields,
                struct ustctl_field *fields, int loglevel_value,
                char *model_emf_uri, struct ust_app *app)
 {
@@ -304,7 +307,7 @@ static struct ust_registry_event *alloc_event(int session_objd,
        }
 
        event->session_objd = session_objd;
-       event->channel_objd = channel_objd;
+       event->container_objd = container_objd;
        /* Allocated by ustctl. */
        event->signature = sig;
        event->nr_fields = nr_fields;
@@ -352,6 +355,33 @@ static void destroy_event_rcu(struct rcu_head *head)
        destroy_event(event);
 }
 
+/*
+ * Destroy ust_registry_map_key_ht_entry function call of the call RCU.
+ */
+static void destroy_ust_registry_map_key_ht_entry(struct rcu_head *head)
+{
+       struct lttng_ht_node_u64 *node =
+               caa_container_of(head, struct lttng_ht_node_u64, head);
+       struct ust_registry_map_key_ht_entry *entry =
+               caa_container_of(node, struct ust_registry_map_key_ht_entry, node);
+
+       lttng_map_key_put(entry->key);
+       free(entry);
+}
+
+/*
+ * Destroy ust_registry_map_index_ht_entry function call of the call RCU.
+ */
+static void destroy_ust_registry_map_index_ht_entry(struct rcu_head *head)
+{
+       struct lttng_ht_node_str *node =
+               caa_container_of(head, struct lttng_ht_node_str, head);
+       struct ust_registry_map_index_ht_entry *entry =
+               caa_container_of(node, struct ust_registry_map_index_ht_entry, node);
+
+       free(entry);
+}
+
 /*
  * Find an event using the name and signature in the given registry. RCU read
  * side lock MUST be acquired before calling this function and as long as the
@@ -359,7 +389,7 @@ static void destroy_event_rcu(struct rcu_head *head)
  *
  * On success, the event pointer is returned else NULL.
  */
-struct ust_registry_event *ust_registry_find_event(
+struct ust_registry_event *ust_registry_chan_find_event(
                struct ust_registry_channel *chan, char *name, char *sig)
 {
        struct lttng_ht_node_u64 *node;
@@ -398,7 +428,7 @@ end:
  *
  * Should be called with session registry mutex held.
  */
-int ust_registry_create_event(struct ust_registry_session *session,
+int ust_registry_chan_create_event(struct ust_registry_session *session,
                uint64_t chan_key, int session_objd, int channel_objd, char *name,
                char *sig, size_t nr_fields, struct ustctl_field *fields,
                int loglevel_value, char *model_emf_uri, int buffer_type,
@@ -447,7 +477,7 @@ int ust_registry_create_event(struct ust_registry_session *session,
 
        DBG3("UST registry creating event with event: %s, sig: %s, id: %u, "
                        "chan_objd: %u, sess_objd: %u, chan_id: %u", event->name,
-                       event->signature, event->id, event->channel_objd,
+                       event->signature, event->id, event->container_objd,
                        event->session_objd, chan->chan_id);
 
        /*
@@ -472,13 +502,13 @@ int ust_registry_create_event(struct ust_registry_session *session,
                        ERR("UST registry create event add unique failed for event: %s, "
                                        "sig: %s, id: %u, chan_objd: %u, sess_objd: %u",
                                        event->name, event->signature, event->id,
-                                       event->channel_objd, event->session_objd);
+                                       event->container_objd, event->session_objd);
                        ret = -EINVAL;
                        goto error_unlock;
                }
        } else {
                /* Request next event id if the node was successfully added. */
-               event_id = event->id = ust_registry_get_next_event_id(chan);
+               event_id = event->id = ust_registry_channel_get_next_event_id(chan);
        }
 
        *event_id_p = event_id;
@@ -506,11 +536,334 @@ error_unlock:
        return ret;
 }
 
+static
+int format_event_key(const struct lttng_map_key *key,
+               const char *full_event_name, char **formated_key)
+{
+       int ret;
+       char _key[LTTNG_UST_KEY_TOKEN_STRING_LEN_MAX] = {0};
+       enum lttng_map_key_status key_status;
+       unsigned int i, token_count;
+       char *cloned_full_event_name;
+       const char *provider_name, *event_name;
+
+       assert(key);
+       assert(full_event_name);
+
+       cloned_full_event_name = strdup(full_event_name);
+
+       provider_name = strtok(cloned_full_event_name, ":");
+       event_name = strtok(NULL, ":");
+
+       key_status = lttng_map_key_get_token_count(key, &token_count);
+       if (key_status != LTTNG_MAP_KEY_STATUS_OK) {
+               ERR("Error getting map key token count");
+               ret = -1;
+               goto end;
+       }
+
+       if (token_count == 0) {
+               ERR("Map key token number is zero");
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < token_count; i++) {
+               const struct lttng_map_key_token *token =
+                               lttng_map_key_get_token_at_index(key, i);
+               switch (token->type) {
+               case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
+               {
+                       struct lttng_map_key_token_string *str_token =
+                                       (struct lttng_map_key_token_string *) token;
+                       DBG("Appending a string type key token: str = '%s'", str_token->string);
+
+                       strcat(_key, lttng_map_key_token_string_get_string(str_token));
+
+                       break;
+               }
+               case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
+               {
+                       struct lttng_map_key_token_variable *var_token =
+                                       (struct lttng_map_key_token_variable *) token;
+
+                       switch (var_token->type) {
+                       case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME:
+                               DBG("Serializing a event name variable type key token: event_name = '%s'",
+                                               event_name);
+                               strcat(_key, event_name);
+                               break;
+                       case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME:
+                               DBG("Serializing a provider name variable type key token: provider_name = '%s'",
+                                               provider_name);
+                               strcat(_key, provider_name);
+                               break;
+                       default:
+                               abort();
+                       }
+                       break;
+               }
+               default:
+                       abort();
+               }
+       }
+
+       *formated_key = strdup(_key);
+
+       ret = 0;
+end:
+       free(cloned_full_event_name);
+       return ret;
+}
+
+static
+const struct lttng_map_key *ust_registry_map_find_key_for_token(
+               struct ust_registry_map *map,
+               uint64_t tracer_token)
+{
+       struct lttng_ht_iter iter;
+       struct lttng_ht_node_u64 *key_node;
+       struct ust_registry_map_key_ht_entry *key_entry;
+       const struct lttng_map_key *key = NULL;;
+
+       assert(map);
+       lttng_ht_lookup(map->tracer_token_to_map_key_ht,
+                       (void *) &tracer_token, &iter);
+
+       key_node = lttng_ht_iter_get_node_u64(&iter);
+       if (!key_node) {
+               goto end;
+       }
+
+       /*
+        * It's already mapped. Return the key we allocated already.
+        */
+       key_entry = caa_container_of(key_node,
+               struct ust_registry_map_key_ht_entry, node);
+       assert(key_entry);
+
+       key = key_entry->key;
+
+       DBG("Returning map key object associated to the tracer token: key = %p, tracer_token = %"PRIu64,
+               key_entry->key, tracer_token);
+
+end:
+       return key;
+}
+
+int ust_registry_map_add_token_key_mapping(struct ust_registry_session *session,
+               uint64_t map_key, uint64_t tracer_token,
+               struct lttng_map_key *key)
+{
+       int ret;
+       struct ust_registry_map_key_ht_entry *key_entry;
+       struct ust_registry_map *map;
+       const struct lttng_map_key *existing_mapping = NULL;
+
+       rcu_read_lock();
+       map = ust_registry_map_find(session, map_key);
+       if (!map) {
+               ret = -EINVAL;
+               goto end;
+       }
+       rcu_read_unlock();
+
+       /* JORAJ check if the mapping already exist, we might want to *move this
+        * to the caller or at least provide more check if for some scenario
+        * (PID) this should never happen
+        */
+       existing_mapping = ust_registry_map_find_key_for_token(map, tracer_token);
+       if (existing_mapping != NULL) {
+               assert(existing_mapping == key);
+               ret = 0;
+               goto end;
+       }
+
+       key_entry = zmalloc(sizeof(struct ust_registry_map_key_ht_entry));
+       if (!key_entry) {
+               ret = -ENOMEM;
+               goto end;
+       }
+       key_entry->key = key;
+
+       /* Ensure the lifetime of the lttng_map_key object. */
+       lttng_map_key_get(key);
+
+       rcu_read_lock();
+
+       lttng_ht_node_init_u64(&key_entry->node, tracer_token);
+       lttng_ht_add_unique_u64(map->tracer_token_to_map_key_ht,
+                       &key_entry->node);
+
+       rcu_read_unlock();
+
+
+       ret = 0;
+end:
+       return ret;
+
+}
+
+static
+int ust_registry_map_find_or_create_index_for_key(struct ust_registry_map *map,
+               const char *formated_key, uint64_t *index)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+       struct lttng_ht_node_str *index_node;
+       struct ust_registry_map_index_ht_entry *index_entry;
+
+       assert(map);
+       assert(formated_key);
+
+       /*
+        * First try to check if we already mapped this formated key to an
+        * index.
+        */
+       lttng_ht_lookup(map->key_string_to_bucket_index_ht,
+                       (void *) formated_key, &iter);
+
+       index_node = lttng_ht_iter_get_node_str(&iter);
+       if (index_node) {
+               /*
+                * It's already mapped. Return the index we allocated already.
+                */
+               index_entry = caa_container_of(index_node,
+                               struct ust_registry_map_index_ht_entry, node);
+               assert(index_entry);
+
+               *index = index_entry->index;
+
+               DBG("Returning an already allocated index for formated key: key = '%s', index = %"PRIu64,
+                               formated_key, *index);
+       } else {
+               /*
+                * It's not mapped. Create a new mapping, add it to the
+                * hashtable and return it.
+                */
+               index_entry = zmalloc(sizeof(struct ust_registry_map_index_ht_entry));
+               if (!index_entry) {
+                       ret = -1;
+                       goto end;
+               }
+
+               index_entry->index = ust_registry_map_get_next_event_id(map);
+               index_entry->formated_key = strdup(formated_key);
+               lttng_ht_node_init_str(&index_entry->node, index_entry->formated_key);
+
+               lttng_ht_add_unique_str(map->key_string_to_bucket_index_ht,
+                               &index_entry->node);
+
+               *index = index_entry->index;
+               DBG("Allocated counter index for new formated_key: key = '%s', index = %"PRIu64,
+                               formated_key, *index);
+       }
+
+       ret = 0;
+end:
+       return ret;
+}
+
+/*
+ * Create a ust_registry_event from the given parameters and add it to the
+ * registry hash table. If event_id is valid, it is set with the newly created
+ * event id.
+ *
+ * On success, return 0 else a negative value. The created event MUST be unique
+ * so on duplicate entry -EINVAL is returned. On error, event_id is untouched.
+ *
+ * Should be called with session registry mutex held.
+ */
+int ust_registry_map_create_event(struct ust_registry_session *session,
+               uint64_t map_key, int session_objd, int map_objd, char *name,
+               char *sig, size_t nr_fields, struct ustctl_field *fields,
+               int loglevel_value, char *model_emf_uri, int buffer_type,
+               uint64_t tracer_token, uint64_t *counter_index_p,
+               struct ust_app *app)
+{
+       int ret;
+       uint64_t counter_index;
+       struct ust_registry_map *map;
+       char *formated_key;
+       const struct lttng_map_key *key;
+
+       assert(session);
+       assert(name);
+       assert(sig);
+       assert(counter_index_p);
+
+       rcu_read_lock();
+
+       /*
+        * This should not happen but since it comes from the UST tracer, an
+        * external party, don't assert and simply validate values.
+        */
+       if (session_objd < 0 || map_objd < 0) {
+               ret = -EINVAL;
+               goto error_free;
+       }
+
+       map = ust_registry_map_find(session, map_key);
+       if (!map) {
+               ret = -EINVAL;
+               goto error_free;
+       }
+
+       /* Check if we've reached the maximum possible id. */
+       if (ust_registry_is_max_id(map->used_event_id)) {
+               ret = -ENOENT;
+               goto error_free;
+       }
+
+       key = ust_registry_map_find_key_for_token(map, tracer_token);
+       if (!key) {
+               ERR("Tracer token %"PRIu64" not found for map id = %"PRIu32,
+                               tracer_token, map->map_id);
+               ret = -EINVAL;
+               goto error_unlock;
+       }
+
+       ret = format_event_key(key, name, &formated_key);
+       if (ret) {
+               ERR("Error formating key");
+               ret = -EINVAL;
+               goto error_unlock;
+       }
+
+       ret = ust_registry_map_find_or_create_index_for_key(map, formated_key,
+                       &counter_index);
+       if (ret) {
+               ERR("Error finding or creating index for formated_key = '%s'",
+                               formated_key);
+               free(formated_key);
+               ret = -EINVAL;
+               goto error_unlock;
+       }
+
+       DBG3("UST registry allocating counter index %"PRIu64 " to event: %s, "
+               "signature: %s, sess_objd: %u, map_objd: %u, map_id: %u",
+               counter_index, name, sig, session_objd, map_objd, map->map_id);
+
+       *counter_index_p = counter_index;
+
+       rcu_read_unlock();
+       return 0;
+
+error_free:
+       free(sig);
+       free(fields);
+       free(model_emf_uri);
+error_unlock:
+       rcu_read_unlock();
+       return ret;
+}
+
+
 /*
  * For a given event in a registry, delete the entry and destroy the event.
  * This MUST be called within a RCU read side lock section.
  */
-void ust_registry_destroy_event(struct ust_registry_channel *chan,
+void ust_registry_chan_destroy_event(struct ust_registry_channel *chan,
                struct ust_registry_event *event)
 {
        int ret;
@@ -529,6 +882,73 @@ void ust_registry_destroy_event(struct ust_registry_channel *chan,
        return;
 }
 
+/*
+ * This MUST be called within a RCU read side lock section.
+ */
+static void ust_registry_map_key_entry_destroy(struct lttng_ht *ht,
+               struct ust_registry_map_key_ht_entry *entry)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+
+       assert(ht);
+       assert(entry);
+
+       /* Delete the node first. */
+       iter.iter.node = &entry->node.node;
+       ret = lttng_ht_del(ht, &iter);
+       assert(!ret);
+
+       call_rcu(&entry->node.head, destroy_ust_registry_map_key_ht_entry);
+
+       return;
+}
+
+/*
+ * This MUST be called within a RCU read side lock section.
+ */
+static void ust_registry_map_index_ht_entry_destroy(struct lttng_ht *ht,
+               struct ust_registry_map_index_ht_entry *entry)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+
+       assert(ht);
+       assert(entry);
+
+       /* Delete the node first. */
+       iter.iter.node = &entry->node.node;
+       ret = lttng_ht_del(ht, &iter);
+       assert(!ret);
+
+       call_rcu(&entry->node.head, destroy_ust_registry_map_index_ht_entry);
+
+       return;
+}
+
+/*
+ * For a given event in a registry, delete the entry and destroy the event.
+ * This MUST be called within a RCU read side lock section.
+ */
+void ust_registry_map_destroy_event(struct ust_registry_map *map,
+               struct ust_registry_event *event)
+{
+       int ret;
+       struct lttng_ht_iter iter;
+
+       assert(map);
+       assert(event);
+
+       /* Delete the node first. */
+       iter.iter.node = &event->node.node;
+       ret = lttng_ht_del(map->events_ht, &iter);
+       assert(!ret);
+
+       call_rcu(&event->node.head, destroy_event_rcu);
+
+       return;
+}
+
 static void destroy_enum(struct ust_registry_enum *reg_enum)
 {
        if (!reg_enum) {
@@ -717,6 +1137,33 @@ void destroy_channel_rcu(struct rcu_head *head)
        free(chan);
 }
 
+/*
+ * We need to execute ht_destroy outside of RCU read-side critical
+ * section and outside of call_rcu thread, so we postpone its execution
+ * using ht_cleanup_push. It is simpler than to mapge the semantic of
+ * the many callers of delete_ust_app_session().
+ */
+static
+void destroy_map_rcu(struct rcu_head *head)
+{
+       struct ust_registry_map *map =
+               caa_container_of(head, struct ust_registry_map, rcu_head);
+
+       if (map->events_ht) {
+               ht_cleanup_push(map->events_ht);
+       }
+
+       if (map->tracer_token_to_map_key_ht) {
+               ht_cleanup_push(map->tracer_token_to_map_key_ht);
+       }
+
+       if (map->key_string_to_bucket_index_ht) {
+               ht_cleanup_push(map->key_string_to_bucket_index_ht);
+       }
+
+       free(map);
+}
+
 /*
  * Destroy every element of the registry and free the memory. This does NOT
  * free the registry pointer since it might not have been allocated before so
@@ -745,13 +1192,55 @@ static void destroy_channel(struct ust_registry_channel *chan, bool notif)
                cds_lfht_for_each_entry(
                                chan->ht->ht, &iter.iter, event, node.node) {
                        /* Delete the node from the ht and free it. */
-                       ust_registry_destroy_event(chan, event);
+                       ust_registry_chan_destroy_event(chan, event);
                }
                rcu_read_unlock();
        }
        call_rcu(&chan->rcu_head, destroy_channel_rcu);
 }
 
+/*
+ * Destroy every element of the registry and free the memory. This does NOT
+ * free the registry pointer since it might not have been allocated before so
+ * it's the caller responsability.
+ */
+static void destroy_map(struct ust_registry_map *map)
+{
+       struct lttng_ht_iter iter;
+       struct ust_registry_event *event;
+       struct ust_registry_map_key_ht_entry *key_entry;
+       struct ust_registry_map_index_ht_entry *index_entry;
+
+       assert(map);
+
+       rcu_read_lock();
+       if (map->events_ht) {
+               /* Destroy all event associated with this registry. */
+               cds_lfht_for_each_entry(map->events_ht->ht, &iter.iter, event, node.node) {
+                       /* Delete the node from the ht and free it. */
+                       ust_registry_map_destroy_event(map, event);
+               }
+       }
+
+       /* Destroy all map_key entries associated with this registry. */
+       cds_lfht_for_each_entry (map->tracer_token_to_map_key_ht->ht,
+                       &iter.iter, key_entry, node.node) {
+               ust_registry_map_key_entry_destroy(
+                               map->tracer_token_to_map_key_ht,
+                               key_entry);
+       }
+
+       /* Destroy all index entry associated with this registry. */
+       cds_lfht_for_each_entry(map->key_string_to_bucket_index_ht->ht,
+                       &iter.iter, index_entry, node.node) {
+               ust_registry_map_index_ht_entry_destroy(
+                               map->key_string_to_bucket_index_ht,
+                               index_entry);
+       }
+       rcu_read_unlock();
+       call_rcu(&map->rcu_head, destroy_map_rcu);
+}
+
 /*
  * Initialize registry with default values.
  */
@@ -804,6 +1293,71 @@ error_alloc:
        return ret;
 }
 
+/*
+ * Initialize registry map entry with default values.
+ */
+int ust_registry_map_add(struct ust_registry_session *session,
+               uint64_t key)
+{
+       int ret = 0;
+       struct ust_registry_map *map;
+
+       assert(session);
+
+       map = zmalloc(sizeof(*map));
+       if (!map) {
+               PERROR("zmalloc ust registry map");
+               ret = -ENOMEM;
+               goto error_alloc;
+       }
+
+       map->events_ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+       if (!map->events_ht) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       /* Set custom match function. */
+       map->events_ht->match_fct = ht_match_event;
+       map->events_ht->hash_fct = ht_hash_event;
+
+       map->tracer_token_to_map_key_ht = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+       if (!map->tracer_token_to_map_key_ht) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       map->key_string_to_bucket_index_ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+       if (!map->key_string_to_bucket_index_ht) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       /*
+        * FIXME frdeso: fix this comment
+        * Assign a map ID right now since the event notification comes
+        * *before* the map notify so the ID needs to be set at this point so
+        * the metadata can be dumped for that event.
+        */
+       if (ust_registry_is_max_id(session->used_map_id)) {
+               ret = -1;
+               goto error;
+       }
+       map->map_id = ust_registry_get_next_map_id(session);
+
+       rcu_read_lock();
+       lttng_ht_node_init_u64(&map->node, key);
+       lttng_ht_add_unique_u64(session->maps, &map->node);
+       rcu_read_unlock();
+
+       return 0;
+
+error:
+       destroy_map(map);
+error_alloc:
+       return ret;
+}
+
 /*
  * Find a channel in the given registry. RCU read side lock MUST be acquired
  * before calling this function and as long as the event reference is kept by
@@ -834,6 +1388,36 @@ end:
        return chan;
 }
 
+/*
+ * Find a map in the given registry. RCU read side lock MUST be acquired
+ * before calling this function and as long as the event reference is kept by
+ * the caller.
+ *
+ * On success, the pointer is returned else NULL.
+ */
+struct ust_registry_map *ust_registry_map_find(
+               struct ust_registry_session *session, uint64_t key)
+{
+       struct lttng_ht_node_u64 *node;
+       struct lttng_ht_iter iter;
+       struct ust_registry_map *map = NULL;
+
+       assert(session);
+       assert(session->maps);
+
+       DBG3("UST registry map finding key %" PRIu64, key);
+
+       lttng_ht_lookup(session->maps, &key, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if (!node) {
+               goto end;
+       }
+       map = caa_container_of(node, struct ust_registry_map, node);
+
+end:
+       return map;
+}
+
 /*
  * Remove channel using key from registry and free memory.
  */
@@ -863,6 +1447,35 @@ end:
        return;
 }
 
+/*
+ * Remove map using key from registry and free memory.
+ */
+void ust_registry_map_del_free(struct ust_registry_session *session,
+               uint64_t key)
+{
+       struct lttng_ht_iter iter;
+       struct ust_registry_map *map;
+       int ret;
+
+       assert(session);
+
+       rcu_read_lock();
+       map = ust_registry_map_find(session, key);
+       if (!map) {
+               rcu_read_unlock();
+               goto end;
+       }
+
+       iter.iter.node = &map->node.node;
+       ret = lttng_ht_del(session->maps, &iter);
+       assert(!ret);
+       rcu_read_unlock();
+       destroy_map(map);
+
+end:
+       return;
+}
+
 /*
  * Initialize registry with default values and set the newly allocated session
  * pointer to sessionp.
@@ -962,6 +1575,12 @@ int ust_registry_session_init(struct ust_registry_session **sessionp,
                goto error;
        }
 
+       session->maps = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+       if (!session->maps) {
+               lttng_ht_destroy(session->channels);
+               goto error;
+       }
+
        ret = lttng_uuid_generate(session->uuid);
        if (ret) {
                ERR("Failed to generate UST uuid (errno = %d)", ret);
index 12614c5d531e08979ea7a20b3eae003e6bd19de7..1e3d2fc6be97380e6d11f118141bab5993309d1c 100644 (file)
@@ -35,6 +35,10 @@ struct ust_registry_session {
        uint32_t next_channel_id;
        /* Once this value reaches UINT32_MAX, no more id can be allocated. */
        uint32_t used_channel_id;
+       /* Next map ID available for a newly registered map. */
+       uint32_t next_map_id;
+       /* Once this value reaches UINT32_MAX, no more id can be allocated. */
+       uint32_t used_map_id;
        /* Next enumeration ID available. */
        uint64_t next_enum_id;
        /* Universal unique identifier used by the tracer. */
@@ -97,6 +101,12 @@ struct ust_registry_session {
         * be accessed with a RCU read side lock acquired.
         */
        struct lttng_ht *channels;
+
+       /*
+        * Hash table containing maps sent by the UST tracer. MUST
+        * be accessed with a RCU read side lock acquired.
+        */
+       struct lttng_ht *maps;
        /*
         * Unique key to identify the metadata on the consumer side.
         */
@@ -162,6 +172,45 @@ struct ust_registry_channel {
        struct rcu_head rcu_head;
 };
 
+struct ust_registry_map_key_ht_entry {
+       struct lttng_map_key *key;
+       struct lttng_ht_node_u64 node;
+};
+
+struct ust_registry_map_index_ht_entry {
+       uint64_t index;
+       char *formated_key;
+       struct lttng_ht_node_str node;
+};
+
+struct ust_registry_map {
+       uint64_t key;
+       /* Id set when replying to a register map. */
+       uint32_t map_id;
+
+       /* Indicates if this map registry has already been registered. */
+       unsigned int register_done;
+
+       /*
+        * Hash table containing events sent by the UST tracer. MUST be accessed
+        * with a RCU read side lock acquired.
+        */
+       struct lttng_ht *events_ht;
+       /* Next event ID available for a newly registered event. */
+       uint32_t next_event_id;
+       /* Once this value reaches UINT32_MAX, no more id can be allocated. */
+       uint32_t used_event_id;
+
+       /* tracer_token -> ust_registry_map_key_ht_entry */
+       struct lttng_ht *tracer_token_to_map_key_ht;
+       /* format key -> ust_registry_map_index_ht_entry */
+       struct lttng_ht *key_string_to_bucket_index_ht;
+
+       struct lttng_ht_node_u64 node;
+       /* For delayed reclaim */
+       struct rcu_head rcu_head;
+};
+
 /*
  * Event registered from a UST tracer sent to the session daemon. This is
  * indexed and matched by <event_name/signature>.
@@ -170,7 +219,7 @@ struct ust_registry_event {
        int id;
        /* Both objd are set by the tracer. */
        int session_objd;
-       int channel_objd;
+       int container_objd;
        /* Name of the event returned by the tracer. */
        char name[LTTNG_UST_SYM_NAME_LEN];
        char *signature;
@@ -220,7 +269,7 @@ static inline int ust_registry_is_max_id(uint32_t id)
  * Return a unique channel ID. If max is reached, the used_event_id counter is
  * returned.
  */
-static inline uint32_t ust_registry_get_next_event_id(
+static inline uint32_t ust_registry_channel_get_next_event_id(
                struct ust_registry_channel *r)
 {
        if (ust_registry_is_max_id(r->used_event_id)) {
@@ -231,6 +280,26 @@ static inline uint32_t ust_registry_get_next_event_id(
        return r->next_event_id++;
 }
 
+/*
+ * Return next available event id and increment the used counter. The
+ * ust_registry_is_max_id function MUST be called before in order to validate
+ * if the maximum number of IDs have been reached. If not, it is safe to call
+ * this function.
+ *
+ * Return a unique map ID. If max is reached, the used_event_id counter is
+ * returned.
+ */
+static inline uint32_t ust_registry_map_get_next_event_id(
+               struct ust_registry_map *r)
+{
+       if (ust_registry_is_max_id(r->used_event_id)) {
+               return r->used_event_id;
+       }
+
+       r->used_event_id++;
+       return r->next_event_id++;
+}
+
 /*
  * Return next available channel id and increment the used counter. The
  * ust_registry_is_max_id function MUST be called before in order to validate
@@ -251,6 +320,26 @@ static inline uint32_t ust_registry_get_next_chan_id(
        return r->next_channel_id++;
 }
 
+/*
+ * Return next available map id and increment the used counter. The
+ * ust_registry_is_max_id function MUST be called before in order to validate
+ * if the maximum number of IDs have been reached. If not, it is safe to call
+ * this function.
+ *
+ * Return a unique map ID. If max is reached, the used_map_id counter
+ * is returned.
+ */
+static inline uint32_t ust_registry_get_next_map_id(
+               struct ust_registry_session *r)
+{
+       if (ust_registry_is_max_id(r->used_map_id)) {
+               return r->used_map_id;
+       }
+
+       r->used_map_id++;
+       return r->next_map_id++;
+}
+
 /*
  * Return registry event count. This is read atomically.
  */
@@ -262,6 +351,7 @@ static inline uint32_t ust_registry_get_event_count(
 
 #ifdef HAVE_LIBLTTNG_UST_CTL
 
+/* Channels */
 void ust_registry_channel_destroy(struct ust_registry_session *session,
                struct ust_registry_channel *chan);
 struct ust_registry_channel *ust_registry_channel_find(
@@ -271,6 +361,19 @@ int ust_registry_channel_add(struct ust_registry_session *session,
 void ust_registry_channel_del_free(struct ust_registry_session *session,
                uint64_t key, bool notif);
 
+/* Maps */
+void ust_registry_map_destroy(struct ust_registry_session *session,
+               struct ust_registry_map *map);
+struct ust_registry_map *ust_registry_map_find(
+               struct ust_registry_session *session, uint64_t key);
+int ust_registry_map_add(struct ust_registry_session *session,
+               uint64_t key);
+void ust_registry_map_del_free(struct ust_registry_session *session,
+               uint64_t key);
+int ust_registry_map_add_token_key_mapping(struct ust_registry_session *session,
+               uint64_t map_key, uint64_t tracer_token,
+               struct lttng_map_key *key);
+
 int ust_registry_session_init(struct ust_registry_session **sessionp,
                struct ust_app *app,
                uint32_t bits_per_long,
@@ -290,14 +393,24 @@ int ust_registry_session_init(struct ust_registry_session **sessionp,
                uid_t tracing_uid);
 void ust_registry_session_destroy(struct ust_registry_session *session);
 
-int ust_registry_create_event(struct ust_registry_session *session,
+int ust_registry_chan_create_event(struct ust_registry_session *session,
                uint64_t chan_key, int session_objd, int channel_objd, char *name,
                char *sig, size_t nr_fields, struct ustctl_field *fields,
                int loglevel_value, char *model_emf_uri, int buffer_type,
                uint32_t *event_id_p, struct ust_app *app);
-struct ust_registry_event *ust_registry_find_event(
+struct ust_registry_event *ust_registry_chan_find_event(
                struct ust_registry_channel *chan, char *name, char *sig);
-void ust_registry_destroy_event(struct ust_registry_channel *chan,
+void ust_registry_chan_destroy_event(struct ust_registry_channel *chan,
+               struct ust_registry_event *event);
+
+int ust_registry_map_create_event(struct ust_registry_session *session,
+               uint64_t map_key, int session_objd, int map_objd, char *name,
+               char *sig, size_t nr_fields, struct ustctl_field *fields,
+               int loglevel_value, char *model_emf_uri, int buffer_type,
+               uint64_t tracer_token, uint64_t *counter_index_p, struct ust_app *app);
+struct ust_registry_event *ust_registry_map_find_event(
+               struct ust_registry_map *map, char *name, char *sig);
+void ust_registry_map_destroy_event(struct ust_registry_map *map,
                struct ust_registry_event *event);
 
 /* app can be NULL for registry shared across applications. */
index 50ab92988db3d88b957bc3aba9af6181d12d73ec..6c262622f10be35ef1412a7177a6fdc6f2c1157a 100644 (file)
@@ -14,9 +14,13 @@ lttng_SOURCES = command.h conf.c conf.h commands/start.c \
                                commands/list.c commands/create.c commands/destroy.c \
                                commands/stop.c commands/enable_events.c \
                                commands/disable_events.c commands/enable_channels.c \
+                               commands/add_map.c \
+                               commands/enable_map.c \
+                               commands/disable_map.c \
                                commands/disable_channels.c commands/add_context.c \
                                commands/set_session.c commands/version.c \
                                commands/view.c \
+                               commands/view_map.c \
                                commands/snapshot.c \
                                commands/save.c \
                                commands/load.c \
@@ -44,4 +48,5 @@ lttng_LDADD = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la \
                        $(top_builddir)/src/common/string-utils/libstring-utils.la \
                        $(top_builddir)/src/common/filter/libfilter.la \
                        $(top_builddir)/src/common/argpar/libargpar.la \
-                       $(POPT_LIBS)
+                       $(POPT_LIBS) \
+                       -lm
index bf004521003787acb910b9d29ea3a1b519c9af9a..6b8c5c5042f418b49da8ae31ec87dac1e5a2f6d5 100644 (file)
@@ -60,10 +60,14 @@ DECL_COMMAND(enable_events);
 DECL_COMMAND(disable_events);
 DECL_COMMAND(enable_channels);
 DECL_COMMAND(disable_channels);
+DECL_COMMAND(add_map);
+DECL_COMMAND(enable_map);
+DECL_COMMAND(disable_map);
 DECL_COMMAND(add_context);
 DECL_COMMAND(set_session);
 DECL_COMMAND(version);
 DECL_COMMAND(view);
+DECL_COMMAND(view_map);
 DECL_COMMAND(enable_consumer);
 DECL_COMMAND(disable_consumer);
 DECL_COMMAND(snapshot);
diff --git a/src/bin/lttng/commands/add_map.c b/src/bin/lttng/commands/add_map.c
new file mode 100644 (file)
index 0000000..d9e4ff4
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <lttng/map/map.h>
+
+#include "common/argpar/argpar.h"
+#include "common/utils.h"
+
+#include "../command.h"
+#include "../utils.h"
+
+#define LTTNG_MAP_DEFAULT_SIZE 4096
+
+enum {
+       OPT_HELP,
+       OPT_SESSION,
+       OPT_USERSPACE,
+       OPT_KERNEL,
+       OPT_MAX_KEY_COUNT,
+       OPT_PER_PID,
+       OPT_PER_UID,
+       OPT_OVERFLOW,
+       OPT_BITNESS,
+       OPT_COALESCE_HITS,
+};
+
+static const struct argpar_opt_descr add_map_opt_descrs[] = {
+
+       { OPT_HELP, 'h', "help", false },
+       { OPT_SESSION, 's', "session", true },
+       { OPT_USERSPACE, 'u', "userspace", false },
+       { OPT_KERNEL, 'k', "kernel", false },
+       { OPT_MAX_KEY_COUNT, '\0', "max-key-count", true},
+       { OPT_PER_PID, '\0', "per-pid", false},
+       { OPT_PER_UID, '\0', "per-uid", false},
+       { OPT_OVERFLOW, '\0', "overflow", false},
+       { OPT_BITNESS, '\0', "bitness", true},
+       { OPT_COALESCE_HITS, '\0', "coalesce-hits", false},
+       ARGPAR_OPT_DESCR_SENTINEL
+};
+
+static
+bool assign_string(char **dest, const char *src, const char *opt_name)
+{
+       bool ret;
+
+       if (*dest) {
+               ERR("Duplicate %s given.", opt_name);
+               goto error;
+       }
+
+       *dest = strdup(src);
+       if (!*dest) {
+               ERR("Failed to allocate %s string.", opt_name);
+               goto error;
+       }
+
+       ret = true;
+       goto end;
+
+error:
+       ret = false;
+
+end:
+       return ret;
+}
+
+int cmd_add_map(int argc, const char **argv)
+{
+       int ret, i;
+       enum lttng_error_code error_code_ret;
+       struct argpar_parse_ret argpar_parse_ret = { 0 };
+       bool opt_userspace = false, opt_kernel = false, opt_buffers_uid = false,
+               opt_buffers_pid = false, opt_overflow = false, opt_coalesce_hits = false;
+       char *opt_session_name = NULL, *session_name = NULL, *opt_max_key_count = NULL, *opt_bitness = NULL;
+       const char *opt_map_name = NULL;;
+       enum lttng_map_bitness bitness_type;
+       enum lttng_map_boundary_policy boundary_policy;
+       enum lttng_map_status status;
+       uint64_t dimensions_sizes[1] = {0};
+       unsigned long long bitness;
+       struct lttng_map *map;
+       struct lttng_domain dom = {0};
+       struct lttng_handle *handle = NULL;
+
+       argpar_parse_ret = argpar_parse(argc - 1, argv + 1,
+               add_map_opt_descrs, true);
+       if (!argpar_parse_ret.items) {
+               ERR("%s", argpar_parse_ret.error);
+               goto error;
+       }
+
+       for (i = 0; i < argpar_parse_ret.items->n_items; i++) {
+               struct argpar_item *item = argpar_parse_ret.items->items[i];
+
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       struct argpar_item_opt *item_opt =
+                               (struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_HELP:
+                               SHOW_HELP();
+                               ret = CMD_SUCCESS;
+                               goto end;
+                       case OPT_SESSION:
+                               if (!assign_string(&opt_session_name, item_opt->arg,
+                                               "-s/--session")) {
+                                       goto error;
+                               }
+                               break;
+                       case OPT_USERSPACE:
+                               opt_userspace = true;
+                               break;
+                       case OPT_KERNEL:
+                               opt_kernel = true;
+                               break;
+                       case OPT_MAX_KEY_COUNT:
+                               if (!assign_string(&opt_max_key_count, item_opt->arg,
+                                               "--max-key-count")) {
+                                       goto error;
+                               }
+                               break;
+                       case OPT_PER_PID:
+                               opt_buffers_pid = true;
+                               break;
+                       case OPT_PER_UID:
+                               opt_buffers_uid = true;
+                               break;
+                       case OPT_OVERFLOW:
+                               opt_overflow = true;
+                               break;
+                       case OPT_BITNESS:
+                               if (!assign_string(&opt_bitness, item_opt->arg,
+                                               "--bitness")) {
+                                       goto error;
+                               }
+                               break;
+                       case OPT_COALESCE_HITS:
+                               opt_coalesce_hits = true;
+                               break;
+                       default:
+                               abort();
+                       }
+               } else {
+                       struct argpar_item_non_opt *item_non_opt =
+                               (struct argpar_item_non_opt *) item;
+
+                       if (opt_map_name) {
+                               ERR("Unexpected argument: %s", item_non_opt->arg);
+                               goto error;
+                       }
+
+                       opt_map_name = item_non_opt->arg;
+               }
+       }
+
+       if (!opt_map_name) {
+               ERR("Missing map name");
+               goto error;
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       goto error;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       /* Check that one and only one domain option was provided. */
+       ret = print_missing_or_multiple_domains(
+                       opt_kernel + opt_userspace, false);
+       if (ret) {
+               goto error;
+       }
+
+       if (opt_kernel) {
+               dom.type = LTTNG_DOMAIN_KERNEL;
+               if (opt_buffers_uid || opt_buffers_pid) {
+                       ERR("Buffer type not supported for kernel domain");
+                       goto error;
+               }
+               dom.buf_type = LTTNG_BUFFER_GLOBAL;
+       } else {
+               dom.type = LTTNG_DOMAIN_UST;
+
+               if (opt_buffers_uid && opt_buffers_pid) {
+                       ERR("Only one domain can be specified");
+                       goto error;
+               }
+               if (opt_buffers_pid) {
+                       dom.buf_type = LTTNG_BUFFER_PER_PID;
+               } else {
+                       /* Defaults to per UID */
+                       dom.buf_type = LTTNG_BUFFER_PER_UID;
+               }
+       }
+
+       handle = lttng_create_handle(session_name, &dom);
+       if (handle == NULL) {
+               ret = -1;
+               goto error;
+       }
+
+       if (opt_max_key_count) {
+               unsigned long long max_key_count;
+               if (utils_parse_unsigned_long_long(opt_max_key_count, &max_key_count) != 0) {
+                       ERR("Failed to parse `%s` as an integer.", opt_max_key_count);
+                       goto error;
+               }
+
+               dimensions_sizes[0] = max_key_count;
+       } else {
+               dimensions_sizes[0] = LTTNG_MAP_DEFAULT_SIZE;
+       }
+
+       if (opt_bitness) {
+               if (utils_parse_unsigned_long_long(opt_bitness, &bitness) != 0) {
+                       ERR("Failed to parse `%s` as an integer.", opt_bitness);
+                       goto error;
+               }
+               switch (bitness) {
+               case 32:
+                       bitness_type = LTTNG_MAP_BITNESS_32BITS;
+                       break;
+               case 64:
+                       bitness_type = LTTNG_MAP_BITNESS_64BITS;
+                       break;
+               default:
+                       ERR("Bitness %llu not supported", bitness);
+                       goto error;
+               }
+
+       } else {
+               bitness_type = LTTNG_MAP_BITNESS_64BITS;
+       }
+
+
+       if (opt_overflow) {
+               boundary_policy = LTTNG_MAP_BOUNDARY_POLICY_OVERFLOW;
+       } else {
+               boundary_policy = LTTNG_MAP_BOUNDARY_POLICY_OVERFLOW;
+       }
+
+       status = lttng_map_create(opt_map_name, 1, dimensions_sizes, dom.type,
+                       dom.buf_type, bitness_type, boundary_policy,
+                       opt_coalesce_hits, &map);
+       if (status != LTTNG_MAP_STATUS_OK) {
+               ERR("Creating map \"%s\"", opt_map_name);
+               goto error;
+       }
+
+       error_code_ret = lttng_add_map(handle, map);
+       if (error_code_ret != LTTNG_OK) {
+               ERR("Adding map \"%s\": %s", opt_map_name,
+                               lttng_strerror(error_code_ret));
+               lttng_map_destroy(map);
+               goto error;
+       }
+
+       MSG("Map %s created.", opt_map_name);
+       ret = CMD_SUCCESS;
+
+       lttng_map_destroy(map);
+
+       goto end;
+
+error:
+       ret = CMD_ERROR;
+end:
+       argpar_parse_ret_fini(&argpar_parse_ret);
+       free(opt_session_name);
+       free(opt_max_key_count);
+       free(opt_bitness);
+       lttng_destroy_handle(handle);
+       return ret;
+}
index b3b1dade11174d7b1481c4d599f6658267bead79..f42720df681d3e04def2629152412ab6bfb48cec 100644 (file)
 /* For lttng_event_rule_type_str(). */
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/lttng.h>
+#include "lttng/event-rule/kernel-function.h"
+#include "lttng/event-rule/kernel-probe.h"
+#include "lttng/event-rule/syscall.h"
+#include <lttng/event-rule/tracepoint.h>
+#include "lttng/event-rule/userspace-probe.h"
+#include "lttng/kernel-function.h"
+#include "lttng/kernel-probe.h"
+#include "lttng/log-level-rule.h"
+#include "lttng/map-key-internal.h"
 #include "common/filter/filter-ast.h"
 #include "common/filter/filter-ir.h"
 #include "common/dynamic-array.h"
@@ -69,6 +78,10 @@ enum {
        OPT_URL,
        OPT_PATH,
 
+       OPT_SESSION_NAME,
+       OPT_MAP_NAME,
+       OPT_KEY,
+
        OPT_CAPTURE,
 };
 
@@ -299,6 +312,98 @@ end:
        return ret;
 }
 
+static int parse_kernel_function_opts(const char *source,
+               struct lttng_kernel_function_location **location)
+{
+       int ret = 0;
+       int match;
+       char s_hex[19];
+       char name[LTTNG_SYMBOL_NAME_LEN];
+       char *symbol_name = NULL;
+       uint64_t offset;
+
+       /* Check for symbol+offset. */
+       match = sscanf(source,
+                       "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
+                       "[^'+']+%18s",
+                       name, s_hex);
+       if (match == 2) {
+               if (*s_hex == '\0') {
+                       ERR("Kernel function symbol offset is missing.");
+                       goto error;
+               }
+
+               symbol_name = strndup(name, LTTNG_SYMBOL_NAME_LEN);
+               if (!symbol_name) {
+                       PERROR("Failed to copy kernel function location symbol name.");
+                       goto error;
+               }
+               offset = strtoul(s_hex, NULL, 0);
+
+               *location = lttng_kernel_function_location_symbol_create(
+                               symbol_name, offset);
+               if (!*location) {
+                       ERR("Failed to create symbol kernel function location.");
+                       goto error;
+               }
+
+               goto end;
+       }
+
+       /* Check for symbol. */
+       if (isalpha(name[0]) || name[0] == '_') {
+               match = sscanf(source,
+                               "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
+                               "s",
+                               name);
+               if (match == 1) {
+                       symbol_name = strndup(name, LTTNG_SYMBOL_NAME_LEN);
+                       if (!symbol_name) {
+                               ERR("Failed to copy kernel function location symbol name.");
+                               goto error;
+                       }
+
+                       *location = lttng_kernel_function_location_symbol_create(
+                                       symbol_name, 0);
+                       if (!*location) {
+                               ERR("Failed to create symbol kernel function location.");
+                               goto error;
+                       }
+
+                       goto end;
+               }
+       }
+
+       /* Check for address. */
+       match = sscanf(source, "%18s", s_hex);
+       if (match > 0) {
+               uint64_t address;
+
+               if (*s_hex == '\0') {
+                       ERR("Invalid kernel function location address.");
+                       goto error;
+               }
+
+               address = strtoul(s_hex, NULL, 0);
+               *location = lttng_kernel_function_location_address_create(address);
+               if (!*location) {
+                       ERR("Failed to create symbol kernel function location.");
+                       goto error;
+               }
+
+               goto end;
+       }
+
+error:
+       /* No match */
+       ret = -1;
+       *location = NULL;
+
+end:
+       free(symbol_name);
+       return ret;
+}
+
 static
 struct lttng_event_expr *ir_op_load_expr_to_event_expr(
                const struct ir_load_expression *load_expr,
@@ -537,10 +642,12 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
        char *error = NULL;
        int consumed_args = -1;
        struct lttng_kernel_probe_location *kernel_probe_location = NULL;
+       struct lttng_kernel_function_location *kernel_function_location = NULL;
        struct lttng_userspace_probe_location *userspace_probe_location = NULL;
        struct parse_event_rule_res res = { 0 };
        struct lttng_event_expr *event_expr = NULL;
        struct filter_parser_ctx *parser_ctx = NULL;
+       struct lttng_log_level_rule *log_level_rule = NULL;
 
        /* Was the -a/--all flag provided? */
        bool all_events = false;
@@ -627,14 +734,18 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
                        /* Event rule types */
                        case OPT_FUNCTION:
                                if (!assign_event_rule_type(&event_rule_type,
-                                               LTTNG_EVENT_RULE_TYPE_KRETPROBE)) {
+                                               LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION)) {
+                                       goto error;
+                               }
+
+                               if (!assign_string(&source, item_opt->arg, "source")) {
                                        goto error;
                                }
 
                                break;
                        case OPT_PROBE:
                                if (!assign_event_rule_type(&event_rule_type,
-                                               LTTNG_EVENT_RULE_TYPE_KPROBE)) {
+                                               LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE)) {
                                        goto error;
                                }
 
@@ -645,7 +756,7 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
                                break;
                        case OPT_USERSPACE_PROBE:
                                if (!assign_event_rule_type(&event_rule_type,
-                                               LTTNG_EVENT_RULE_TYPE_UPROBE)) {
+                                               LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE)) {
                                        goto error;
                                }
 
@@ -817,9 +928,9 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
 
        /* Validate event rule type against domain. */
        switch (event_rule_type) {
-       case LTTNG_EVENT_RULE_TYPE_KPROBE:
-       case LTTNG_EVENT_RULE_TYPE_KRETPROBE:
-       case LTTNG_EVENT_RULE_TYPE_UPROBE:
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE:
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION:
+       case LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE:
        case LTTNG_EVENT_RULE_TYPE_SYSCALL:
                if (domain_type != LTTNG_DOMAIN_KERNEL) {
                        ERR("Event type not available for user-space tracing.");
@@ -938,15 +1049,20 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
                        }
 
                        if (loglevel_only) {
-                               event_rule_status = lttng_event_rule_tracepoint_set_log_level(
-                                               res.er,
-                                               loglevel);
+                               log_level_rule = lttng_log_level_rule_exactly_create(loglevel);
                        } else {
-                               event_rule_status = lttng_event_rule_tracepoint_set_log_level_range_lower_bound(
-                                               res.er,
-                                               loglevel);
+                               log_level_rule = lttng_log_level_rule_at_least_as_severe_as_create(loglevel);
+                       }
+
+                       if (log_level_rule == NULL) {
+                               ERR("Failed to create log level rule object.");
+                               goto error;
                        }
 
+                       event_rule_status =
+                               lttng_event_rule_tracepoint_set_log_level_rule(
+                                       res.er, log_level_rule);
+
                        if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
                                ERR("Failed to set log level on event fule.");
                                goto error;
@@ -955,16 +1071,11 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
 
                break;
        }
-       case LTTNG_EVENT_RULE_TYPE_KPROBE:
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE:
        {
                int ret;
                enum lttng_event_rule_status event_rule_status;
 
-               res.er = lttng_event_rule_kprobe_create();
-               if (!res.er) {
-                       ERR("Failed to create kprobe event rule.");
-                       goto error;
-               }
 
                ret = parse_kernel_probe_opts(source, &kernel_probe_location);
                if (ret) {
@@ -972,22 +1083,49 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
                        goto error;
                }
 
-               event_rule_status = lttng_event_rule_kprobe_set_name(res.er, tracepoint_name);
+               assert(kernel_probe_location);
+               res.er = lttng_event_rule_kernel_probe_create(kernel_probe_location);
+               if (!res.er) {
+                       ERR("Failed to create kprobe event rule.");
+                       goto error;
+               }
+
+               event_rule_status = lttng_event_rule_kernel_probe_set_event_name(res.er, tracepoint_name);
                if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
                        ERR("Failed to set kprobe event rule's name to '%s'.", tracepoint_name);
                        goto error;
                }
 
-               assert(kernel_probe_location);
-               event_rule_status = lttng_event_rule_kprobe_set_location(res.er, kernel_probe_location);
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION:
+       {
+               int ret;
+               enum lttng_event_rule_status event_rule_status;
+
+
+               ret = parse_kernel_function_opts(source, &kernel_function_location);
+               if (ret) {
+                       ERR("Failed to parse kernel function location.");
+                       goto error;
+               }
+
+               assert(kernel_function_location);
+               res.er = lttng_event_rule_kernel_function_create(kernel_function_location);
+               if (!res.er) {
+                       ERR("Failed to create kfunction event rule.");
+                       goto error;
+               }
+
+               event_rule_status = lttng_event_rule_kernel_function_set_event_name(res.er, tracepoint_name);
                if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       ERR("Failed to set kprobe event rule's location.");
+                       ERR("Failed to set kfunction event rule's name to '%s'.", tracepoint_name);
                        goto error;
                }
 
                break;
        }
-       case LTTNG_EVENT_RULE_TYPE_UPROBE:
+       case LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE:
        {
                int ret;
                enum lttng_event_rule_status event_rule_status;
@@ -999,20 +1137,13 @@ struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
                        goto error;
                }
 
-               res.er = lttng_event_rule_uprobe_create();
+               res.er = lttng_event_rule_userspace_probe_create(userspace_probe_location);
                if (!res.er) {
                        ERR("Failed to create userspace probe event rule.");
                        goto error;
                }
 
-               event_rule_status = lttng_event_rule_uprobe_set_location(
-                               res.er, userspace_probe_location);
-               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       ERR("Failed to set user space probe event rule's location.");
-                       goto error;
-               }
-
-               event_rule_status = lttng_event_rule_uprobe_set_name(
+               event_rule_status = lttng_event_rule_userspace_probe_set_event_name(
                                res.er, tracepoint_name);
                if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
                        ERR("Failed to set user space probe event rule's name to '%s'.",
@@ -1080,6 +1211,7 @@ end:
        strutils_free_null_terminated_array_of_strings(exclusion_list);
        lttng_kernel_probe_location_destroy(kernel_probe_location);
        lttng_userspace_probe_location_destroy(userspace_probe_location);
+       lttng_log_level_rule_destroy(log_level_rule);
        return res;
 }
 
@@ -1096,7 +1228,7 @@ struct lttng_condition *handle_condition_event(int *argc, const char ***argv)
                goto error;
        }
 
-       c = lttng_condition_event_rule_create(res.er);
+       c = lttng_condition_on_event_create(res.er);
        lttng_event_rule_destroy(res.er);
        res.er = NULL;
        if (!c) {
@@ -1112,9 +1244,12 @@ struct lttng_condition *handle_condition_event(int *argc, const char ***argv)
 
                assert(expr);
                assert(*expr);
-               status = lttng_condition_event_rule_append_capture_descriptor(
+               status = lttng_condition_on_event_append_capture_descriptor(
                                c, *expr);
                if (status != LTTNG_CONDITION_STATUS_OK) {
+                       if (status == LTTNG_CONDITION_STATUS_UNSUPPORTED) {
+                               ERR("The capture feature is unsupported by the event-rule type");
+                       }
                        goto error;
                }
 
@@ -1764,6 +1899,139 @@ end:
        return action;
 }
 
+static const struct argpar_opt_descr incr_value_action_opt_descrs[] = {
+       { OPT_SESSION_NAME, 's', "session", true },
+       { OPT_MAP_NAME, 'm', "map", true },
+       { OPT_KEY, '\0', "key", true },
+       ARGPAR_OPT_DESCR_SENTINEL
+};
+
+static
+struct lttng_action *handle_action_incr_value(int *argc,
+               const char ***argv)
+{
+       struct lttng_action *action = NULL;
+       struct argpar_state *state = NULL;
+       struct argpar_item *item = NULL;
+       struct lttng_map_key *key = NULL;
+       char *session_name_arg = NULL, *map_name_arg = NULL;
+       char *key_arg = NULL;
+       char *error = NULL;
+       enum lttng_action_status action_status;
+
+       state = argpar_state_create(*argc, *argv, incr_value_action_opt_descrs);
+       if (!state) {
+               ERR("Failed to allocate an argpar state.");
+               goto error;
+       }
+
+       while (true) {
+               enum argpar_state_parse_next_status status;
+
+               ARGPAR_ITEM_DESTROY_AND_RESET(item);
+               status = argpar_state_parse_next(state, &item, &error);
+               if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
+                       ERR("%s", error);
+                       goto error;
+               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
+                       /* Just stop parsing here. */
+                       break;
+               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
+                       break;
+               }
+
+               assert(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
+
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       struct argpar_item_opt *item_opt =
+                               (struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_SESSION_NAME:
+                               if (!assign_string(&session_name_arg, item_opt->arg, "--session/-s")) {
+                                       goto error;
+                               }
+                               break;
+                       case OPT_MAP_NAME:
+                               if (!assign_string(&map_name_arg, item_opt->arg, "--map/-m")) {
+                                       goto error;
+                               }
+                               break;
+                       case OPT_KEY:
+                               if (!assign_string(&key_arg, item_opt->arg, "--key")) {
+                                       goto error;
+                               }
+                               break;
+                       default:
+                               abort();
+                       }
+               }
+       }
+
+       *argc -= argpar_state_get_ingested_orig_args(state);
+       *argv += argpar_state_get_ingested_orig_args(state);
+
+       if (!session_name_arg) {
+               ERR("Missing session name.");
+               goto error;
+       }
+
+       if (!map_name_arg) {
+               ERR("Missing map name.");
+               goto error;
+       }
+
+       if (!key_arg) {
+               ERR("Missing key");
+               goto error;
+       }
+
+       key = lttng_map_key_parse_from_string(key_arg);
+       if (!key) {
+               ERR("Error parsing key argument");
+               goto error;
+       }
+
+       action = lttng_action_incr_value_create();
+       if (!action) {
+               ERR("Failed to allocate incr-value action.");
+               goto error;
+       }
+
+       action_status = lttng_action_incr_value_set_session_name(action,
+                       session_name_arg);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Failed to set action incr-value's session name.");
+               goto error;
+       }
+
+       action_status = lttng_action_incr_value_set_map_name(action,
+                       map_name_arg);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Failed to set action incr-value's map name.");
+               goto error;
+       }
+
+       action_status = lttng_action_incr_value_set_key(action, key);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Failed to set action incr-value's key");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       lttng_action_destroy(action);
+       action = NULL;
+
+end:
+       lttng_map_key_destroy(key);
+       free(session_name_arg);
+       free(map_name_arg);
+       free(key_arg);
+       return action;
+}
+
 struct action_descr {
        const char *name;
        struct lttng_action *(*handler) (int *argc, const char ***argv);
@@ -1776,6 +2044,7 @@ struct action_descr action_descrs[] = {
        { "stop-session", handle_action_stop_session },
        { "rotate-session", handle_action_rotate_session },
        { "snapshot-session", handle_action_snapshot_session },
+       { "incr-value", handle_action_incr_value },
 };
 
 static
@@ -1834,6 +2103,30 @@ struct argpar_opt_descr add_trigger_options[] = {
        ARGPAR_OPT_DESCR_SENTINEL,
 };
 
+static
+bool action_is_tracer_executed(const struct lttng_action *action)
+{
+       bool is_tracer_executed;
+       switch (lttng_action_get_type(action)) {
+       case LTTNG_ACTION_TYPE_NOTIFY:
+       case LTTNG_ACTION_TYPE_START_SESSION:
+       case LTTNG_ACTION_TYPE_STOP_SESSION:
+       case LTTNG_ACTION_TYPE_ROTATE_SESSION:
+       case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
+               is_tracer_executed = false;
+               goto end;
+       case LTTNG_ACTION_TYPE_INCREMENT_VALUE:
+               is_tracer_executed = true;
+               goto end;
+       case LTTNG_ACTION_TYPE_GROUP:
+       default:
+               abort();
+       }
+
+end:
+       return is_tracer_executed;
+}
+
 static
 void lttng_actions_destructor(void *p)
 {
@@ -2021,6 +2314,18 @@ int cmd_add_trigger(int argc, const char **argv)
                enum lttng_action_status status;
 
                action = lttng_dynamic_pointer_array_steal_pointer(&actions, i);
+               if (action_is_tracer_executed(action)) {
+                       if (fire_every_str || fire_once_after_str) {
+                               /*
+                                * Firing policy with tracer-executed actions
+                                * (`incr-value`) is not supported at the
+                                * moment. It's not clear how the tracers will
+                                * handle the different policies efficiently.
+                                */
+                               ERR("Can't use --fire-once-after or --fire-every with tracer executed action (incr-value)");
+                               goto error;
+                       }
+               }
 
                status = lttng_action_group_add_action(action_group, action);
                if (status != LTTNG_ACTION_STATUS_OK) {
diff --git a/src/bin/lttng/commands/disable_map.c b/src/bin/lttng/commands/disable_map.c
new file mode 100644 (file)
index 0000000..5985b53
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <stdio.h>
+
+#include <lttng/map/map.h>
+
+#include "common/argpar/argpar.h"
+
+#include "../command.h"
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-disable-map.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP,
+       OPT_KERNEL,
+       OPT_SESSION,
+       OPT_USERSPACE,
+};
+
+static const
+struct argpar_opt_descr disable_map_options[] = {
+       { OPT_HELP, 'h', "help", false },
+       { OPT_SESSION, 's', "session", true },
+       { OPT_USERSPACE, 'u', "userspace", false },
+       { OPT_KERNEL, 'k', "kernel", false },
+       ARGPAR_OPT_DESCR_SENTINEL,
+};
+
+static
+bool assign_string(char **dest, const char *src, const char *opt_name)
+{
+       bool ret;
+
+       if (*dest) {
+               ERR("Duplicate %s given.", opt_name);
+               goto error;
+       }
+
+       *dest = strdup(src);
+       if (!*dest) {
+               ERR("Failed to allocate %s string.", opt_name);
+               goto error;
+       }
+
+       ret = true;
+       goto end;
+
+error:
+       ret = false;
+
+end:
+       return ret;
+}
+
+int cmd_disable_map(int argc, const char **argv)
+{
+       int ret, i;
+       struct argpar_parse_ret argpar_parse_ret = { 0 };
+       const char *opt_map_name = NULL;
+       enum lttng_error_code error_code_ret;
+       bool opt_userspace = false, opt_kernel = false;
+       char *opt_session_name = NULL, *session_name = NULL;
+       struct lttng_domain dom = {0};
+       struct lttng_handle *handle;
+
+       argpar_parse_ret = argpar_parse(argc - 1, argv + 1,
+               disable_map_options, true);
+       if (!argpar_parse_ret.items) {
+               ERR("%s", argpar_parse_ret.error);
+               goto error;
+       }
+
+       for (i = 0; i < argpar_parse_ret.items->n_items; i++) {
+               struct argpar_item *item = argpar_parse_ret.items->items[i];
+
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       struct argpar_item_opt *item_opt =
+                               (struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_HELP:
+                               SHOW_HELP();
+                               ret = 0;
+                               goto end;
+                       case OPT_SESSION:
+                               if (!assign_string(&opt_session_name, item_opt->arg,
+                                               "-s/--session")) {
+                                       goto error;
+                               }
+                               break;
+                       case OPT_USERSPACE:
+                               opt_userspace = true;
+                               break;
+                       case OPT_KERNEL:
+                               opt_kernel = true;
+                               break;
+                       default:
+                               abort();
+                       }
+
+               } else {
+                       struct argpar_item_non_opt *item_non_opt =
+                               (struct argpar_item_non_opt *) item;
+
+                       if (opt_map_name) {
+                               ERR("Unexpected argument: %s", item_non_opt->arg);
+                               goto error;
+                       }
+
+                       opt_map_name = item_non_opt->arg;
+               }
+       }
+
+       if (!opt_map_name) {
+               ERR("Missing `name` argument.");
+               goto error;
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       goto error;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       /* Check that one and only one domain option was provided. */
+       ret = print_missing_or_multiple_domains(
+                       opt_kernel + opt_userspace, false);
+       if (ret) {
+               goto error;
+       }
+
+       if (opt_kernel) {
+               dom.type = LTTNG_DOMAIN_KERNEL;
+               dom.buf_type = LTTNG_BUFFER_GLOBAL;
+       } else {
+               dom.type=LTTNG_DOMAIN_UST;
+               dom.buf_type = LTTNG_BUFFER_PER_UID;
+       }
+
+       handle = lttng_create_handle(session_name, &dom);
+       if (handle == NULL) {
+               ret = -1;
+               goto error;
+       }
+
+       error_code_ret = lttng_disable_map(handle, opt_map_name);
+       if (error_code_ret != LTTNG_OK) {
+               ERR("Error disabling map \"%s\"", opt_map_name);
+               goto error;
+       }
+
+       MSG("Disabled map `%s`.", opt_map_name);
+
+       ret = 0;
+       goto end;
+
+error:
+       ret = 1;
+
+end:
+       argpar_parse_ret_fini(&argpar_parse_ret);
+
+       return ret;
+}
diff --git a/src/bin/lttng/commands/enable_map.c b/src/bin/lttng/commands/enable_map.c
new file mode 100644 (file)
index 0000000..f246fb9
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <stdio.h>
+
+#include <lttng/map/map.h>
+
+#include "common/argpar/argpar.h"
+
+#include "../command.h"
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-enable-map.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP,
+       OPT_KERNEL,
+       OPT_SESSION,
+       OPT_USERSPACE,
+};
+
+static const
+struct argpar_opt_descr enable_map_options[] = {
+       { OPT_HELP, 'h', "help", false },
+       { OPT_SESSION, 's', "session", true },
+       { OPT_USERSPACE, 'u', "userspace", false },
+       { OPT_KERNEL, 'k', "kernel", false },
+       ARGPAR_OPT_DESCR_SENTINEL,
+};
+
+static
+bool assign_string(char **dest, const char *src, const char *opt_name)
+{
+       bool ret;
+
+       if (*dest) {
+               ERR("Duplicate %s given.", opt_name);
+               goto error;
+       }
+
+       *dest = strdup(src);
+       if (!*dest) {
+               ERR("Failed to allocate %s string.", opt_name);
+               goto error;
+       }
+
+       ret = true;
+       goto end;
+
+error:
+       ret = false;
+
+end:
+       return ret;
+}
+
+int cmd_enable_map(int argc, const char **argv)
+{
+       int ret, i;
+       struct argpar_parse_ret argpar_parse_ret = { 0 };
+       const char *opt_map_name = NULL;
+       enum lttng_error_code error_code_ret;
+       bool opt_userspace = false, opt_kernel = false;
+       char *opt_session_name = NULL, *session_name = NULL;
+       struct lttng_domain dom = {0};
+       struct lttng_handle *handle;
+
+       argpar_parse_ret = argpar_parse(argc - 1, argv + 1,
+               enable_map_options, true);
+       if (!argpar_parse_ret.items) {
+               ERR("%s", argpar_parse_ret.error);
+               goto error;
+       }
+
+       for (i = 0; i < argpar_parse_ret.items->n_items; i++) {
+               struct argpar_item *item = argpar_parse_ret.items->items[i];
+
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       struct argpar_item_opt *item_opt =
+                               (struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_HELP:
+                               SHOW_HELP();
+                               ret = 0;
+                               goto end;
+                       case OPT_SESSION:
+                               if (!assign_string(&opt_session_name, item_opt->arg,
+                                               "-s/--session")) {
+                                       goto error;
+                               }
+                               break;
+                       case OPT_USERSPACE:
+                               opt_userspace = true;
+                               break;
+                       case OPT_KERNEL:
+                               opt_kernel = true;
+                               break;
+                       default:
+                               abort();
+                       }
+
+               } else {
+                       struct argpar_item_non_opt *item_non_opt =
+                               (struct argpar_item_non_opt *) item;
+
+                       if (opt_map_name) {
+                               ERR("Unexpected argument: %s", item_non_opt->arg);
+                               goto error;
+                       }
+
+                       opt_map_name = item_non_opt->arg;
+               }
+       }
+
+       if (!opt_map_name) {
+               ERR("Missing `name` argument.");
+               goto error;
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       goto error;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       /* Check that one and only one domain option was provided. */
+       ret = print_missing_or_multiple_domains(
+                       opt_kernel + opt_userspace, false);
+       if (ret) {
+               goto error;
+       }
+
+       if (opt_kernel) {
+               dom.type = LTTNG_DOMAIN_KERNEL;
+               dom.buf_type = LTTNG_BUFFER_GLOBAL;
+       } else {
+               dom.type=LTTNG_DOMAIN_UST;
+               dom.buf_type = LTTNG_BUFFER_PER_UID;
+       }
+
+       handle = lttng_create_handle(session_name, &dom);
+       if (handle == NULL) {
+               ret = -1;
+               goto error;
+       }
+
+       error_code_ret = lttng_enable_map(handle, opt_map_name);
+       if (error_code_ret != LTTNG_OK) {
+               ERR("Error enabling map \"%s\"", opt_map_name);
+               goto error;
+       }
+
+       MSG("Enabled map `%s`.", opt_map_name);
+
+       ret = 0;
+       goto end;
+
+error:
+       ret = 1;
+
+end:
+       argpar_parse_ret_fini(&argpar_parse_ret);
+
+       return ret;
+}
index 4540177941faf9e30f610caf448ff6728c486a45..77a49e17208fe077a752df4a2037ad3f405ede3b 100644 (file)
@@ -19,6 +19,7 @@
 #include <common/time.h>
 #include <common/tracker.h>
 #include <lttng/lttng.h>
+#include <lttng/map/map.h>
 
 #include "../command.h"
 
@@ -28,6 +29,7 @@ static int opt_jul;
 static int opt_log4j;
 static int opt_python;
 static char *opt_channel;
+static char *opt_map;
 static int opt_domain;
 static int opt_fields;
 static int opt_syscall;
@@ -63,6 +65,7 @@ static struct poptOption long_options[] = {
        {"python",      'p', POPT_ARG_VAL, &opt_python, 1, 0, 0},
        {"userspace",   'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
        {"channel",     'c', POPT_ARG_STRING, &opt_channel, 0, 0, 0},
+       {"map",         'm', POPT_ARG_STRING, &opt_map, 0, 0, 0},
        {"domain",      'd', POPT_ARG_VAL, &opt_domain, 1, 0, 0},
        {"fields",      'f', POPT_ARG_VAL, &opt_fields, 1, 0, 0},
        {"syscall",     'S', POPT_ARG_VAL, &opt_syscall, 1, 0, 0},
@@ -1367,6 +1370,58 @@ skip_stats_printing:
        return;
 }
 
+static void print_map(const struct lttng_map *map)
+{
+       const char *map_name;
+       enum lttng_map_status map_status;
+       enum lttng_buffer_type buffer_type;
+       enum lttng_map_bitness bitness;
+       enum lttng_map_boundary_policy boundary_policy;
+       uint64_t bucket_count;
+       bool is_enabled;
+
+       bitness = lttng_map_get_bitness(map);
+       is_enabled = lttng_map_get_is_enabled(map);
+       buffer_type = lttng_map_get_buffer_type(map);
+
+       boundary_policy = lttng_map_get_boundary_policy(map);
+
+       map_status = lttng_map_get_name(map, &map_name);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Failed to get map name");
+               goto end;
+       }
+
+       map_status = lttng_map_get_dimension_length(map, 0, &bucket_count);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Failed to bucket count");
+               goto end;
+       }
+
+       MSG("- %s (%s)", map_name, is_enabled ? "enabled": "disabled");
+       MSG("%sAttributes:", indent4);
+       MSG("%sBitness: %s", indent6, bitness == LTTNG_MAP_BITNESS_32BITS ? "32" : "64");
+       _MSG("%sCounter type: ", indent6);
+       switch (buffer_type) {
+       case LTTNG_BUFFER_PER_PID:
+               MSG("per-pid");
+               break;
+       case LTTNG_BUFFER_PER_UID:
+               MSG("per-uid");
+               break;
+       case LTTNG_BUFFER_GLOBAL:
+               MSG("global");
+               break;
+       default:
+               abort();
+       }
+       MSG("%sBoundary policy: %s", indent6,
+                       boundary_policy == LTTNG_MAP_BOUNDARY_POLICY_OVERFLOW ? "OVERFLOW" : "<unknown>");
+       MSG("%sBucket count: %"PRIu64, indent6, bucket_count);
+end:
+       return;
+}
+
 /*
  * Machine interface
  * Print a list of channel
@@ -1508,6 +1563,68 @@ error_channels:
        return ret;
 }
 
+/*
+ * List map(s) of session and domain.
+ *
+ * If map_name is NULL, all maps are listed.
+ */
+static int list_maps(const char *desired_map_name)
+{
+       struct lttng_map_list *map_list = NULL;
+       enum lttng_map_status map_status;
+       enum lttng_error_code ret_code;
+       unsigned int i, map_count;
+       int ret = CMD_SUCCESS;
+
+       DBG("Listing map(s) (%s)", desired_map_name ? : "<all>");
+
+       ret_code = lttng_list_maps(handle, &map_list);
+       if (ret_code != LTTNG_OK) {
+               ERR("Error getting map list");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       map_status = lttng_map_list_get_count(map_list, &map_count);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Error getting map list element count");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       MSG("Maps:\n-------------");
+       for (i = 0; i < map_count; i++) {
+               const struct lttng_map *map = NULL;
+               const char *map_name = NULL;
+               map = lttng_map_list_get_at_index(map_list, i);
+               if (!map) {
+                       ret = CMD_ERROR;
+                       ERR("Error getting map from list: index = %u", i);
+                       goto end;
+               }
+
+               map_status = lttng_map_get_name(map, &map_name);
+               if (map_status != LTTNG_MAP_STATUS_OK) {
+                       ERR("Error getting map name");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               if (desired_map_name != NULL) {
+                       if (strncmp(map_name, desired_map_name, NAME_MAX) == 0) {
+                               print_map(map);
+                               break;
+                       }
+               } else {
+                       print_map(map);
+               }
+       }
+end:
+       // Should be in its own patch.
+       lttng_map_list_destroy(map_list);
+       return ret;
+}
+
 static const char *get_capitalized_process_attr_str(enum lttng_process_attr process_attr)
 {
        switch (process_attr) {
@@ -2460,6 +2577,11 @@ int cmd_list(int argc, const char **argv)
                                goto end;
                        }
 
+                       ret = list_maps(opt_map);
+                       if (ret) {
+                               goto end;
+                       }
+
                        if (lttng_opt_mi) {
                                /* Close domain and domain element */
                                ret = mi_lttng_close_multi_element(writer, 2);
@@ -2560,6 +2682,11 @@ int cmd_list(int argc, const char **argv)
                                        goto end;
                                }
 
+                               ret = list_maps(opt_map);
+                               if (ret) {
+                                       goto end;
+                               }
+
 next_domain:
                                if (lttng_opt_mi) {
                                        /* Close domain element */
index a6f0211938649e269176a3fd60a75de6184df097..e9ad3d661af05c3ea050b4dcb2bd87baeea14a4e 100644 (file)
 #include "common/mi-lttng.h"
 /* For lttng_condition_type_str(). */
 #include "lttng/condition/condition-internal.h"
+#include "lttng/condition/on-event.h"
+#include "lttng/condition/on-event-internal.h"
 /* For lttng_domain_type_str(). */
 #include "lttng/domain-internal.h"
+#include "lttng/event-rule/event-rule-internal.h"
+#include "lttng/event-rule/kernel-probe.h"
+#include "lttng/event-rule/kernel-probe-internal.h"
+#include "lttng/event-rule/syscall.h"
+#include "lttng/event-rule/tracepoint.h"
+#include "lttng/event-rule/userspace-probe.h"
+#include "lttng/map-key.h"
+#include "lttng/map-key-internal.h"
+#include "lttng/trigger/trigger-internal.h"
+#include "lttng/kernel-probe.h"
 
 #ifdef LTTNG_EMBED_HELP
 static const char help_msg[] =
@@ -43,6 +55,7 @@ void print_event_rule_tracepoint(const struct lttng_event_rule *event_rule)
        const char *pattern;
        const char *filter;
        int log_level;
+       const struct lttng_log_level_rule *log_level_rule = NULL;
        unsigned int exclusions_count;
        int i;
 
@@ -65,20 +78,33 @@ void print_event_rule_tracepoint(const struct lttng_event_rule *event_rule)
                assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
        }
 
-       event_rule_status = lttng_event_rule_tracepoint_get_log_level(
-                       event_rule, &log_level);
+       event_rule_status = lttng_event_rule_tracepoint_get_log_level_rule(
+                       event_rule, &log_level_rule);
        if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
-               enum lttng_loglevel_type log_level_type;
+               enum lttng_log_level_rule_status llr_status;
                const char *log_level_op;
 
-               event_rule_status = lttng_event_rule_tracepoint_get_log_level_type(
-                               event_rule, &log_level_type);
-               assert(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
-               assert(log_level_type == LTTNG_EVENT_LOGLEVEL_RANGE ||
-                               log_level_type == LTTNG_EVENT_LOGLEVEL_SINGLE);
+               switch (lttng_log_level_rule_get_type(log_level_rule)) {
+               case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+                       llr_status = lttng_log_level_rule_exactly_get_level(
+                                       log_level_rule, &log_level);
+                       log_level_op = "==";
+                       break;
+               case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+                       log_level_op = "<=";
+                       llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level(
+                                       log_level_rule, &log_level);
+                       break;
+               default:
+                       abort();
+               }
 
-               log_level_op = (log_level_type == LTTNG_EVENT_LOGLEVEL_RANGE ? "<=" : "==");
+               assert(llr_status == LTTNG_LOG_LEVEL_RULE_STATUS_OK);
 
+               /* TODO: here the raw level value must be printed since the
+                * value could have no known string equivalent, the string
+                * representation is only a "convenience".
+                */
                _MSG(", log level %s %s", log_level_op,
                                mi_lttng_loglevel_string(
                                                log_level, domain_type));
@@ -160,21 +186,21 @@ end:
 }
 
 static
-void print_event_rule_kprobe(const struct lttng_event_rule *event_rule)
+void print_event_rule_kernel_probe(const struct lttng_event_rule *event_rule)
 {
        enum lttng_event_rule_status event_rule_status;
        const char *name;
        const struct lttng_kernel_probe_location *location;
 
-       assert(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_KPROBE);
+       assert(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE);
 
-       event_rule_status = lttng_event_rule_kprobe_get_name(event_rule, &name);
+       event_rule_status = lttng_event_rule_kernel_probe_get_event_name(event_rule, &name);
        if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
                ERR("Failed to get kprobe event rule's name.");
                goto end;
        }
 
-       event_rule_status = lttng_event_rule_kprobe_get_location(
+       event_rule_status = lttng_event_rule_kernel_probe_get_location(
                        event_rule, &location);
        if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
                ERR("Failed to get kprobe event rule's location.");
@@ -192,22 +218,22 @@ end:
 }
 
 static
-void print_event_rule_uprobe(const struct lttng_event_rule *event_rule)
+void print_event_rule_userspace_probe(const struct lttng_event_rule *event_rule)
 {
        enum lttng_event_rule_status event_rule_status;
        const char *name;
        const struct lttng_userspace_probe_location *location;
        enum lttng_userspace_probe_location_type userspace_probe_location_type;
 
-       assert(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_UPROBE);
+       assert(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE);
 
-       event_rule_status = lttng_event_rule_uprobe_get_name(event_rule, &name);
+       event_rule_status = lttng_event_rule_userspace_probe_get_event_name(event_rule, &name);
        if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
                ERR("Failed to get uprobe event rule's name.");
                goto end;
        }
 
-       event_rule_status = lttng_event_rule_uprobe_get_location(
+       event_rule_status = lttng_event_rule_userspace_probe_get_location(
                        event_rule, &location);
        if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
                ERR("Failed to get uprobe event rule's location.");
@@ -280,11 +306,11 @@ void print_event_rule(const struct lttng_event_rule *event_rule)
        case LTTNG_EVENT_RULE_TYPE_TRACEPOINT:
                print_event_rule_tracepoint(event_rule);
                break;
-       case LTTNG_EVENT_RULE_TYPE_KPROBE:
-               print_event_rule_kprobe(event_rule);
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE:
+               print_event_rule_kernel_probe(event_rule);
                break;
-       case LTTNG_EVENT_RULE_TYPE_UPROBE:
-               print_event_rule_uprobe(event_rule);
+       case LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE:
+               print_event_rule_userspace_probe(event_rule);
                break;
        case LTTNG_EVENT_RULE_TYPE_SYSCALL:
                print_event_rule_syscall(event_rule);
@@ -295,16 +321,180 @@ void print_event_rule(const struct lttng_event_rule *event_rule)
 }
 
 static
-void print_condition_event_rule_hit(const struct lttng_condition *condition)
+void print_one_event_expr(const struct lttng_event_expr *event_expr)
+{
+       enum lttng_event_expr_type type;
+
+       type = lttng_event_expr_get_type(event_expr);
+
+       switch (type) {
+       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD: {
+               const char *name;
+
+               name = lttng_event_expr_event_payload_field_get_name(event_expr);
+               _MSG("%s", name);
+
+               break;
+       }
+
+       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD: {
+               const char *name;
+
+               name = lttng_event_expr_channel_context_field_get_name(event_expr);
+               _MSG("$ctx.%s", name);
+
+               break;
+       }
+
+       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD: {
+               const char *provider_name;
+               const char *type_name;
+
+               provider_name =
+                       lttng_event_expr_app_specific_context_field_get_provider_name(
+                               event_expr);
+               type_name =
+                       lttng_event_expr_app_specific_context_field_get_type_name(
+                               event_expr);
+
+               _MSG("$app.%s:%s", provider_name, type_name);
+
+               break;
+       }
+
+       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT: {
+               unsigned int index;
+               const struct lttng_event_expr *parent_expr;
+               enum lttng_event_expr_status status;
+
+               parent_expr = lttng_event_expr_array_field_element_get_parent_expr(
+                       event_expr);
+               assert(parent_expr != NULL);
+
+               print_one_event_expr(parent_expr);
+
+               status = lttng_event_expr_array_field_element_get_index(
+                       event_expr, &index);
+               assert(status == LTTNG_EVENT_EXPR_STATUS_OK);
+
+               _MSG("[%u]", index);
+
+               break;
+       }
+
+       default:
+               abort();
+       }
+}
+
+static
+void print_condition_on_event(const struct lttng_condition *condition)
 {
        const struct lttng_event_rule *event_rule;
        enum lttng_condition_status condition_status;
+       unsigned int cap_desc_count, i;
+       uint64_t error_count;
 
        condition_status =
-               lttng_condition_event_rule_get_rule(condition, &event_rule);
+               lttng_condition_on_event_get_rule(condition, &event_rule);
        assert(condition_status == LTTNG_CONDITION_STATUS_OK);
 
        print_event_rule(event_rule);
+
+       condition_status
+               = lttng_condition_on_event_get_capture_descriptor_count(
+                       condition, &cap_desc_count);
+       assert(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+       error_count = lttng_condition_on_event_get_error_count(condition);
+       MSG("    tracer notifications discarded: %ld", error_count);
+
+       if (cap_desc_count > 0) {
+               MSG("    captures:");
+
+               for (i = 0; i < cap_desc_count; i++) {
+                       const struct lttng_event_expr *cap_desc =
+                               lttng_condition_on_event_get_capture_descriptor_at_index(
+                                       condition, i);
+
+                       _MSG("      - ");
+                       print_one_event_expr(cap_desc);
+                       MSG("");
+               }
+       }
+}
+
+static
+void print_map_key(const struct lttng_map_key *key)
+{
+       unsigned int i, token_count;
+       enum lttng_map_key_status key_status;
+
+       _MSG("       key: `");
+       key_status = lttng_map_key_get_token_count(key, &token_count);
+       assert(key_status == LTTNG_MAP_KEY_STATUS_OK);
+
+       for (i = 0; i < token_count; i++) {
+               const struct lttng_map_key_token *token =
+                               lttng_map_key_get_token_at_index(key, i);
+               assert(token);
+
+               switch (token->type) {
+               case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
+               {
+                       const struct lttng_map_key_token_string *str_token;
+                       str_token = (typeof(str_token)) token;
+                       _MSG("%s", str_token->string);
+                       break;
+               }
+               case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
+               {
+                       const struct lttng_map_key_token_variable *var_token;
+                       var_token = (typeof(var_token)) token;
+
+                       switch (var_token->type) {
+                       case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME:
+                               _MSG("${EVENT_NAME}");
+                               break;
+                       case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME:
+                               _MSG("${PROVIDER_NAME}");
+                               break;
+                       default:
+                               abort();
+                       }
+
+                       break;
+               }
+               default:
+                       abort();
+               }
+       }
+       MSG("`");
+}
+
+static
+void print_one_incr_value_action(const struct lttng_action *action)
+{
+       enum lttng_action_status action_status;
+       const char *session_name, *map_name;
+       const struct lttng_map_key *key;
+
+       action_status = lttng_action_incr_value_get_session_name(
+               action, &session_name);
+       assert(action_status == LTTNG_ACTION_STATUS_OK);
+
+       action_status = lttng_action_incr_value_get_map_name(
+               action, &map_name);
+       assert(action_status == LTTNG_ACTION_STATUS_OK);
+
+       action_status = lttng_action_incr_value_get_key(
+               action, &key);
+       assert(action_status == LTTNG_ACTION_STATUS_OK);
+
+       MSG("increment value:");
+       MSG("       session: `%s`", session_name);
+       MSG("       map: `%s`", map_name);
+       print_map_key(key);
 }
 
 static
@@ -318,6 +508,9 @@ void print_one_action(const struct lttng_action *action)
        assert(action_type != LTTNG_ACTION_TYPE_GROUP);
 
        switch (action_type) {
+       case LTTNG_ACTION_TYPE_INCREMENT_VALUE:
+               print_one_incr_value_action(action);
+               break;
        case LTTNG_ACTION_TYPE_NOTIFY:
                MSG("notify");
                break;
@@ -447,8 +640,8 @@ void print_one_trigger(const struct lttng_trigger *trigger)
        condition_type = lttng_condition_get_type(condition);
        MSG("  condition: %s", lttng_condition_type_str(condition_type));
        switch (condition_type) {
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
-               print_condition_event_rule_hit(condition);
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
+               print_condition_on_event(condition);
                break;
        default:
                MSG("  (condition type not handled in %s)", __func__);
diff --git a/src/bin/lttng/commands/view_map.c b/src/bin/lttng/commands/view_map.c
new file mode 100644 (file)
index 0000000..7d8dac5
--- /dev/null
@@ -0,0 +1,651 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <math.h>
+
+#include <common/dynamic-array.h>
+#include <lttng/domain.h>
+#include <lttng/lttng-error.h>
+#include <lttng/map/map.h>
+#include <lttng/map/map-internal.h>
+#include <lttng/map/map-query.h>
+
+#include "../command.h"
+
+#include "common/argpar/argpar.h"
+
+enum {
+       OPT_HELP,
+       OPT_SESSION,
+       OPT_LIST_OPTIONS,
+       OPT_USERSPACE,
+       OPT_KERNEL,
+       OPT_KEY,
+};
+
+static const
+struct argpar_opt_descr view_map_options[] = {
+       { OPT_HELP, 'h', "help", false },
+       { OPT_SESSION, 's', "session", true },
+       { OPT_LIST_OPTIONS, '\0', "list-options", false },
+       /* Domains */
+       { OPT_USERSPACE, 'u', "userspace", false },
+       { OPT_KERNEL, 'k', "kernel", false },
+       { OPT_KEY, '\0', "key", true },
+       ARGPAR_OPT_DESCR_SENTINEL,
+};
+
+static
+bool assign_domain_type(enum lttng_domain_type *dest,
+               enum lttng_domain_type src)
+{
+       bool ret;
+
+       if (*dest == LTTNG_DOMAIN_NONE || *dest == src) {
+               *dest = src;
+               ret = true;
+       } else {
+               ERR("Multiple domains specified.");
+               ret = false;
+       }
+
+       return ret;
+}
+
+static
+bool assign_string(char **dest, const char *src, const char *opt_name)
+{
+       bool ret;
+
+       if (*dest) {
+               ERR("Duplicate %s given.", opt_name);
+               goto error;
+       }
+
+       *dest = strdup(src);
+       if (!*dest) {
+               ERR("Failed to allocate %s string.", opt_name);
+               goto error;
+       }
+
+       ret = true;
+       goto end;
+
+error:
+       ret = false;
+
+end:
+       return ret;
+}
+
+static
+int compare_key_value_by_key(const void *a, const void *b)
+{
+       const struct lttng_map_key_value_pair *kv_a =
+                       *((const struct lttng_map_key_value_pair **) a);
+       const struct lttng_map_key_value_pair *kv_b =
+                       *((const struct lttng_map_key_value_pair **) b);
+       const char *key_a, *key_b;
+       enum lttng_map_status map_status;
+
+       map_status = lttng_map_key_value_pair_get_key(kv_a, &key_a);
+       assert(map_status == LTTNG_MAP_STATUS_OK);
+
+       map_status = lttng_map_key_value_pair_get_key(kv_b, &key_b);
+       assert(map_status == LTTNG_MAP_STATUS_OK);
+
+       return strcmp(key_a, key_b);
+}
+
+static
+void print_one_map_key_value_pair(const struct lttng_map_key_value_pair *kv_pair,
+               size_t key_len, size_t val_len)
+{
+       const char *key = NULL;
+       int64_t value;
+       enum lttng_map_status status;
+       bool has_overflowed, has_underflowed;
+
+       status = lttng_map_key_value_pair_get_key(kv_pair, &key);
+       if (status != LTTNG_MAP_STATUS_OK) {
+               ERR("Failed to get key-value pair's key.");
+               goto end;
+       }
+
+       status = lttng_map_key_value_pair_get_value(kv_pair, &value);
+       if (status != LTTNG_MAP_STATUS_OK) {
+               ERR("Failed to get value-value pair's value.");
+               goto end;
+       }
+
+       has_overflowed = lttng_map_key_value_pair_get_has_overflowed(kv_pair);
+       has_underflowed = lttng_map_key_value_pair_get_has_underflowed(kv_pair);
+
+       /* Ensure the padding is nice using the `%*s` delimiter. */
+       MSG("| %*s | %*"PRId64" |  %d |  %d |", (int) -key_len, key,
+                       (int) val_len, value, has_underflowed, has_overflowed);
+
+end:
+       return;
+}
+
+static
+void print_line(size_t key_len, size_t val_len)
+{
+       int i;
+
+       _MSG("+");
+       for (i = 0; i < (int) key_len + 2; i++) {
+               _MSG("-");
+       }
+       _MSG("+");
+       for (i = 0; i < (int) val_len + 2; i++) {
+               _MSG("-");
+       }
+       MSG("+----+----+");
+}
+
+static
+size_t number_of_digit(int64_t val)
+{
+       size_t ret = 0;
+
+       if (val == 0) {
+               ret = 1;
+               goto end;
+       }
+
+       if (val < 0) {
+               /* Account for the minus sign. */
+               ret++;
+               val = llabs(val);
+       }
+
+       /*
+        * SOURCE:
+        * https://stackoverflow.com/questions/1068849/how-do-i-determine-the-number-of-digits-of-an-integer-in-c
+        * If the log10() call becomes too expensive, we could use a
+        * recursive approach to count the digits.
+        */
+       ret += floor(log10(val)) + 1;
+
+end:
+       return ret;
+}
+
+static
+void print_map_section_identifier(const struct lttng_map_key_value_pair_list *kv_pair_list)
+{
+       switch (lttng_map_key_value_pair_list_get_type(kv_pair_list)) {
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_KERNEL:
+               _MSG("Kernel global map");
+               break;
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID_AGGREGATED:
+               _MSG("Per-PID dead app aggregated map");
+               break;
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID:
+               _MSG("PID: %"PRIu64, lttng_map_key_value_pair_list_get_identifer(
+                                       kv_pair_list));
+               break;
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID:
+               _MSG("UID: %"PRIu64, lttng_map_key_value_pair_list_get_identifer(
+                                       kv_pair_list));
+               break;
+       default:
+               break;
+       }
+       _MSG(", CPU: ");
+       if (lttng_map_key_value_pair_list_get_summed_all_cpu(kv_pair_list)) {
+               MSG("ALL");
+       } else {
+               MSG("%"PRIu64, lttng_map_key_value_pair_list_get_cpu(kv_pair_list));
+       }
+}
+
+static
+void print_map_table_header(size_t max_key_len, size_t max_val_len)
+{
+       print_line(max_key_len, max_val_len);
+       /* Ensure the padding is nice using the `%*s` delimiter. */
+       MSG("| %*s | %*s | %s | %s |", (int) -max_key_len, "key",
+                       (int) max_val_len, "val", "uf", "of");
+}
+
+static
+enum lttng_error_code print_one_map_section(
+               const struct lttng_map_key_value_pair_list *kv_pair_list,
+               enum lttng_buffer_type buffer_type)
+{
+       enum lttng_error_code ret;
+       enum lttng_map_status map_status;
+       size_t longest_key_len = strlen("key"), longest_val_len = strlen("val");
+       unsigned int i, key_value_pair_count;
+       struct lttng_dynamic_pointer_array sorted_kv_pair_list;
+
+       lttng_dynamic_pointer_array_init(&sorted_kv_pair_list, NULL);
+
+       map_status = lttng_map_key_value_pair_list_get_count(kv_pair_list,
+                       &key_value_pair_count);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Failed to get key-value pair count.");
+               goto error;
+       }
+
+       for (i = 0; i < key_value_pair_count; i++) {
+               const char *cur_key;
+               int64_t cur_val;
+               const struct lttng_map_key_value_pair *pair =
+                               lttng_map_key_value_pair_list_get_at_index(
+                                               kv_pair_list, i);
+
+               /* Add all key value pairs to the sorting array. */
+               lttng_dynamic_pointer_array_add_pointer(&sorted_kv_pair_list,
+                               (void *) pair);
+
+               /* Keep track of the longest key. */
+               lttng_map_key_value_pair_get_key(pair, &cur_key);
+               longest_key_len = max(longest_key_len, strlen(cur_key));
+
+               /* Keep track of the longest value. */
+               lttng_map_key_value_pair_get_value(pair, &cur_val);
+               longest_val_len = max(longest_val_len, number_of_digit(cur_val));
+       }
+
+       qsort(sorted_kv_pair_list.array.buffer.data,
+                       lttng_dynamic_pointer_array_get_count(&sorted_kv_pair_list),
+                       sizeof(struct lttng_map_key_value_pair *),
+                       compare_key_value_by_key);
+
+       print_map_section_identifier(kv_pair_list);
+       if (key_value_pair_count == 0) {
+               MSG("    No value in the map");
+               ret = LTTNG_OK;
+               goto end;
+       } else {
+               print_map_table_header(longest_key_len, longest_val_len);
+
+               for (i = 0; i < key_value_pair_count; i++) {
+                       print_line(longest_key_len, longest_val_len);
+
+                       print_one_map_key_value_pair(
+                               lttng_dynamic_pointer_array_get_pointer(
+                                               &sorted_kv_pair_list, i),
+                               longest_key_len, longest_val_len);
+               }
+
+               print_line(longest_key_len, longest_val_len);
+       }
+
+       ret = LTTNG_OK;
+       goto end;
+
+error:
+       ret = LTTNG_ERR_MAP_VALUES_LIST_FAIL;
+end:
+       lttng_dynamic_pointer_array_reset(&sorted_kv_pair_list);
+
+       return ret;
+}
+
+static
+enum lttng_error_code print_one_map(struct lttng_handle *handle,
+               const struct lttng_map *map, const char *key_filter)
+{
+       enum lttng_error_code ret;
+       enum lttng_map_status map_status;
+       struct lttng_map_content *map_content = NULL;
+       unsigned int i, map_content_section_count;
+       enum lttng_buffer_type buffer_type;
+       struct lttng_map_query *map_query = NULL;
+       enum lttng_map_query_config_buffer query_buffer_config;
+       enum lttng_map_query_config_app_bitness query_bitness_config;
+       enum lttng_map_query_status query_status;
+       const char *map_name = NULL;
+       enum lttng_map_bitness map_bitness;
+
+       map_status = lttng_map_get_name(map, &map_name);
+       assert(map_status == LTTNG_MAP_STATUS_OK);
+
+       map_bitness = lttng_map_get_bitness(map);
+
+       switch (lttng_map_get_buffer_type(map)) {
+       case LTTNG_BUFFER_GLOBAL:
+               query_buffer_config = LTTNG_MAP_QUERY_CONFIG_BUFFER_KERNEL_GLOBAL;
+               query_bitness_config = LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_KERNEL;
+               break;
+       case LTTNG_BUFFER_PER_UID:
+               query_buffer_config = LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_ALL;
+               query_bitness_config = LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_ALL;
+               break;
+       case LTTNG_BUFFER_PER_PID:
+               query_buffer_config = LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_ALL;
+               query_bitness_config = LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_ALL;
+               break;
+       default:
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       map_query = lttng_map_query_create(LTTNG_MAP_QUERY_CONFIG_CPU_ALL,
+                       query_buffer_config, query_bitness_config);
+       if (!map_query) {
+               ret = LTTNG_ERR_NOMEM;
+               ERR("Creating map query");
+               goto end;
+       }
+
+       if (key_filter) {
+               query_status = lttng_map_query_add_key_filter(map_query, key_filter);
+               assert(query_status == LTTNG_MAP_QUERY_STATUS_OK);
+       }
+
+       query_status = lttng_map_query_set_sum_by_cpu(map_query, true);
+       assert(query_status == LTTNG_MAP_QUERY_STATUS_OK);
+
+       /*
+        * We don't want to aggregate all uid (or pid) together for the lttng
+        * view-map command.
+        */
+       if (query_buffer_config == LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_ALL) {
+               //query_status = lttng_map_query_set_sum_by_uid(map_query, false);
+               //assert(query_status == LTTNG_MAP_QUERY_STATUS_OK);
+       } else  if (query_buffer_config == LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_ALL) {
+               query_status = lttng_map_query_set_sum_by_pid(map_query, false);
+               assert(query_status == LTTNG_MAP_QUERY_STATUS_OK);
+       }
+
+       /*
+        * If we have 32bits and 64bits maps, we want to aggregate both maps in
+        * a single table in the lttng view-map command.
+        */
+       if (query_bitness_config == LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_ALL) {
+               //query_status = lttng_map_query_set_sum_by_app_bitness(map_query, true);
+               //assert(query_status == LTTNG_MAP_QUERY_STATUS_OK);
+       }
+
+       /* Fetch the key value pair_list from the sessiond */
+       ret = lttng_list_map_content(handle, map, map_query, &map_content);
+       if (ret != LTTNG_OK) {
+               ERR("Error listing map key value pair_list: %s.",
+                               lttng_strerror(-ret));
+               goto end;
+       }
+
+       map_status = lttng_map_content_get_count(map_content,
+                       &map_content_section_count);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ret = LTTNG_ERR_MAP_VALUES_LIST_FAIL;
+               ERR("Failed to get map content section count.");
+               goto end;
+       }
+
+       if (map_content_section_count == 0) {
+               DBG("Map %s is not found", map_name);
+               goto end;
+       }
+
+       MSG("Session: '%s', map: '%s', map bitness: %d", handle->session_name,
+                       map_name, map_bitness);
+
+       buffer_type = lttng_map_content_get_buffer_type(map_content);
+
+       for (i = 0; i < map_content_section_count; i++) {
+               const struct lttng_map_key_value_pair_list *kv_pair_list =
+                               lttng_map_content_get_at_index(map_content, i);
+
+               assert(kv_pair_list);
+               ret = print_one_map_section(kv_pair_list, buffer_type);
+               if (ret != LTTNG_OK) {
+                       ERR("Error printing map section");
+                       goto end;
+               }
+       }
+
+
+       ret = LTTNG_OK;
+       goto end;
+end:
+       lttng_map_content_destroy(map_content);
+       return ret;
+}
+
+static
+int view_map(struct lttng_handle *handle, const char *desired_map_name,
+               const char *key_filter)
+{
+       enum lttng_error_code ret;
+       struct lttng_map_list *map_list = NULL;
+       enum lttng_map_status map_status;
+       bool desired_map_found = false;
+       unsigned int i, map_count;
+
+       DBG("Listing map(s) (%s)", desired_map_name ? : "<all>");
+       /*
+        * Query the sessiond for a list of all the maps that match the
+        * provided map name and domain (if any).
+        */
+       ret = lttng_list_maps(handle, &map_list);
+       if (ret != LTTNG_OK) {
+               ERR("Error getting map list");
+               goto end;
+       }
+
+       map_status = lttng_map_list_get_count(map_list, &map_count);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Error getting map list element count");
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < map_count; i++) {
+               const struct lttng_map *map = NULL;
+               const char *map_name = NULL;
+               map = lttng_map_list_get_at_index(map_list, i);
+               if (!map) {
+                       ERR("Error getting map from list: index = %u", i);
+                       goto end;
+               }
+
+               map_status = lttng_map_get_name(map, &map_name);
+               if (map_status != LTTNG_MAP_STATUS_OK) {
+                       ERR("Error getting map name");
+                       ret = -1;
+                       goto end;
+               }
+
+
+               if (desired_map_name != NULL) {
+                       if (strncmp(map_name, desired_map_name, NAME_MAX) == 0) {
+                               desired_map_found = true;
+                               ret = print_one_map(handle, map, key_filter);
+                               if (ret != LTTNG_OK) {
+                                       ret = -1;
+                                       goto end;
+                               }
+                       }
+               }
+       }
+
+       if (desired_map_name && !desired_map_found) {
+               DBG("Map %s in domain: %s (session %s)", desired_map_name,
+                       lttng_strerror(-ret), handle->session_name);
+               ret = LTTNG_ERR_MAP_NOT_FOUND;
+               goto end;
+       }
+
+end:
+       lttng_map_list_destroy(map_list);
+       return ret;
+}
+
+int cmd_view_map(int argc, const char **argv)
+{
+       struct argpar_parse_ret argpar_parse_ret = { 0 };
+       enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
+       const char *opt_map_name = NULL;;
+       char *opt_session_name = NULL, *session_name = NULL;
+       char *opt_key_filter = NULL;
+       struct lttng_domain domain;
+       struct lttng_domain *domains = NULL;
+       struct lttng_handle *handle;
+
+       int ret, i;
+
+       memset(&domain, 0, sizeof(domain));
+
+       argpar_parse_ret = argpar_parse(argc - 1, argv + 1,
+               view_map_options, true);
+       if (!argpar_parse_ret.items) {
+               ERR("%s", argpar_parse_ret.error);
+               goto error;
+       }
+
+       for (i = 0; i < argpar_parse_ret.items->n_items; i++) {
+               struct argpar_item *item = argpar_parse_ret.items->items[i];
+
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       struct argpar_item_opt *item_opt =
+                               (struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_HELP:
+                               SHOW_HELP();
+                               ret = CMD_SUCCESS;
+                               goto end;
+                       case OPT_SESSION:
+                               if (!assign_string(&opt_session_name, item_opt->arg,
+                                               "-s/--session")) {
+                                       goto error;
+                               }
+                               break;
+                       case OPT_LIST_OPTIONS:
+                               list_cmd_options_argpar(stdout,
+                                       view_map_options);
+                               ret = CMD_SUCCESS;
+                               goto end;
+                       case OPT_USERSPACE:
+                               if (!assign_domain_type(&domain_type, LTTNG_DOMAIN_UST)) {
+                                       goto error;
+                               }
+                               break;
+
+                       case OPT_KERNEL:
+                               if (!assign_domain_type(&domain_type, LTTNG_DOMAIN_KERNEL)) {
+                                       goto error;
+                               }
+                               break;
+                       case OPT_KEY:
+                               if (!assign_string(&opt_key_filter, item_opt->arg,
+                                               "--key")) {
+                                       goto error;
+                               }
+                               break;
+
+                       default:
+                               abort();
+                       }
+
+               } else {
+                       struct argpar_item_non_opt *item_non_opt =
+                               (struct argpar_item_non_opt *) item;
+
+                       if (opt_map_name) {
+                               ERR("Unexpected argument: %s", item_non_opt->arg);
+                               goto error;
+                       }
+                       opt_map_name = item_non_opt->arg;
+               }
+       }
+
+       if (!opt_map_name) {
+               ERR("Map name must be provided");
+               goto error;
+       }
+
+       if (!opt_session_name) {
+               DBG("No session name provided, print maps of the default session");
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       goto error;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       domain.type = domain_type;
+       handle = lttng_create_handle(session_name, &domain);
+       if (handle == NULL) {
+               ret = CMD_FATAL;
+               goto end;
+       }
+
+       if (domain.type != LTTNG_DOMAIN_NONE) {
+               /* Print maps of the given domain. */
+               ret = view_map(handle, opt_map_name, opt_key_filter);
+               if (ret != LTTNG_OK) {
+                       goto error;
+               }
+       } else {
+               int i, nb_domain;
+               bool found_one_map = false;
+
+               /* We want all domain(s) */
+               nb_domain = lttng_list_domains(session_name, &domains);
+               if (nb_domain < 0) {
+                       ret = CMD_ERROR;
+                       ERR("%s", lttng_strerror(nb_domain));
+                       goto end;
+               }
+
+               for (i = 0; i < nb_domain; i++) {
+                       /* Clean handle before creating a new one */
+                       if (handle) {
+                               lttng_destroy_handle(handle);
+                       }
+
+                       handle = lttng_create_handle(session_name, &domains[i]);
+                       if (handle == NULL) {
+                               ret = CMD_FATAL;
+                               goto end;
+                       }
+
+                       ret = view_map(handle, opt_map_name, opt_key_filter);
+
+                       if (ret == LTTNG_OK) {
+                               found_one_map = true;
+                       } else if (ret == LTTNG_ERR_MAP_NOT_FOUND) {
+                               DBG("Map not found in the current domain");
+                               continue;
+                       } else {
+                               goto error;
+                       }
+               }
+
+               if (!found_one_map) {
+                       ERR("Map %s not found on any of the domains", opt_map_name);
+                       goto error;
+
+               }
+       }
+
+       ret = CMD_SUCCESS;
+       goto end;
+error:
+       ret = CMD_ERROR;
+
+end:
+       if (!opt_session_name && session_name) {
+               free(session_name);
+       }
+
+       if (opt_key_filter) {
+               free(opt_key_filter);
+       }
+
+       argpar_parse_ret_fini(&argpar_parse_ret);
+       return ret;
+}
index 437a9cc4c2e00367ec5d10f2d0061ae18f4d5c49..61ed247738ac2adfe748fe88087f54dfe54fc86b 100644 (file)
@@ -73,6 +73,9 @@ static struct cmd_struct commands[] =  {
        { "disable-event", cmd_disable_events},
        { "enable-channel", cmd_enable_channels},
        { "enable-event", cmd_enable_events},
+       { "add-map", cmd_add_map},
+       { "enable-map", cmd_enable_map},
+       { "disable-map", cmd_disable_map},
        { "help", NULL},
        { "list", cmd_list},
        { "list-triggers", cmd_list_triggers},
@@ -93,6 +96,7 @@ static struct cmd_struct commands[] =  {
        { "untrack", cmd_untrack},
        { "version", cmd_version},
        { "view", cmd_view},
+       { "view-map", cmd_view_map},
        { NULL, NULL}   /* Array closure */
 };
 
@@ -286,6 +290,10 @@ static void show_basic_help(void)
        puts("  disable-channel   " CONFIG_CMD_DESCR_DISABLE_CHANNEL);
        puts("  enable-channel    " CONFIG_CMD_DESCR_ENABLE_CHANNEL);
        puts("");
+       puts("Maps:");
+       puts("  add-map           " CONFIG_CMD_DESCR_ADD_MAP);
+       puts("  remove-map        " CONFIG_CMD_DESCR_ADD_MAP);
+       puts("");
        puts("Event rules:");
        puts("  disable-event     " CONFIG_CMD_DESCR_DISABLE_EVENT);
        puts("  enable-event      " CONFIG_CMD_DESCR_ENABLE_EVENT);
index 4b549aa08e2baf06212a9f853a73ab1c8f78af92..339a554922df227c246cda9dc314d015deb0bc14 100644 (file)
@@ -36,6 +36,7 @@ EXTRA_DIST = mi-lttng-4.0.xsd
 libcommon_la_SOURCES = \
        actions/action.c \
        actions/group.c \
+       actions/incr-value.c \
        actions/notify.c \
        actions/rotate-session.c \
        actions/snapshot-session.c \
@@ -45,7 +46,7 @@ libcommon_la_SOURCES = \
        common.h \
        conditions/buffer-usage.c \
        conditions/condition.c \
-       conditions/event-rule.c \
+       conditions/on-event.c \
        conditions/session-consumed-size.c \
        conditions/session-rotation.c \
        context.c context.h \
@@ -62,16 +63,23 @@ libcommon_la_SOURCES = \
        event-expr-to-bytecode.c event-expr-to-bytecode.h \
        event-field-value.c \
        event-rule/event-rule.c \
-       event-rule/kprobe.c \
+       event-rule/kernel-function.c \
+       event-rule/kernel-probe.c \
        event-rule/syscall.c \
-       event-rule/uprobe.c \
+       event-rule/userspace-probe.c \
        event-rule/tracepoint.c \
        filter.c filter.h \
        fd-handle.c fd-handle.h \
        fs-handle.c fs-handle.h fs-handle-internal.h \
        futex.c futex.h \
+       kernel-function.c \
        kernel-probe.c \
+       index-allocator.c index-allocator.h \
        location.c \
+       log-level-rule.c \
+       map.c \
+       map-query.c \
+       map-key/map-key.c \
        mi-lttng.c mi-lttng.h \
        notification.c \
        optional.h \
@@ -80,6 +88,7 @@ libcommon_la_SOURCES = \
        pipe.c pipe.h \
        readwrite.c readwrite.h \
        runas.c runas.h \
+       shm.c shm.h \
        session-descriptor.c \
        snapshot.c snapshot.h \
        spawn-viewer.c spawn-viewer.h \
index 95a0c0f4d20a19eb743b60d392c65934a82d656f..2bf5e4877c501f0df38e1de1e1072278d4a7b660 100644 (file)
@@ -9,6 +9,7 @@
 #include <common/error.h>
 #include <lttng/action/action-internal.h>
 #include <lttng/action/group-internal.h>
+#include <lttng/action/incr-value-internal.h>
 #include <lttng/action/notify-internal.h>
 #include <lttng/action/rotate-session-internal.h>
 #include <lttng/action/snapshot-session-internal.h>
@@ -33,6 +34,8 @@ const char *lttng_action_type_string(enum lttng_action_type action_type)
                return "START_SESSION";
        case LTTNG_ACTION_TYPE_STOP_SESSION:
                return "STOP_SESSION";
+       case LTTNG_ACTION_TYPE_INCREMENT_VALUE:
+               return "INCREMENT_VALUE";
        default:
                return "???";
        }
@@ -182,6 +185,10 @@ ssize_t lttng_action_create_from_payload(struct lttng_payload_view *view,
                create_from_payload_cb =
                                lttng_action_stop_session_create_from_payload;
                break;
+       case LTTNG_ACTION_TYPE_INCREMENT_VALUE:
+               create_from_payload_cb =
+                               lttng_action_incr_value_create_from_payload;
+               break;
        case LTTNG_ACTION_TYPE_GROUP:
                create_from_payload_cb = lttng_action_group_create_from_payload;
                break;
index 4ac239c9d62c14f43c7b2ddf0623c5e901aeaf5d..f7bbfd5a9155aac87fd93fb6b211466b7ea0435b 100644 (file)
@@ -353,3 +353,11 @@ const struct lttng_action *lttng_action_group_get_at_index(
 end:
        return action;
 }
+
+struct lttng_action *lttng_action_group_get_mutable_at_index(
+               struct lttng_action *group,
+               unsigned int index)
+{
+       return (struct lttng_action *) lttng_action_group_get_at_index(
+                       (const struct lttng_action *) group, index);
+}
diff --git a/src/common/actions/incr-value.c b/src/common/actions/incr-value.c
new file mode 100644 (file)
index 0000000..0c4ddc2
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/optional.h>
+
+#include <lttng/action/action-internal.h>
+#include <lttng/action/incr-value-internal.h>
+#include <lttng/action/incr-value.h>
+#include <lttng/map-key.h>
+#include <lttng/map-key-internal.h>
+
+#define IS_INCR_VALUE_ACTION(action) \
+       (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_INCREMENT_VALUE)
+
+struct lttng_action_incr_value {
+       struct lttng_action parent;
+
+       /* Owned by this. */
+       struct lttng_map_key *key;
+       /* Owned by this. */
+       char *session_name;
+       /* Owned by this. */
+       char *map_name;
+
+       LTTNG_OPTIONAL(uint64_t) action_tracer_token;
+};
+
+struct lttng_action_incr_value_comm {
+       /* Includes the trailing \0. */
+       uint32_t session_name_len;
+       /* Includes the trailing \0. */
+       uint32_t map_name_len;
+
+       /*
+        * Variable data:
+        *
+        *  - struct lttng_map_key object with variable data
+        *  - session name (null terminated)
+        *  - map name (null terminated)
+        */
+       char data[];
+} LTTNG_PACKED;
+
+static struct lttng_action_incr_value *action_incr_value_from_action(
+               struct lttng_action *action)
+{
+       assert(action);
+
+       return container_of(action, struct lttng_action_incr_value, parent);
+}
+
+static const struct lttng_action_incr_value *
+action_incr_value_from_action_const(const struct lttng_action *action)
+{
+       assert(action);
+
+       return container_of(action, struct lttng_action_incr_value, parent);
+}
+
+static bool lttng_action_incr_value_validate(struct lttng_action *action)
+{
+       bool valid;
+       struct lttng_action_incr_value *action_incr_value;
+
+       if (!action) {
+               valid = false;
+               goto end;
+       }
+
+       action_incr_value = action_incr_value_from_action(action);
+
+       /* Non null key is mandatory. */
+       if (!action_incr_value->key) {
+               valid = false;
+               goto end;
+       }
+
+       /* A non-empty session name is mandatory. */
+       if (!action_incr_value->session_name ||
+                       strlen(action_incr_value->session_name) == 0) {
+               valid = false;
+               goto end;
+       }
+
+       /* A non-empty map name is mandatory. */
+       if (!action_incr_value->map_name ||
+                       strlen(action_incr_value->map_name) == 0) {
+               valid = false;
+               goto end;
+       }
+
+       valid = true;
+end:
+       return valid;
+}
+
+static bool lttng_action_incr_value_is_equal(
+               const struct lttng_action *_a, const struct lttng_action *_b)
+{
+       bool is_equal = false;
+       const struct lttng_action_incr_value *a, *b;
+
+       a = action_incr_value_from_action_const(_a);
+       b = action_incr_value_from_action_const(_b);
+
+       /* Action is not valid if this is not true. */
+       assert(a->key);
+       assert(b->key);
+       assert(a->session_name);
+       assert(b->session_name);
+       assert(a->map_name);
+       assert(b->map_name);
+
+       if (strcmp(a->session_name, b->session_name)) {
+               goto end;
+       }
+
+       if (strcmp(a->map_name, b->map_name)) {
+               goto end;
+       }
+
+       is_equal = lttng_map_key_is_equal(a->key, b->key);
+
+end:
+       return is_equal;
+}
+
+static int lttng_action_incr_value_serialize(
+               struct lttng_action *action, struct lttng_payload *payload)
+{
+       struct lttng_action_incr_value *action_incr_value;
+       struct lttng_action_incr_value_comm comm;
+       size_t session_name_len, map_name_len;
+       int ret;
+
+       assert(action);
+       assert(payload);
+
+       action_incr_value = action_incr_value_from_action(action);
+
+       DBG("Serializing increment value action");
+
+       session_name_len = strlen(action_incr_value->session_name) + 1;
+       comm.session_name_len = session_name_len;
+
+       map_name_len = strlen(action_incr_value->map_name) + 1;
+       comm.map_name_len = map_name_len;
+
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, &comm, sizeof(comm));
+       if (ret) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = lttng_map_key_serialize(action_incr_value->key, payload);
+       if (ret) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                       action_incr_value->session_name, session_name_len);
+       if (ret) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                       action_incr_value->map_name, map_name_len);
+       if (ret) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = 0;
+end:
+       return ret;
+}
+
+static void lttng_action_incr_value_destroy(struct lttng_action *action)
+{
+       struct lttng_action_incr_value *action_incr_value;
+
+       if (!action) {
+               goto end;
+       }
+
+       action_incr_value = action_incr_value_from_action(action);
+
+       lttng_map_key_destroy(action_incr_value->key);
+
+       free(action_incr_value->session_name);
+       free(action_incr_value->map_name);
+       free(action_incr_value);
+
+end:
+       return;
+}
+
+ssize_t lttng_action_incr_value_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_action **p_action)
+{
+       ssize_t consumed_len, consumed_key_len, ret;
+       struct lttng_map_key *key = NULL;
+       const struct lttng_action_incr_value_comm *comm;
+       const char *session_name, *map_name;
+       struct lttng_action *action;
+       enum lttng_action_status status;
+
+       action = lttng_action_incr_value_create();
+       if (!action) {
+               consumed_len = -1;
+               goto error;
+       }
+
+       comm = (typeof(comm)) view->buffer.data;
+       consumed_len = sizeof(struct lttng_action_incr_value_comm);
+
+       {
+               struct lttng_payload_view key_view =
+                               lttng_payload_view_from_view(view, consumed_len,
+                                               view->buffer.size - consumed_len);
+
+               if (!lttng_payload_view_is_valid(&key_view)) {
+                       consumed_len = -1;
+                       goto end;
+               }
+               ret = lttng_map_key_create_from_payload(&key_view, &key);
+               if (ret <= 0) {
+                       consumed_len = -1;
+                       goto error;
+               }
+               consumed_key_len = ret;
+       }
+
+       consumed_len += consumed_key_len;
+       session_name = (const char *) &comm->data + consumed_key_len;
+
+       if (!lttng_buffer_view_contains_string(
+                       &view->buffer, session_name, comm->session_name_len)) {
+               consumed_len = -1;
+               goto error;
+       }
+
+       consumed_len += comm->session_name_len;
+
+       map_name = (const char *) &comm->data + consumed_key_len + comm->session_name_len;
+
+       if (!lttng_buffer_view_contains_string(
+                       &view->buffer, map_name, comm->map_name_len)) {
+               consumed_len = -1;
+               goto error;
+       }
+
+       consumed_len += comm->map_name_len;
+
+       status = lttng_action_incr_value_set_key(action, key);
+       /* Ownership is passed to the action. */
+       lttng_map_key_put(key);
+
+       if (status != LTTNG_ACTION_STATUS_OK) {
+               consumed_len = -1;
+               goto error;
+       }
+
+       status = lttng_action_incr_value_set_session_name(
+                       action, session_name);
+       if (status != LTTNG_ACTION_STATUS_OK) {
+               consumed_len = -1;
+               goto error;
+       }
+
+       status = lttng_action_incr_value_set_map_name(
+                       action, map_name);
+       if (status != LTTNG_ACTION_STATUS_OK) {
+               consumed_len = -1;
+               goto error;
+       }
+
+       *p_action = action;
+       action = NULL;
+       goto end;
+
+error:
+       lttng_action_incr_value_destroy(action);
+       consumed_len = -1;
+
+end:
+       return consumed_len;
+}
+
+struct lttng_action *lttng_action_incr_value_create(void)
+{
+       struct lttng_action *action;
+
+       action = zmalloc(sizeof(struct lttng_action_incr_value));
+       if (!action) {
+               goto end;
+       }
+
+       lttng_action_init(action, LTTNG_ACTION_TYPE_INCREMENT_VALUE,
+                       lttng_action_incr_value_validate,
+                       lttng_action_incr_value_serialize,
+                       lttng_action_incr_value_is_equal,
+                       lttng_action_incr_value_destroy);
+
+end:
+       return action;
+}
+
+enum lttng_action_status lttng_action_incr_value_set_session_name(
+               struct lttng_action *action, const char *session_name)
+{
+       struct lttng_action_incr_value *action_incr_value;
+       enum lttng_action_status status;
+
+       if (!action || !IS_INCR_VALUE_ACTION(action) || !session_name ||
+                       strlen(session_name) == 0) {
+               status = LTTNG_ACTION_STATUS_INVALID;
+               goto end;
+       }
+
+       action_incr_value = action_incr_value_from_action(action);
+
+       free(action_incr_value->session_name);
+
+       action_incr_value->session_name = strdup(session_name);
+       if (!action_incr_value->session_name) {
+               status = LTTNG_ACTION_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_ACTION_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_action_status lttng_action_incr_value_get_session_name(
+               const struct lttng_action *action, const char **session_name)
+{
+       const struct lttng_action_incr_value *action_incr_value;
+       enum lttng_action_status status;
+
+       if (!action || !IS_INCR_VALUE_ACTION(action) || !session_name) {
+               status = LTTNG_ACTION_STATUS_INVALID;
+               goto end;
+       }
+
+       action_incr_value = action_incr_value_from_action_const(action);
+
+       *session_name = action_incr_value->session_name;
+
+       status = LTTNG_ACTION_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_action_status lttng_action_incr_value_set_map_name(
+               struct lttng_action *action, const char *map_name)
+{
+       struct lttng_action_incr_value *action_incr_value;
+       enum lttng_action_status status;
+
+       if (!action || !IS_INCR_VALUE_ACTION(action) || !map_name ||
+                       strlen(map_name) == 0) {
+               status = LTTNG_ACTION_STATUS_INVALID;
+               goto end;
+       }
+
+       action_incr_value = action_incr_value_from_action(action);
+
+       free(action_incr_value->map_name);
+
+       action_incr_value->map_name = strdup(map_name);
+       if (!action_incr_value->map_name) {
+               status = LTTNG_ACTION_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_ACTION_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_action_status lttng_action_incr_value_get_map_name(
+               const struct lttng_action *action, const char **map_name)
+{
+       const struct lttng_action_incr_value *action_incr_value;
+       enum lttng_action_status status;
+
+       if (!action || !IS_INCR_VALUE_ACTION(action) || !map_name) {
+               status = LTTNG_ACTION_STATUS_INVALID;
+               goto end;
+       }
+
+       action_incr_value = action_incr_value_from_action_const(action);
+
+       *map_name = action_incr_value->map_name;
+
+       status = LTTNG_ACTION_STATUS_OK;
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+enum lttng_action_status lttng_action_incr_value_borrow_key_mutable(
+               const struct lttng_action *action, struct lttng_map_key **key)
+{
+       const struct lttng_action_incr_value *action_incr_value;
+       enum lttng_action_status status;
+
+       if (!action || !IS_INCR_VALUE_ACTION(action) || !key) {
+               status = LTTNG_ACTION_STATUS_INVALID;
+               goto end;
+       }
+
+       action_incr_value = action_incr_value_from_action_const(action);
+
+       *key = action_incr_value->key;
+
+       status = LTTNG_ACTION_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_action_status lttng_action_incr_value_get_key(
+               const struct lttng_action *action,
+               const struct lttng_map_key **key)
+{
+       struct lttng_map_key *mutable_key = NULL;
+       enum lttng_action_status status =
+                       lttng_action_incr_value_borrow_key_mutable(
+                                       action, &mutable_key);
+
+       *key = mutable_key;
+       return status;
+}
+
+enum lttng_action_status
+lttng_action_incr_value_set_key(
+               struct lttng_action *action,
+               struct lttng_map_key *key)
+{
+       struct lttng_action_incr_value *action_incr_value;
+       enum lttng_action_status status;
+
+       if (!action || !IS_INCR_VALUE_ACTION(action) || !key) {
+               status = LTTNG_ACTION_STATUS_INVALID;
+               goto end;
+       }
+
+       action_incr_value = action_incr_value_from_action(action);
+
+       /* Take a reference to the key. */
+       lttng_map_key_get(key);
+       action_incr_value->key = key;
+
+       status = LTTNG_ACTION_STATUS_OK;
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+enum lttng_action_status lttng_action_incr_value_set_tracer_token(
+               struct lttng_action *action, uint64_t token)
+{
+       struct lttng_action_incr_value *action_incr_value;
+       enum lttng_action_status status;
+
+       if (!action || !IS_INCR_VALUE_ACTION(action)) {
+               status = LTTNG_ACTION_STATUS_INVALID;
+               goto end;
+       }
+
+       action_incr_value = action_incr_value_from_action(action);
+
+       LTTNG_OPTIONAL_SET(&action_incr_value->action_tracer_token, token);
+
+       status = LTTNG_ACTION_STATUS_OK;
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+uint64_t lttng_action_incr_value_get_tracer_token(
+               const struct lttng_action *action)
+{
+       const struct lttng_action_incr_value *action_incr_value;
+
+       assert(action);
+       assert(IS_INCR_VALUE_ACTION(action));
+
+       action_incr_value = action_incr_value_from_action_const(action);
+
+       return LTTNG_OPTIONAL_GET(action_incr_value->action_tracer_token);
+}
+
index e0b85e429d48c8a149364b7bfb2acf271daad751..4948dbd3ffe5385aede0ff4d3b0b42842692fce2 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <lttng/condition/condition-internal.h>
 #include <lttng/condition/buffer-usage-internal.h>
-#include <lttng/condition/event-rule-internal.h>
+#include <lttng/condition/on-event-internal.h>
 #include <lttng/condition/session-consumed-size-internal.h>
 #include <lttng/condition/session-rotation-internal.h>
 #include <common/macros.h>
@@ -170,8 +170,8 @@ ssize_t lttng_condition_create_from_payload(
        case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
                create_from_payload = lttng_condition_session_rotation_completed_create_from_payload;
                break;
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
-               create_from_payload = lttng_condition_event_rule_create_from_payload;
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
+               create_from_payload = lttng_condition_on_event_create_from_payload;
                break;
        default:
                ERR("Attempted to create condition of unknown type (%i)",
@@ -230,7 +230,7 @@ const char *lttng_condition_type_str(enum lttng_condition_type type)
        case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
                return "session rotation completed";
 
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
                return "event rule hit";
 
        default:
diff --git a/src/common/conditions/event-rule.c b/src/common/conditions/event-rule.c
deleted file mode 100644 (file)
index dcc31ef..0000000
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*
- * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <assert.h>
-#include <common/error.h>
-#include <common/event-expr-to-bytecode.h>
-#include <common/macros.h>
-#include <inttypes.h>
-#include <lttng/condition/condition-internal.h>
-#include <lttng/event-rule/event-rule-internal.h>
-#include <lttng/condition/event-rule-internal.h>
-#include <lttng/condition/event-rule.h>
-#include <lttng/event-expr-internal.h>
-#include <lttng/event-expr.h>
-#include <lttng/lttng-error.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <vendor/msgpack/msgpack.h>
-
-#define IS_EVENT_RULE_CONDITION(condition)      \
-       (lttng_condition_get_type(condition) == \
-                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT)
-
-static bool is_event_rule_evaluation(const struct lttng_evaluation *evaluation)
-{
-       enum lttng_condition_type type = lttng_evaluation_get_type(evaluation);
-
-       return type == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT;
-}
-
-static bool lttng_condition_event_rule_validate(
-               const struct lttng_condition *condition);
-static int lttng_condition_event_rule_serialize(
-               const struct lttng_condition *condition,
-               struct lttng_payload *payload);
-static bool lttng_condition_event_rule_is_equal(
-               const struct lttng_condition *_a,
-               const struct lttng_condition *_b);
-static void lttng_condition_event_rule_destroy(
-               struct lttng_condition *condition);
-
-static bool lttng_condition_event_rule_validate(
-               const struct lttng_condition *condition)
-{
-       bool valid = false;
-       struct lttng_condition_event_rule *event_rule;
-
-       if (!condition) {
-               goto end;
-       }
-
-       event_rule = container_of(
-                       condition, struct lttng_condition_event_rule, parent);
-       if (!event_rule->rule) {
-               ERR("Invalid event rule condition: a rule must be set.");
-               goto end;
-       }
-
-       valid = lttng_event_rule_validate(event_rule->rule);
-end:
-       return valid;
-}
-
-/*
- * Serializes the C string `str` into `buf`.
- *
- * Encoding is the length of `str` plus one (for the null character),
- * and then the string, including its null terminator.
- */
-static
-int serialize_cstr(const char *str, struct lttng_dynamic_buffer *buf)
-{
-       int ret;
-       const uint32_t len = strlen(str) + 1;
-
-       /* Serialize the length, including the null terminator. */
-       DBG("Serializing C string's length (including null terminator): "
-                       "%" PRIu32, len);
-       ret = lttng_dynamic_buffer_append(buf, &len, sizeof(len));
-       if (ret) {
-               goto end;
-       }
-
-       /* Serialize the string. */
-       DBG("Serializing C string: '%s'", str);
-       ret = lttng_dynamic_buffer_append(buf, str, len);
-       if (ret) {
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Serializes the event expression `expr` into `buf`.
- */
-static
-int serialize_event_expr(const struct lttng_event_expr *expr,
-               struct lttng_payload *payload)
-{
-       const uint8_t type = expr->type;
-       int ret;
-
-       /* Serialize the expression's type. */
-       DBG("Serializing event expression's type: %d", expr->type);
-       ret = lttng_dynamic_buffer_append(&payload->buffer, &type, sizeof(type));
-       if (ret) {
-               goto end;
-       }
-
-       /* Serialize the expression */
-       switch (expr->type) {
-       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
-       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
-       {
-               const struct lttng_event_expr_field *field_expr =
-                               container_of(expr,
-                                       const struct lttng_event_expr_field,
-                                       parent);
-
-               /* Serialize the field name. */
-               DBG("Serializing field event expression's field name: '%s'",
-                               field_expr->name);
-               ret = serialize_cstr(field_expr->name, &payload->buffer);
-               if (ret) {
-                       goto end;
-               }
-
-               break;
-       }
-       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
-       {
-               const struct lttng_event_expr_app_specific_context_field *field_expr =
-                               container_of(expr,
-                                       const struct lttng_event_expr_app_specific_context_field,
-                                       parent);
-
-               /* Serialize the provider name. */
-               DBG("Serializing app-specific context field event expression's "
-                               "provider name: '%s'",
-                               field_expr->provider_name);
-               ret = serialize_cstr(field_expr->provider_name, &payload->buffer);
-               if (ret) {
-                       goto end;
-               }
-
-               /* Serialize the type name. */
-               DBG("Serializing app-specific context field event expression's "
-                               "type name: '%s'",
-                               field_expr->provider_name);
-               ret = serialize_cstr(field_expr->type_name, &payload->buffer);
-               if (ret) {
-                       goto end;
-               }
-
-               break;
-       }
-       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
-       {
-               const struct lttng_event_expr_array_field_element *elem_expr =
-                               container_of(expr,
-                                       const struct lttng_event_expr_array_field_element,
-                                       parent);
-               const uint32_t index = elem_expr->index;
-
-               /* Serialize the index. */
-               DBG("Serializing array field element event expression's "
-                               "index: %u", elem_expr->index);
-               ret = lttng_dynamic_buffer_append(&payload->buffer, &index, sizeof(index));
-               if (ret) {
-                       goto end;
-               }
-
-               /* Serialize the parent array field expression. */
-               DBG("Serializing array field element event expression's "
-                               "parent array field event expression.");
-               ret = serialize_event_expr(elem_expr->array_field_expr, payload);
-               if (ret) {
-                       goto end;
-               }
-
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-static
-struct lttng_capture_descriptor *
-lttng_condition_event_rule_get_internal_capture_descriptor_at_index(
-               const struct lttng_condition *condition, unsigned int index)
-{
-       const struct lttng_condition_event_rule *event_rule_cond =
-                       container_of(condition,
-                               const struct lttng_condition_event_rule,
-                               parent);
-       struct lttng_capture_descriptor *desc = NULL;
-       unsigned int count;
-       enum lttng_condition_status status;
-
-       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
-               goto end;
-       }
-
-       status = lttng_condition_event_rule_get_capture_descriptor_count(
-                       condition, &count);
-       if (status != LTTNG_CONDITION_STATUS_OK) {
-               goto end;
-       }
-
-       if (index >= count) {
-               goto end;
-       }
-
-       desc = lttng_dynamic_pointer_array_get_pointer(
-                       &event_rule_cond->capture_descriptors, index);
-end:
-       return desc;
-}
-
-static int lttng_condition_event_rule_serialize(
-               const struct lttng_condition *condition,
-               struct lttng_payload *payload)
-{
-       int ret;
-       struct lttng_condition_event_rule *event_rule;
-       enum lttng_condition_status status;
-       /* Used for iteration and communication (size matters). */
-       uint32_t i, capture_descr_count;
-
-       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
-               ret = -1;
-               goto end;
-       }
-
-       DBG("Serializing event rule condition");
-       event_rule = container_of(
-                       condition, struct lttng_condition_event_rule, parent);
-
-       DBG("Serializing event rule condition's event rule");
-       ret = lttng_event_rule_serialize(event_rule->rule, payload);
-       if (ret) {
-               goto end;
-       }
-
-       status = lttng_condition_event_rule_get_capture_descriptor_count(
-                       condition, &capture_descr_count);
-       if (status != LTTNG_CONDITION_STATUS_OK) {
-               ret = -1;
-               goto end;
-       };
-
-       DBG("Serializing event rule condition's capture descriptor count: %" PRIu32,
-                       capture_descr_count);
-       ret = lttng_dynamic_buffer_append(&payload->buffer, &capture_descr_count,
-                       sizeof(capture_descr_count));
-       if (ret) {
-               goto end;
-       }
-
-       for (i = 0; i < capture_descr_count; i++) {
-               const struct lttng_capture_descriptor *desc =
-                               lttng_condition_event_rule_get_internal_capture_descriptor_at_index(
-                                               condition, i);
-
-               DBG("Serializing event rule condition's capture descriptor %" PRIu32,
-                               i);
-               ret = serialize_event_expr(desc->event_expression, payload);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-bool capture_descriptors_are_equal(
-               const struct lttng_condition *condition_a,
-               const struct lttng_condition *condition_b)
-{
-       bool is_equal = true;
-       unsigned int capture_descr_count_a;
-       unsigned int capture_descr_count_b;
-       size_t i;
-       enum lttng_condition_status status;
-
-       status = lttng_condition_event_rule_get_capture_descriptor_count(
-                       condition_a, &capture_descr_count_a);
-       if (status != LTTNG_CONDITION_STATUS_OK) {
-               goto not_equal;
-       }
-
-       status = lttng_condition_event_rule_get_capture_descriptor_count(
-                       condition_b, &capture_descr_count_b);
-       if (status != LTTNG_CONDITION_STATUS_OK) {
-               goto not_equal;
-       }
-
-       if (capture_descr_count_a != capture_descr_count_b) {
-               goto not_equal;
-       }
-
-       for (i = 0; i < capture_descr_count_a; i++) {
-               const struct lttng_event_expr *expr_a =
-                               lttng_condition_event_rule_get_capture_descriptor_at_index(
-                                       condition_a,
-                                       i);
-               const struct lttng_event_expr *expr_b =
-                               lttng_condition_event_rule_get_capture_descriptor_at_index(
-                                       condition_b,
-                                       i);
-
-               if (!lttng_event_expr_is_equal(expr_a, expr_b)) {
-                       goto not_equal;
-               }
-       }
-
-       goto end;
-
-not_equal:
-       is_equal = false;
-
-end:
-       return is_equal;
-}
-
-static bool lttng_condition_event_rule_is_equal(
-               const struct lttng_condition *_a,
-               const struct lttng_condition *_b)
-{
-       bool is_equal = false;
-       struct lttng_condition_event_rule *a, *b;
-
-       a = container_of(_a, struct lttng_condition_event_rule, parent);
-       b = container_of(_b, struct lttng_condition_event_rule, parent);
-
-       /* Both event rules must be set or both must be unset. */
-       if ((a->rule && !b->rule) || (!a->rule && b->rule)) {
-               WARN("Comparing event_rule conditions with uninitialized rule");
-               goto end;
-       }
-
-       is_equal = lttng_event_rule_is_equal(a->rule, b->rule);
-       if (!is_equal) {
-               goto end;
-       }
-
-       is_equal = capture_descriptors_are_equal(_a, _b);
-
-end:
-       return is_equal;
-}
-
-static void lttng_condition_event_rule_destroy(
-               struct lttng_condition *condition)
-{
-       struct lttng_condition_event_rule *event_rule;
-
-       event_rule = container_of(
-                       condition, struct lttng_condition_event_rule, parent);
-
-       lttng_event_rule_put(event_rule->rule);
-       lttng_dynamic_pointer_array_reset(&event_rule->capture_descriptors);
-       free(event_rule);
-}
-
-static
-void destroy_capture_descriptor(void *ptr)
-{
-       struct lttng_capture_descriptor *desc =
-                       (struct lttng_capture_descriptor *) ptr;
-
-       lttng_event_expr_destroy(desc->event_expression);
-       free(desc->bytecode);
-       free(desc);
-}
-
-struct lttng_condition *lttng_condition_event_rule_create(
-               struct lttng_event_rule *rule)
-{
-       struct lttng_condition *parent = NULL;
-       struct lttng_condition_event_rule *condition = NULL;
-
-       if (!rule) {
-               goto end;
-       }
-
-       condition = zmalloc(sizeof(struct lttng_condition_event_rule));
-       if (!condition) {
-               return NULL;
-       }
-
-       lttng_condition_init(&condition->parent,
-                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
-       condition->parent.validate = lttng_condition_event_rule_validate,
-       condition->parent.serialize = lttng_condition_event_rule_serialize,
-       condition->parent.equal = lttng_condition_event_rule_is_equal,
-       condition->parent.destroy = lttng_condition_event_rule_destroy,
-
-       lttng_event_rule_get(rule);
-       condition->rule = rule;
-       rule = NULL;
-
-       lttng_dynamic_pointer_array_init(&condition->capture_descriptors,
-                       destroy_capture_descriptor);
-
-       parent = &condition->parent;
-end:
-       return parent;
-}
-
-static
-uint64_t uint_from_buffer(const struct lttng_buffer_view *view, size_t size,
-               size_t *offset)
-{
-       uint64_t ret;
-       const struct lttng_buffer_view uint_view =
-                       lttng_buffer_view_from_view(view, *offset, size);
-
-       if (!lttng_buffer_view_is_valid(&uint_view)) {
-               ret = UINT64_C(-1);
-               goto end;
-       }
-
-       switch (size) {
-       case 1:
-               ret = (uint64_t) *uint_view.data;
-               break;
-       case sizeof(uint32_t):
-       {
-               uint32_t u32;
-
-               memcpy(&u32, uint_view.data, sizeof(u32));
-               ret = (uint64_t) u32;
-               break;
-       }
-       case sizeof(ret):
-               memcpy(&ret, uint_view.data, sizeof(ret));
-               break;
-       default:
-               abort();
-       }
-
-       *offset += size;
-
-end:
-       return ret;
-}
-
-static
-const char *str_from_buffer(const struct lttng_buffer_view *view,
-               size_t *offset)
-{
-       uint64_t len;
-       const char *ret;
-
-       len = uint_from_buffer(view, sizeof(uint32_t), offset);
-       if (len == UINT64_C(-1)) {
-               goto error;
-       }
-
-       ret = &view->data[*offset];
-
-       if (!lttng_buffer_view_contains_string(view, ret, len)) {
-               goto error;
-       }
-
-       *offset += len;
-       goto end;
-
-error:
-       ret = NULL;
-
-end:
-       return ret;
-}
-
-static
-struct lttng_event_expr *event_expr_from_payload(
-               struct lttng_payload_view *view, size_t *offset)
-{
-       struct lttng_event_expr *expr = NULL;
-       const char *str;
-       uint64_t type;
-
-       type = uint_from_buffer(&view->buffer, sizeof(uint8_t), offset);
-       if (type == UINT64_C(-1)) {
-               goto error;
-       }
-
-       switch (type) {
-       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
-               str = str_from_buffer(&view->buffer, offset);
-               if (!str) {
-                       goto error;
-               }
-
-               expr = lttng_event_expr_event_payload_field_create(str);
-               break;
-       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
-               str = str_from_buffer(&view->buffer, offset);
-               if (!str) {
-                       goto error;
-               }
-
-               expr = lttng_event_expr_channel_context_field_create(str);
-               break;
-       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
-       {
-               const char *provider_name;
-               const char *type_name;
-
-               provider_name = str_from_buffer(&view->buffer, offset);
-               if (!provider_name) {
-                       goto error;
-               }
-
-               type_name = str_from_buffer(&view->buffer, offset);
-               if (!type_name) {
-                       goto error;
-               }
-
-               expr = lttng_event_expr_app_specific_context_field_create(
-                               provider_name, type_name);
-               break;
-       }
-       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
-       {
-               struct lttng_event_expr *array_field_expr;
-               const uint64_t index = uint_from_buffer(
-                               &view->buffer, sizeof(uint32_t), offset);
-
-               if (index == UINT64_C(-1)) {
-                       goto error;
-               }
-
-               /* Array field expression is the encoded after this. */
-               array_field_expr = event_expr_from_payload(view, offset);
-               if (!array_field_expr) {
-                       goto error;
-               }
-
-               /* Move ownership of `array_field_expr` to new expression. */
-               expr = lttng_event_expr_array_field_element_create(
-                               array_field_expr, (unsigned int) index);
-               if (!expr) {
-                       /* `array_field_expr` not moved: destroy it. */
-                       lttng_event_expr_destroy(array_field_expr);
-               }
-
-               break;
-       }
-       default:
-               abort();
-       }
-
-       goto end;
-
-error:
-       lttng_event_expr_destroy(expr);
-       expr = NULL;
-
-end:
-       return expr;
-}
-
-LTTNG_HIDDEN
-ssize_t lttng_condition_event_rule_create_from_payload(
-               struct lttng_payload_view *view,
-               struct lttng_condition **_condition)
-{
-       ssize_t consumed_length;
-       size_t offset = 0;
-       ssize_t event_rule_length;
-       uint32_t i, capture_descr_count;
-       struct lttng_condition *condition = NULL;
-       struct lttng_event_rule *event_rule = NULL;
-
-       if (!view || !_condition) {
-               goto error;
-       }
-
-       /* Struct lttng_event_rule. */
-       {
-               struct lttng_payload_view event_rule_view =
-                               lttng_payload_view_from_view(view, offset, -1);
-
-               event_rule_length = lttng_event_rule_create_from_payload(
-                               &event_rule_view, &event_rule);
-       }
-
-       if (event_rule_length < 0 || !event_rule) {
-               goto error;
-       }
-
-       /* Create condition (no capture descriptors yet) at this point. */
-       condition = lttng_condition_event_rule_create(event_rule);
-       if (!condition) {
-               goto error;
-       }
-
-
-       /* Capture descriptor count. */
-       assert(event_rule_length >= 0);
-       offset += (size_t) event_rule_length;
-       capture_descr_count = uint_from_buffer(&view->buffer, sizeof(uint32_t), &offset);
-       if (capture_descr_count == UINT32_C(-1)) {
-               goto error;
-       }
-
-       /* Capture descriptors. */
-       for (i = 0; i < capture_descr_count; i++) {
-               enum lttng_condition_status status;
-               struct lttng_event_expr *expr = event_expr_from_payload(
-                               view, &offset);
-
-               if (!expr) {
-                       goto error;
-               }
-
-               /* Move ownership of `expr` to `condition`. */
-               status = lttng_condition_event_rule_append_capture_descriptor(
-                               condition, expr);
-               if (status != LTTNG_CONDITION_STATUS_OK) {
-                       /* `expr` not moved: destroy it. */
-                       lttng_event_expr_destroy(expr);
-                       goto error;
-               }
-       }
-
-       consumed_length = (ssize_t) offset;
-       *_condition = condition;
-       condition = NULL;
-       goto end;
-
-error:
-       consumed_length = -1;
-
-end:
-       lttng_event_rule_put(event_rule);
-       lttng_condition_put(condition);
-       return consumed_length;
-}
-
-LTTNG_HIDDEN
-enum lttng_condition_status lttng_condition_event_rule_borrow_rule_mutable(
-               const struct lttng_condition *condition,
-               struct lttng_event_rule **rule)
-{
-       struct lttng_condition_event_rule *event_rule;
-       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
-
-       if (!condition || !IS_EVENT_RULE_CONDITION(condition) || !rule) {
-               status = LTTNG_CONDITION_STATUS_INVALID;
-               goto end;
-       }
-
-       event_rule = container_of(
-                       condition, struct lttng_condition_event_rule, parent);
-       if (!event_rule->rule) {
-               status = LTTNG_CONDITION_STATUS_UNSET;
-               goto end;
-       }
-
-       *rule = event_rule->rule;
-end:
-       return status;
-}
-
-enum lttng_condition_status lttng_condition_event_rule_get_rule(
-               const struct lttng_condition *condition,
-               const struct lttng_event_rule **rule)
-{
-       struct lttng_event_rule *mutable_rule = NULL;
-       const enum lttng_condition_status status =
-                       lttng_condition_event_rule_borrow_rule_mutable(
-                               condition, &mutable_rule);
-
-       *rule = mutable_rule;
-       return status;
-}
-
-enum lttng_condition_status
-lttng_condition_event_rule_append_capture_descriptor(
-               struct lttng_condition *condition,
-               struct lttng_event_expr *expr)
-{
-       int ret;
-       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
-       struct lttng_condition_event_rule *event_rule_cond =
-                       container_of(condition,
-                               struct lttng_condition_event_rule, parent);
-       struct lttng_capture_descriptor *descriptor = NULL;
-
-       /* Only accept l-values. */
-       if (!condition || !IS_EVENT_RULE_CONDITION(condition) || !expr ||
-                       !lttng_event_expr_is_lvalue(expr)) {
-               status = LTTNG_CONDITION_STATUS_INVALID;
-               goto end;
-       }
-
-       descriptor = malloc(sizeof(*descriptor));
-       if (descriptor == NULL) {
-               status = LTTNG_CONDITION_STATUS_ERROR;
-               goto end;
-       }
-
-       descriptor->event_expression = expr;
-       descriptor->bytecode = NULL;
-
-       ret = lttng_dynamic_pointer_array_add_pointer(
-                       &event_rule_cond->capture_descriptors, descriptor);
-       if (ret) {
-               status = LTTNG_CONDITION_STATUS_ERROR;
-               goto end;
-       }
-
-       /* Ownership is transfered to the internal capture_descriptors array */
-       descriptor = NULL;
-end:
-       free(descriptor);
-       return status;
-}
-
-enum lttng_condition_status
-lttng_condition_event_rule_get_capture_descriptor_count(
-               const struct lttng_condition *condition, unsigned int *count)
-{
-       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
-       const struct lttng_condition_event_rule *event_rule_cond =
-                       container_of(condition,
-                               const struct lttng_condition_event_rule,
-                               parent);
-
-       if (!condition || !IS_EVENT_RULE_CONDITION(condition) || !count) {
-               status = LTTNG_CONDITION_STATUS_INVALID;
-               goto end;
-       }
-
-       *count = lttng_dynamic_pointer_array_get_count(
-                       &event_rule_cond->capture_descriptors);
-
-end:
-       return status;
-}
-
-const struct lttng_event_expr *
-lttng_condition_event_rule_get_capture_descriptor_at_index(
-               const struct lttng_condition *condition, unsigned int index)
-{
-       const struct lttng_event_expr *expr = NULL;
-       const struct lttng_capture_descriptor *desc = NULL;
-
-       desc = lttng_condition_event_rule_get_internal_capture_descriptor_at_index(
-                       condition, index);
-       if (desc == NULL) {
-               goto end;
-       }
-       expr = desc->event_expression;
-
-end:
-       return expr;
-}
-
-LTTNG_HIDDEN
-ssize_t lttng_evaluation_event_rule_create_from_payload(
-               struct lttng_payload_view *view,
-               struct lttng_evaluation **_evaluation)
-{
-       ssize_t ret, offset = 0;
-       const char *trigger_name;
-       struct lttng_evaluation *evaluation = NULL;
-       const struct lttng_evaluation_event_rule_comm *header;
-       const struct lttng_payload_view header_view =
-                       lttng_payload_view_from_view(
-                                       view, 0, sizeof(*header));
-
-       if (!_evaluation) {
-               ret = -1;
-               goto error;
-       }
-
-       if (!lttng_payload_view_is_valid(&header_view)) {
-               ERR("Failed to initialize from malformed event rule evaluation: buffer too short to contain header");
-               ret = -1;
-               goto error;
-       }
-
-       header = (typeof(header)) header_view.buffer.data;
-
-       /* Map the originating trigger's name. */
-       offset += sizeof(*header);
-       {
-               struct lttng_payload_view current_view =
-                               lttng_payload_view_from_view(view, offset,
-                                               header->trigger_name_length);
-
-               if (!lttng_payload_view_is_valid(&current_view)) {
-                       ERR("Failed to initialize from malformed event rule evaluation: buffer too short to contain trigger name");
-                       ret = -1;
-                       goto error;
-               }
-
-               trigger_name = current_view.buffer.data;
-               if (!lttng_buffer_view_contains_string(&current_view.buffer,
-                                   trigger_name, header->trigger_name_length)) {
-                       ERR("Failed to initialize from malformed event rule evaluation: invalid trigger name");
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       offset += header->trigger_name_length;
-
-       evaluation = lttng_evaluation_event_rule_create(trigger_name);
-       if (!evaluation) {
-               ret = -1;
-               goto error;
-       }
-
-       *_evaluation = evaluation;
-       evaluation = NULL;
-       ret = offset;
-
-error:
-       lttng_evaluation_destroy(evaluation);
-       return ret;
-}
-
-static int lttng_evaluation_event_rule_serialize(
-               const struct lttng_evaluation *evaluation,
-               struct lttng_payload *payload)
-{
-       int ret = 0;
-       struct lttng_evaluation_event_rule *hit;
-       struct lttng_evaluation_event_rule_comm comm;
-
-       hit = container_of(
-                       evaluation, struct lttng_evaluation_event_rule, parent);
-
-       assert(hit->name);
-       comm.trigger_name_length = strlen(hit->name) + 1;
-
-       ret = lttng_dynamic_buffer_append(
-                       &payload->buffer, &comm, sizeof(comm));
-       if (ret) {
-               goto end;
-       }
-
-       ret = lttng_dynamic_buffer_append(
-                       &payload->buffer, hit->name, comm.trigger_name_length);
-end:
-       return ret;
-}
-
-static void lttng_evaluation_event_rule_destroy(
-               struct lttng_evaluation *evaluation)
-{
-       struct lttng_evaluation_event_rule *hit;
-
-       hit = container_of(
-                       evaluation, struct lttng_evaluation_event_rule, parent);
-       free(hit->name);
-       free(hit);
-}
-
-LTTNG_HIDDEN
-struct lttng_evaluation *lttng_evaluation_event_rule_create(
-               const char *trigger_name)
-{
-       struct lttng_evaluation_event_rule *hit;
-       struct lttng_evaluation *evaluation = NULL;
-
-       hit = zmalloc(sizeof(struct lttng_evaluation_event_rule));
-       if (!hit) {
-               goto end;
-       }
-
-       hit->name = strdup(trigger_name);
-       if (!hit->name) {
-               goto end;
-       }
-
-       hit->parent.type = LTTNG_CONDITION_TYPE_EVENT_RULE_HIT;
-       hit->parent.serialize = lttng_evaluation_event_rule_serialize;
-       hit->parent.destroy = lttng_evaluation_event_rule_destroy;
-
-       evaluation = &hit->parent;
-       hit = NULL;
-
-end:
-       if (hit) {
-               lttng_evaluation_event_rule_destroy(&hit->parent);
-       }
-
-       return evaluation;
-}
-
-enum lttng_evaluation_status lttng_evaluation_event_rule_get_trigger_name(
-               const struct lttng_evaluation *evaluation, const char **name)
-{
-       struct lttng_evaluation_event_rule *hit;
-       enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
-
-       if (!evaluation || !is_event_rule_evaluation(evaluation) || !name) {
-               status = LTTNG_EVALUATION_STATUS_INVALID;
-               goto end;
-       }
-
-       hit = container_of(
-                       evaluation, struct lttng_evaluation_event_rule, parent);
-       *name = hit->name;
-end:
-       return status;
-}
-
-LTTNG_HIDDEN
-enum lttng_error_code
-lttng_condition_event_rule_generate_capture_descriptor_bytecode(
-               struct lttng_condition *condition)
-{
-       enum lttng_error_code ret;
-       enum lttng_condition_status status;
-       unsigned int capture_count, i;
-
-       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
-               ret = LTTNG_ERR_FATAL;
-               goto end;
-       }
-
-       status = lttng_condition_event_rule_get_capture_descriptor_count(
-                       condition, &capture_count);
-       if (status != LTTNG_CONDITION_STATUS_OK) {
-               ret = LTTNG_ERR_FATAL;
-               goto end;
-       }
-
-       for (i = 0; i < capture_count; i++) {
-               struct lttng_capture_descriptor *local_capture_desc =
-                               lttng_condition_event_rule_get_internal_capture_descriptor_at_index(
-                                               condition, i);
-
-               if (local_capture_desc == NULL) {
-                       ret = LTTNG_ERR_FATAL;
-                       goto end;
-               }
-
-               /* Generate the bytecode. */
-               status = lttng_event_expr_to_bytecode(
-                               local_capture_desc->event_expression,
-                               &local_capture_desc->bytecode);
-               if (status < 0 || local_capture_desc->bytecode == NULL) {
-                       ret = LTTNG_ERR_INVALID_CAPTURE_EXPRESSION;
-                       goto end;
-               }
-       }
-
-       /* Everything went better than expected */
-       ret = LTTNG_OK;
-
-end:
-       return ret;
-}
-
-LTTNG_HIDDEN
-const struct lttng_bytecode *
-lttng_condition_event_rule_get_capture_bytecode_at_index(
-               const struct lttng_condition *condition, unsigned int index)
-{
-       const struct lttng_condition_event_rule *event_rule_cond =
-                       container_of(condition,
-                               const struct lttng_condition_event_rule,
-                               parent);
-       struct lttng_capture_descriptor *desc = NULL;
-       struct lttng_bytecode *bytecode = NULL;
-       unsigned int count;
-       enum lttng_condition_status status;
-
-       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
-               goto end;
-       }
-
-       status = lttng_condition_event_rule_get_capture_descriptor_count(
-                       condition, &count);
-       if (status != LTTNG_CONDITION_STATUS_OK) {
-               goto end;
-       }
-
-       if (index >= count) {
-               goto end;
-       }
-
-       desc = lttng_dynamic_pointer_array_get_pointer(
-                       &event_rule_cond->capture_descriptors, index);
-       if (desc == NULL) {
-               goto end;
-       }
-
-       bytecode = desc->bytecode;
-end:
-       return bytecode;
-}
diff --git a/src/common/conditions/on-event.c b/src/common/conditions/on-event.c
new file mode 100644 (file)
index 0000000..699de46
--- /dev/null
@@ -0,0 +1,1552 @@
+/*
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <common/error.h>
+#include <common/event-expr-to-bytecode.h>
+#include <common/macros.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <lttng/condition/condition-internal.h>
+#include <lttng/condition/on-event-internal.h>
+#include <lttng/condition/on-event.h>
+#include <lttng/event-expr-internal.h>
+#include <lttng/event-expr.h>
+#include <lttng/event-field-value-internal.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/lttng-error.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <vendor/msgpack/msgpack.h>
+
+#define IS_EVENT_RULE_CONDITION(condition)      \
+       (lttng_condition_get_type(condition) == \
+                       LTTNG_CONDITION_TYPE_ON_EVENT)
+
+static bool is_event_rule_evaluation(const struct lttng_evaluation *evaluation)
+{
+       enum lttng_condition_type type = lttng_evaluation_get_type(evaluation);
+
+       return type == LTTNG_CONDITION_TYPE_ON_EVENT;
+}
+
+static bool lttng_condition_on_event_validate(
+               const struct lttng_condition *condition);
+static int lttng_condition_on_event_serialize(
+               const struct lttng_condition *condition,
+               struct lttng_payload *payload);
+static bool lttng_condition_on_event_is_equal(
+               const struct lttng_condition *_a,
+               const struct lttng_condition *_b);
+static void lttng_condition_on_event_destroy(
+               struct lttng_condition *condition);
+
+static bool lttng_condition_on_event_validate(
+               const struct lttng_condition *condition)
+{
+       bool valid = false;
+       struct lttng_condition_on_event *event_rule;
+
+       if (!condition) {
+               goto end;
+       }
+
+       event_rule = container_of(
+                       condition, struct lttng_condition_on_event, parent);
+       if (!event_rule->rule) {
+               ERR("Invalid event rule condition: a rule must be set.");
+               goto end;
+       }
+
+       valid = lttng_event_rule_validate(event_rule->rule);
+end:
+       return valid;
+}
+
+/*
+ * Serializes the C string `str` into `buf`.
+ *
+ * Encoding is the length of `str` plus one (for the null character),
+ * and then the string, including its null terminator.
+ */
+static
+int serialize_cstr(const char *str, struct lttng_dynamic_buffer *buf)
+{
+       int ret;
+       const uint32_t len = strlen(str) + 1;
+
+       /* Serialize the length, including the null terminator. */
+       DBG("Serializing C string's length (including null terminator): "
+                       "%" PRIu32, len);
+       ret = lttng_dynamic_buffer_append(buf, &len, sizeof(len));
+       if (ret) {
+               goto end;
+       }
+
+       /* Serialize the string. */
+       DBG("Serializing C string: '%s'", str);
+       ret = lttng_dynamic_buffer_append(buf, str, len);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Serializes the event expression `expr` into `buf`.
+ */
+static
+int serialize_event_expr(const struct lttng_event_expr *expr,
+               struct lttng_payload *payload)
+{
+       const uint8_t type = expr->type;
+       int ret;
+
+       /* Serialize the expression's type. */
+       DBG("Serializing event expression's type: %d", expr->type);
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &type, sizeof(type));
+       if (ret) {
+               goto end;
+       }
+
+       /* Serialize the expression */
+       switch (expr->type) {
+       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
+       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
+       {
+               const struct lttng_event_expr_field *field_expr =
+                               container_of(expr,
+                                       const struct lttng_event_expr_field,
+                                       parent);
+
+               /* Serialize the field name. */
+               DBG("Serializing field event expression's field name: '%s'",
+                               field_expr->name);
+               ret = serialize_cstr(field_expr->name, &payload->buffer);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
+       {
+               const struct lttng_event_expr_app_specific_context_field *field_expr =
+                               container_of(expr,
+                                       const struct lttng_event_expr_app_specific_context_field,
+                                       parent);
+
+               /* Serialize the provider name. */
+               DBG("Serializing app-specific context field event expression's "
+                               "provider name: '%s'",
+                               field_expr->provider_name);
+               ret = serialize_cstr(field_expr->provider_name, &payload->buffer);
+               if (ret) {
+                       goto end;
+               }
+
+               /* Serialize the type name. */
+               DBG("Serializing app-specific context field event expression's "
+                               "type name: '%s'",
+                               field_expr->provider_name);
+               ret = serialize_cstr(field_expr->type_name, &payload->buffer);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
+       {
+               const struct lttng_event_expr_array_field_element *elem_expr =
+                               container_of(expr,
+                                       const struct lttng_event_expr_array_field_element,
+                                       parent);
+               const uint32_t index = elem_expr->index;
+
+               /* Serialize the index. */
+               DBG("Serializing array field element event expression's "
+                               "index: %u", elem_expr->index);
+               ret = lttng_dynamic_buffer_append(&payload->buffer, &index, sizeof(index));
+               if (ret) {
+                       goto end;
+               }
+
+               /* Serialize the parent array field expression. */
+               DBG("Serializing array field element event expression's "
+                               "parent array field event expression.");
+               ret = serialize_event_expr(elem_expr->array_field_expr, payload);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+static
+struct lttng_capture_descriptor *
+lttng_condition_on_event_get_internal_capture_descriptor_at_index(
+               const struct lttng_condition *condition, unsigned int index)
+{
+       const struct lttng_condition_on_event *event_rule_cond =
+                       container_of(condition,
+                               const struct lttng_condition_on_event,
+                               parent);
+       struct lttng_capture_descriptor *desc = NULL;
+       unsigned int count;
+       enum lttng_condition_status status;
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
+               goto end;
+       }
+
+       status = lttng_condition_on_event_get_capture_descriptor_count(
+                       condition, &count);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto end;
+       }
+
+       if (index >= count) {
+               goto end;
+       }
+
+       desc = lttng_dynamic_pointer_array_get_pointer(
+                       &event_rule_cond->capture_descriptors, index);
+end:
+       return desc;
+}
+
+static int lttng_condition_on_event_serialize(
+               const struct lttng_condition *condition,
+               struct lttng_payload *payload)
+{
+       int ret;
+       struct lttng_condition_on_event *event_rule;
+       enum lttng_condition_status status;
+       uint64_t error_count, error_counter_index;
+       /* Used for iteration and communication (size matters). */
+       uint32_t i, capture_descr_count;
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
+               ret = -1;
+               goto end;
+       }
+
+       DBG("Serializing event rule condition");
+       event_rule = container_of(
+                       condition, struct lttng_condition_on_event, parent);
+
+       DBG("Serializing event rule condition's event rule");
+       ret = lttng_event_rule_serialize(event_rule->rule, payload);
+       if (ret) {
+               goto end;
+       }
+
+       error_counter_index = lttng_condition_on_event_get_error_counter_index(
+                       condition);
+       DBG("Serializing event rule condition's error counter index: %" PRIu64,
+                       error_counter_index);
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &error_counter_index,
+                       sizeof(error_counter_index));
+       if (ret) {
+               goto end;
+       }
+
+       error_count = lttng_condition_on_event_get_error_count(
+                       condition);
+       DBG("Serializing event rule condition's error count: %" PRIu64,
+                       error_count);
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &error_count,
+                       sizeof(error_count));
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_condition_on_event_get_capture_descriptor_count(
+                       condition, &capture_descr_count);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               ret = -1;
+               goto end;
+       };
+
+       DBG("Serializing event rule condition's capture descriptor count: %" PRIu32,
+                       capture_descr_count);
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &capture_descr_count,
+                       sizeof(capture_descr_count));
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < capture_descr_count; i++) {
+               const struct lttng_capture_descriptor *desc =
+                               lttng_condition_on_event_get_internal_capture_descriptor_at_index(
+                                               condition, i);
+
+               DBG("Serializing event rule condition's capture descriptor %" PRIu32,
+                               i);
+               ret = serialize_event_expr(desc->event_expression, payload);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+bool capture_descriptors_are_equal(
+               const struct lttng_condition *condition_a,
+               const struct lttng_condition *condition_b)
+{
+       bool is_equal = true;
+       unsigned int capture_descr_count_a;
+       unsigned int capture_descr_count_b;
+       size_t i;
+       enum lttng_condition_status status;
+
+       status = lttng_condition_on_event_get_capture_descriptor_count(
+                       condition_a, &capture_descr_count_a);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto not_equal;
+       }
+
+       status = lttng_condition_on_event_get_capture_descriptor_count(
+                       condition_b, &capture_descr_count_b);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto not_equal;
+       }
+
+       if (capture_descr_count_a != capture_descr_count_b) {
+               goto not_equal;
+       }
+
+       for (i = 0; i < capture_descr_count_a; i++) {
+               const struct lttng_event_expr *expr_a =
+                               lttng_condition_on_event_get_capture_descriptor_at_index(
+                                       condition_a,
+                                       i);
+               const struct lttng_event_expr *expr_b =
+                               lttng_condition_on_event_get_capture_descriptor_at_index(
+                                       condition_b,
+                                       i);
+
+               if (!lttng_event_expr_is_equal(expr_a, expr_b)) {
+                       goto not_equal;
+               }
+       }
+
+       goto end;
+
+not_equal:
+       is_equal = false;
+
+end:
+       return is_equal;
+}
+
+static bool lttng_condition_on_event_is_equal(
+               const struct lttng_condition *_a,
+               const struct lttng_condition *_b)
+{
+       bool is_equal = false;
+       struct lttng_condition_on_event *a, *b;
+
+       a = container_of(_a, struct lttng_condition_on_event, parent);
+       b = container_of(_b, struct lttng_condition_on_event, parent);
+
+       /* Both event rules must be set or both must be unset. */
+       if ((a->rule && !b->rule) || (!a->rule && b->rule)) {
+               WARN("Comparing event_rule conditions with uninitialized rule");
+               goto end;
+       }
+
+       is_equal = lttng_event_rule_is_equal(a->rule, b->rule);
+       if (!is_equal) {
+               goto end;
+       }
+
+       is_equal = capture_descriptors_are_equal(_a, _b);
+
+end:
+       return is_equal;
+}
+
+static void lttng_condition_on_event_destroy(
+               struct lttng_condition *condition)
+{
+       struct lttng_condition_on_event *event_rule;
+
+       event_rule = container_of(
+                       condition, struct lttng_condition_on_event, parent);
+
+       lttng_event_rule_put(event_rule->rule);
+       lttng_dynamic_pointer_array_reset(&event_rule->capture_descriptors);
+       free(event_rule);
+}
+
+static
+void destroy_capture_descriptor(void *ptr)
+{
+       struct lttng_capture_descriptor *desc =
+                       (struct lttng_capture_descriptor *) ptr;
+
+       lttng_event_expr_destroy(desc->event_expression);
+       free(desc->bytecode);
+       free(desc);
+}
+
+struct lttng_condition *lttng_condition_on_event_create(
+               struct lttng_event_rule *rule)
+{
+       struct lttng_condition *parent = NULL;
+       struct lttng_condition_on_event *condition = NULL;
+
+       if (!rule) {
+               goto end;
+       }
+
+       condition = zmalloc(sizeof(struct lttng_condition_on_event));
+       if (!condition) {
+               return NULL;
+       }
+
+       lttng_condition_init(&condition->parent,
+                       LTTNG_CONDITION_TYPE_ON_EVENT);
+       condition->parent.validate = lttng_condition_on_event_validate,
+       condition->parent.serialize = lttng_condition_on_event_serialize,
+       condition->parent.equal = lttng_condition_on_event_is_equal,
+       condition->parent.destroy = lttng_condition_on_event_destroy,
+
+       lttng_event_rule_get(rule);
+       condition->rule = rule;
+       rule = NULL;
+
+       LTTNG_OPTIONAL_SET(&condition->error_count, 0);
+       LTTNG_OPTIONAL_SET(&condition->error_counter_index, 0);
+
+       lttng_dynamic_pointer_array_init(&condition->capture_descriptors,
+                       destroy_capture_descriptor);
+
+       parent = &condition->parent;
+end:
+       return parent;
+}
+
+static
+uint64_t uint_from_buffer(const struct lttng_buffer_view *view, size_t size,
+               size_t *offset)
+{
+       uint64_t ret;
+       const struct lttng_buffer_view uint_view =
+                       lttng_buffer_view_from_view(view, *offset, size);
+
+       if (!lttng_buffer_view_is_valid(&uint_view)) {
+               ret = UINT64_C(-1);
+               goto end;
+       }
+
+       switch (size) {
+       case 1:
+               ret = (uint64_t) *uint_view.data;
+               break;
+       case sizeof(uint32_t):
+       {
+               uint32_t u32;
+
+               memcpy(&u32, uint_view.data, sizeof(u32));
+               ret = (uint64_t) u32;
+               break;
+       }
+       case sizeof(ret):
+               memcpy(&ret, uint_view.data, sizeof(ret));
+               break;
+       default:
+               abort();
+       }
+
+       *offset += size;
+
+end:
+       return ret;
+}
+
+static
+const char *str_from_buffer(const struct lttng_buffer_view *view,
+               size_t *offset)
+{
+       uint64_t len;
+       const char *ret;
+
+       len = uint_from_buffer(view, sizeof(uint32_t), offset);
+       if (len == UINT64_C(-1)) {
+               goto error;
+       }
+
+       ret = &view->data[*offset];
+
+       if (!lttng_buffer_view_contains_string(view, ret, len)) {
+               goto error;
+       }
+
+       *offset += len;
+       goto end;
+
+error:
+       ret = NULL;
+
+end:
+       return ret;
+}
+
+static
+struct lttng_event_expr *event_expr_from_payload(
+               struct lttng_payload_view *view, size_t *offset)
+{
+       struct lttng_event_expr *expr = NULL;
+       const char *str;
+       uint64_t type;
+
+       type = uint_from_buffer(&view->buffer, sizeof(uint8_t), offset);
+       if (type == UINT64_C(-1)) {
+               goto error;
+       }
+
+       switch (type) {
+       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
+               str = str_from_buffer(&view->buffer, offset);
+               if (!str) {
+                       goto error;
+               }
+
+               expr = lttng_event_expr_event_payload_field_create(str);
+               break;
+       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
+               str = str_from_buffer(&view->buffer, offset);
+               if (!str) {
+                       goto error;
+               }
+
+               expr = lttng_event_expr_channel_context_field_create(str);
+               break;
+       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
+       {
+               const char *provider_name;
+               const char *type_name;
+
+               provider_name = str_from_buffer(&view->buffer, offset);
+               if (!provider_name) {
+                       goto error;
+               }
+
+               type_name = str_from_buffer(&view->buffer, offset);
+               if (!type_name) {
+                       goto error;
+               }
+
+               expr = lttng_event_expr_app_specific_context_field_create(
+                               provider_name, type_name);
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
+       {
+               struct lttng_event_expr *array_field_expr;
+               const uint64_t index = uint_from_buffer(
+                               &view->buffer, sizeof(uint32_t), offset);
+
+               if (index == UINT64_C(-1)) {
+                       goto error;
+               }
+
+               /* Array field expression is the encoded after this. */
+               array_field_expr = event_expr_from_payload(view, offset);
+               if (!array_field_expr) {
+                       goto error;
+               }
+
+               /* Move ownership of `array_field_expr` to new expression. */
+               expr = lttng_event_expr_array_field_element_create(
+                               array_field_expr, (unsigned int) index);
+               if (!expr) {
+                       /* `array_field_expr` not moved: destroy it. */
+                       lttng_event_expr_destroy(array_field_expr);
+               }
+
+               break;
+       }
+       default:
+               abort();
+       }
+
+       goto end;
+
+error:
+       lttng_event_expr_destroy(expr);
+       expr = NULL;
+
+end:
+       return expr;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_on_event_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_condition **_condition)
+{
+       ssize_t consumed_length;
+       size_t offset = 0;
+       ssize_t event_rule_length;
+       uint32_t i, capture_descr_count;
+       uint64_t error_counter_index, error_count;
+       struct lttng_condition *condition = NULL;
+       struct lttng_event_rule *event_rule = NULL;
+
+       if (!view || !_condition) {
+               goto error;
+       }
+
+       /* Struct lttng_event_rule. */
+       {
+               struct lttng_payload_view event_rule_view =
+                               lttng_payload_view_from_view(view, offset, -1);
+
+               event_rule_length = lttng_event_rule_create_from_payload(
+                               &event_rule_view, &event_rule);
+       }
+
+       if (event_rule_length < 0 || !event_rule) {
+               goto error;
+       }
+
+       offset += event_rule_length;
+
+       /* Error counter index. */
+       error_counter_index = uint_from_buffer(&view->buffer, sizeof(uint64_t),
+                       &offset);
+       if (error_counter_index == UINT64_C(-1)) {
+               goto error;
+       }
+
+       /* Error count. */
+       error_count = uint_from_buffer(&view->buffer, sizeof(uint64_t), &offset);
+       if (error_count == UINT64_C(-1)) {
+               goto error;
+       }
+
+       /* Create condition (no capture descriptors yet) at this point */
+       condition = lttng_condition_on_event_create(event_rule);
+       if (!condition) {
+               goto error;
+       }
+
+       lttng_condition_on_event_set_error_count(condition, error_count);
+       lttng_condition_on_event_set_error_counter_index(condition,
+                       error_counter_index);
+
+       /* Capture descriptor count. */
+       assert(event_rule_length >= 0);
+       capture_descr_count = uint_from_buffer(&view->buffer, sizeof(uint32_t), &offset);
+       if (capture_descr_count == UINT32_C(-1)) {
+               goto error;
+       }
+
+       /* Capture descriptors. */
+       for (i = 0; i < capture_descr_count; i++) {
+               enum lttng_condition_status status;
+               struct lttng_event_expr *expr = event_expr_from_payload(
+                               view, &offset);
+
+               if (!expr) {
+                       goto error;
+               }
+
+               /* Move ownership of `expr` to `condition`. */
+               status = lttng_condition_on_event_append_capture_descriptor(
+                               condition, expr);
+               if (status != LTTNG_CONDITION_STATUS_OK) {
+                       /* `expr` not moved: destroy it. */
+                       lttng_event_expr_destroy(expr);
+                       goto error;
+               }
+       }
+
+       consumed_length = (ssize_t) offset;
+       *_condition = condition;
+       condition = NULL;
+       goto end;
+
+error:
+       consumed_length = -1;
+
+end:
+       lttng_event_rule_put(event_rule);
+       lttng_condition_put(condition);
+       return consumed_length;
+}
+
+LTTNG_HIDDEN
+enum lttng_condition_status lttng_condition_on_event_borrow_rule_mutable(
+               const struct lttng_condition *condition,
+               struct lttng_event_rule **rule)
+{
+       struct lttng_condition_on_event *event_rule;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition) || !rule) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       event_rule = container_of(
+                       condition, struct lttng_condition_on_event, parent);
+       if (!event_rule->rule) {
+               status = LTTNG_CONDITION_STATUS_UNSET;
+               goto end;
+       }
+
+       *rule = event_rule->rule;
+end:
+       return status;
+}
+
+enum lttng_condition_status lttng_condition_on_event_get_rule(
+               const struct lttng_condition *condition,
+               const struct lttng_event_rule **rule)
+{
+       struct lttng_event_rule *mutable_rule = NULL;
+       const enum lttng_condition_status status =
+                       lttng_condition_on_event_borrow_rule_mutable(
+                               condition, &mutable_rule);
+
+       *rule = mutable_rule;
+       return status;
+}
+
+void lttng_condition_on_event_set_error_counter_index(
+               struct lttng_condition *condition, uint64_t error_counter_index)
+{
+       struct lttng_condition_on_event *on_event_cond =
+                       container_of(condition,
+                               struct lttng_condition_on_event, parent);
+
+       LTTNG_OPTIONAL_SET(&on_event_cond->error_counter_index, error_counter_index);
+}
+
+uint64_t lttng_condition_on_event_get_error_counter_index(
+               const struct lttng_condition *condition)
+{
+       struct lttng_condition_on_event *on_event_cond =
+                       container_of(condition,
+                               struct lttng_condition_on_event, parent);
+
+       return LTTNG_OPTIONAL_GET(on_event_cond->error_counter_index);
+}
+
+void lttng_condition_on_event_set_error_count(struct lttng_condition *condition,
+               uint64_t error_count)
+{
+       struct lttng_condition_on_event *on_event_cond =
+                       container_of(condition,
+                               struct lttng_condition_on_event, parent);
+
+       LTTNG_OPTIONAL_SET(&on_event_cond->error_count, error_count);
+}
+
+uint64_t lttng_condition_on_event_get_error_count(
+               const struct lttng_condition *condition)
+{
+       struct lttng_condition_on_event *on_event_cond =
+                       container_of(condition,
+                               struct lttng_condition_on_event, parent);
+
+       return LTTNG_OPTIONAL_GET(on_event_cond->error_count);
+}
+
+enum lttng_condition_status
+lttng_condition_on_event_append_capture_descriptor(
+               struct lttng_condition *condition,
+               struct lttng_event_expr *expr)
+{
+       int ret;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+       struct lttng_condition_on_event *on_event_cond =
+                       container_of(condition,
+                               struct lttng_condition_on_event, parent);
+       struct lttng_capture_descriptor *descriptor = NULL;
+       const struct lttng_event_rule *rule = NULL;
+
+       /* Only accept l-values. */
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition) || !expr ||
+                       !lttng_event_expr_is_lvalue(expr)) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       status = lttng_condition_on_event_get_rule(condition, &rule);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto end;
+       }
+
+       switch(lttng_event_rule_get_type(rule)) {
+       case LTTNG_EVENT_RULE_TYPE_TRACEPOINT:
+       case LTTNG_EVENT_RULE_TYPE_SYSCALL:
+               /* Supported */
+               status = LTTNG_CONDITION_STATUS_OK;
+               break;
+       case LTTNG_EVENT_RULE_TYPE_UNKNOWN:
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               break;
+       default:
+               status = LTTNG_CONDITION_STATUS_UNSUPPORTED;
+               break;
+       }
+
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto end;
+       }
+
+       descriptor = malloc(sizeof(*descriptor));
+       if (descriptor == NULL) {
+               status = LTTNG_CONDITION_STATUS_ERROR;
+               goto end;
+       }
+
+       descriptor->event_expression = expr;
+       descriptor->bytecode = NULL;
+
+       ret = lttng_dynamic_pointer_array_add_pointer(
+                       &on_event_cond->capture_descriptors, descriptor);
+       if (ret) {
+               status = LTTNG_CONDITION_STATUS_ERROR;
+               goto end;
+       }
+
+       /* Ownership is transfered to the internal capture_descriptors array */
+       descriptor = NULL;
+end:
+       free(descriptor);
+       return status;
+}
+
+enum lttng_condition_status
+lttng_condition_on_event_get_capture_descriptor_count(
+               const struct lttng_condition *condition, unsigned int *count)
+{
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+       const struct lttng_condition_on_event *event_rule_cond =
+                       container_of(condition,
+                               const struct lttng_condition_on_event,
+                               parent);
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition) || !count) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       *count = lttng_dynamic_pointer_array_get_count(
+                       &event_rule_cond->capture_descriptors);
+
+end:
+       return status;
+}
+
+const struct lttng_event_expr *
+lttng_condition_on_event_get_capture_descriptor_at_index(
+               const struct lttng_condition *condition, unsigned int index)
+{
+       const struct lttng_event_expr *expr = NULL;
+       const struct lttng_capture_descriptor *desc = NULL;
+
+       desc = lttng_condition_on_event_get_internal_capture_descriptor_at_index(
+                       condition, index);
+       if (desc == NULL) {
+               goto end;
+       }
+       expr = desc->event_expression;
+
+end:
+       return expr;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_event_rule_create_from_payload(
+               const struct lttng_condition_on_event *condition,
+               struct lttng_payload_view *view,
+               struct lttng_evaluation **_evaluation)
+{
+       ssize_t ret, offset = 0;
+       const char *trigger_name;
+       struct lttng_evaluation *evaluation = NULL;
+       const struct lttng_evaluation_event_rule_comm *header;
+       const struct lttng_payload_view header_view =
+                       lttng_payload_view_from_view(
+                                       view, 0, sizeof(*header));
+       uint32_t capture_payload_size;
+       const char *capture_payload = NULL;
+
+       if (!_evaluation) {
+               ret = -1;
+               goto error;
+       }
+
+       if (!lttng_payload_view_is_valid(&header_view)) {
+               ERR("Failed to initialize from malformed event rule evaluation: buffer too short to contain header");
+               ret = -1;
+               goto error;
+       }
+
+       header = (typeof(header)) header_view.buffer.data;
+
+       /* Map the originating trigger's name. */
+       offset += sizeof(*header);
+       {
+               const struct lttng_payload_view current_view =
+                               lttng_payload_view_from_view(view, offset,
+                                               header->trigger_name_length);
+
+               if (!lttng_payload_view_is_valid(&current_view)) {
+                       ERR("Failed to initialize from malformed event rule evaluation: buffer too short to contain trigger name");
+                       ret = -1;
+                       goto error;
+               }
+
+               trigger_name = current_view.buffer.data;
+               if (!lttng_buffer_view_contains_string(&current_view.buffer,
+                                   trigger_name, header->trigger_name_length)) {
+                       ERR("Failed to initialize from malformed event rule evaluation: invalid trigger name");
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       offset += header->trigger_name_length;
+       {
+               const struct lttng_payload_view current_view =
+                               lttng_payload_view_from_view(view, offset, -1);
+
+               if (current_view.buffer.size < sizeof(capture_payload_size)) {
+                       ret = -1;
+                       goto error;
+               }
+
+               memcpy(&capture_payload_size, current_view.buffer.data,
+                               sizeof(capture_payload_size));
+       }
+       offset += sizeof(capture_payload_size);
+
+       if (capture_payload_size > 0) {
+               const struct lttng_payload_view current_view =
+                               lttng_payload_view_from_view(view, offset, -1);
+
+               if (current_view.buffer.size < capture_payload_size) {
+                       ret = -1;
+                       goto error;
+               }
+
+               capture_payload = current_view.buffer.data;
+       }
+
+       evaluation = lttng_evaluation_event_rule_create(condition, trigger_name,
+                       capture_payload, capture_payload_size, true);
+       if (!evaluation) {
+               ret = -1;
+               goto error;
+       }
+
+       offset += capture_payload_size;
+       *_evaluation = evaluation;
+       evaluation = NULL;
+       ret = offset;
+
+error:
+       lttng_evaluation_destroy(evaluation);
+       return ret;
+}
+
+static int lttng_evaluation_event_rule_serialize(
+               const struct lttng_evaluation *evaluation,
+               struct lttng_payload *payload)
+{
+       int ret = 0;
+       struct lttng_evaluation_event_rule *hit;
+       struct lttng_evaluation_event_rule_comm comm;
+       uint32_t capture_payload_size;
+
+       hit = container_of(
+                       evaluation, struct lttng_evaluation_event_rule, parent);
+
+       assert(hit->name);
+       comm.trigger_name_length = strlen(hit->name) + 1;
+
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, &comm, sizeof(comm));
+       if (ret) {
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, hit->name, comm.trigger_name_length);
+       if (ret) {
+               goto end;
+       }
+
+       capture_payload_size = (uint32_t) hit->capture_payload.size;
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &capture_payload_size,
+                       sizeof(capture_payload_size));
+       if (ret) {
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, hit->capture_payload.data,
+                       hit->capture_payload.size);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+bool msgpack_str_is_equal(const struct msgpack_object *obj, const char *str)
+{
+       bool is_equal = true;
+
+       assert(obj->type == MSGPACK_OBJECT_STR);
+
+       if (obj->via.str.size != strlen(str)) {
+               is_equal = false;
+               goto end;
+       }
+
+       if (strncmp(obj->via.str.ptr, str, obj->via.str.size) != 0) {
+               is_equal = false;
+               goto end;
+       }
+
+end:
+       return is_equal;
+}
+
+static
+const msgpack_object *get_msgpack_map_obj(const struct msgpack_object *map_obj,
+               const char *name)
+{
+       const msgpack_object *ret = NULL;
+       size_t i;
+
+       assert(map_obj->type == MSGPACK_OBJECT_MAP);
+
+       for (i = 0; i < map_obj->via.map.size; i++) {
+               const struct msgpack_object_kv *kv = &map_obj->via.map.ptr[i];
+
+               assert(kv->key.type == MSGPACK_OBJECT_STR);
+
+               if (msgpack_str_is_equal(&kv->key, name)) {
+                       ret = &kv->val;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static void lttng_evaluation_event_rule_destroy(
+               struct lttng_evaluation *evaluation)
+{
+       struct lttng_evaluation_event_rule *hit;
+
+       hit = container_of(
+                       evaluation, struct lttng_evaluation_event_rule, parent);
+       free(hit->name);
+       lttng_dynamic_buffer_reset(&hit->capture_payload);
+       lttng_event_field_value_destroy(hit->captured_values);
+       free(hit);
+}
+
+static
+int event_field_value_from_obj(const msgpack_object *obj,
+               struct lttng_event_field_value **field_val)
+{
+       int ret = 0;
+
+       assert(obj);
+       assert(field_val);
+
+       switch (obj->type) {
+       case MSGPACK_OBJECT_NIL:
+               /* Unavailable. */
+               *field_val = NULL;
+               goto end;
+       case MSGPACK_OBJECT_POSITIVE_INTEGER:
+               *field_val = lttng_event_field_value_uint_create(
+                               obj->via.u64);
+               break;
+       case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+               *field_val = lttng_event_field_value_int_create(
+                               obj->via.i64);
+               break;
+       case MSGPACK_OBJECT_FLOAT32:
+       case MSGPACK_OBJECT_FLOAT64:
+               *field_val = lttng_event_field_value_real_create(
+                               obj->via.f64);
+               break;
+       case MSGPACK_OBJECT_STR:
+               *field_val = lttng_event_field_value_string_create_with_size(
+                               obj->via.str.ptr, obj->via.str.size);
+               break;
+       case MSGPACK_OBJECT_ARRAY:
+       {
+               size_t i;
+
+               *field_val = lttng_event_field_value_array_create();
+               if (!*field_val) {
+                       goto error;
+               }
+
+               for (i = 0; i < obj->via.array.size; i++) {
+                       const msgpack_object *elem_obj = &obj->via.array.ptr[i];
+                       struct lttng_event_field_value *elem_field_val;
+
+                       ret = event_field_value_from_obj(elem_obj,
+                                       &elem_field_val);
+                       if (ret) {
+                               goto error;
+                       }
+
+                       if (elem_field_val) {
+                               ret = lttng_event_field_value_array_append(
+                                               *field_val, elem_field_val);
+                       } else {
+                               ret = lttng_event_field_value_array_append_unavailable(
+                                               *field_val);
+                       }
+
+                       if (ret) {
+                               lttng_event_field_value_destroy(elem_field_val);
+                               goto error;
+                       }
+               }
+
+               break;
+       }
+       case MSGPACK_OBJECT_MAP:
+       {
+               /*
+                * As of this version, the only valid map object is
+                * for an enumeration value, for example:
+                *
+                *     type: enum
+                *     value: 177
+                *     labels:
+                *     - Labatt 50
+                *     - Molson Dry
+                *     - Carling Black Label
+                */
+               const msgpack_object *inner_obj;
+               size_t label_i;
+
+               inner_obj = get_msgpack_map_obj(obj, "type");
+               if (!inner_obj) {
+                       ERR("Missing `type` entry in map object.");
+                       goto error;
+               }
+
+               if (inner_obj->type != MSGPACK_OBJECT_STR) {
+                       ERR("Map object's `type` entry is not a string (it's a %d).",
+                                       inner_obj->type);
+                       goto error;
+               }
+
+               if (!msgpack_str_is_equal(inner_obj, "enum")) {
+                       ERR("Map object's `type` entry: expecting `enum`.");
+                       goto error;
+               }
+
+               inner_obj = get_msgpack_map_obj(obj, "value");
+               if (!inner_obj) {
+                       ERR("Missing `value` entry in map object.");
+                       goto error;
+               }
+
+               if (inner_obj->type == MSGPACK_OBJECT_POSITIVE_INTEGER) {
+                       *field_val = lttng_event_field_value_enum_uint_create(
+                                       inner_obj->via.u64);
+               } else if (inner_obj->type == MSGPACK_OBJECT_NEGATIVE_INTEGER) {
+                       *field_val = lttng_event_field_value_enum_int_create(
+                                       inner_obj->via.i64);
+               } else {
+                       ERR("Map object's `value` entry is not an integer (it's a %d).",
+                                       inner_obj->type);
+                       goto error;
+               }
+
+               if (!*field_val) {
+                       goto error;
+               }
+
+               inner_obj = get_msgpack_map_obj(obj, "labels");
+               if (!inner_obj) {
+                       /* No labels */
+                       goto end;
+               }
+
+               if (inner_obj->type != MSGPACK_OBJECT_ARRAY) {
+                       ERR("Map object's `labels` entry is not an array (it's a %d).",
+                                       inner_obj->type);
+                       goto error;
+               }
+
+               for (label_i = 0; label_i < inner_obj->via.array.size;
+                               label_i++) {
+                       int iret;
+                       const msgpack_object *elem_obj =
+                                       &inner_obj->via.array.ptr[label_i];
+
+                       if (elem_obj->type != MSGPACK_OBJECT_STR) {
+                               ERR("Map object's `labels` entry's type is not a string (it's a %d).",
+                                               elem_obj->type);
+                               goto error;
+                       }
+
+                       iret = lttng_event_field_value_enum_append_label_with_size(
+                                       *field_val, elem_obj->via.str.ptr,
+                                       elem_obj->via.str.size);
+                       if (iret) {
+                               goto error;
+                       }
+               }
+
+               break;
+       }
+       default:
+               ERR("Unexpected object type %d.", obj->type);
+               goto error;
+       }
+
+       if (!*field_val) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(*field_val);
+       *field_val = NULL;
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+struct lttng_event_field_value *event_field_value_from_capture_payload(
+               const struct lttng_condition_on_event *condition,
+               const char *capture_payload, size_t capture_payload_size)
+{
+       struct lttng_event_field_value *ret = NULL;
+       msgpack_unpacked unpacked;
+       msgpack_unpack_return unpack_return;
+       const msgpack_object *root_obj;
+       const msgpack_object_array *root_array_obj;
+       size_t i;
+       size_t count;
+
+       assert(condition);
+       assert(capture_payload);
+
+       /* Initialize value. */
+       msgpack_unpacked_init(&unpacked);
+
+       /* Decode. */
+       unpack_return = msgpack_unpack_next(&unpacked, capture_payload,
+                       capture_payload_size, NULL);
+       if (unpack_return != MSGPACK_UNPACK_SUCCESS) {
+               ERR("msgpack_unpack_next() failed to decode the "
+                               "MessagePack-encoded capture payload "
+                               "(size %zu); returned %d.",
+                               capture_payload_size, unpack_return);
+               goto error;
+       }
+
+       /* Get root array. */
+       root_obj = &unpacked.data;
+
+       if (root_obj->type != MSGPACK_OBJECT_ARRAY) {
+               ERR("Expecting an array as the root object; got type %d.",
+                               root_obj->type);
+               goto error;
+       }
+
+       root_array_obj = &root_obj->via.array;
+
+       /* Create an empty root array event field value. */
+       ret = lttng_event_field_value_array_create();
+       if (!ret) {
+               goto error;
+       }
+
+       /*
+        * For each capture descriptor in the condition object:
+        *
+        * 1. Get its corresponding captured field value MessagePack
+        *    object.
+        *
+        * 2. Create a corresponding event field value.
+        *
+        * 3. Append it to `ret` (the root array event field value).
+        */
+       count = lttng_dynamic_pointer_array_get_count(
+                       &condition->capture_descriptors);
+       assert(count > 0);
+
+       for (i = 0; i < count; i++) {
+               const struct lttng_capture_descriptor *capture_descriptor =
+                               lttng_condition_on_event_get_internal_capture_descriptor_at_index(
+                                               &condition->parent, i);
+               const msgpack_object *elem_obj;
+               struct lttng_event_field_value *elem_field_val;
+               int iret;
+
+               assert(capture_descriptor);
+
+               elem_obj = &root_array_obj->ptr[i];
+               iret = event_field_value_from_obj(elem_obj,
+                               &elem_field_val);
+               if (iret) {
+                       goto error;
+               }
+
+               if (elem_field_val) {
+                       iret = lttng_event_field_value_array_append(ret,
+                                       elem_field_val);
+               } else {
+                       iret = lttng_event_field_value_array_append_unavailable(
+                                       ret);
+               }
+
+               if (iret) {
+                       lttng_event_field_value_destroy(elem_field_val);
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       lttng_event_field_value_destroy(ret);
+       ret = NULL;
+
+end:
+       msgpack_unpacked_destroy(&unpacked);
+       return ret;
+}
+
+LTTNG_HIDDEN
+struct lttng_evaluation *lttng_evaluation_event_rule_create(
+               const struct lttng_condition_on_event *condition,
+               const char *trigger_name,
+               const char *capture_payload, size_t capture_payload_size,
+               bool decode_capture_payload)
+{
+       struct lttng_evaluation_event_rule *hit;
+       struct lttng_evaluation *evaluation = NULL;
+
+       hit = zmalloc(sizeof(struct lttng_evaluation_event_rule));
+       if (!hit) {
+               goto error;
+       }
+
+       hit->name = strdup(trigger_name);
+       if (!hit->name) {
+               goto error;
+       }
+
+       lttng_dynamic_buffer_init(&hit->capture_payload);
+
+       if (capture_payload) {
+               const int ret = lttng_dynamic_buffer_append(
+                               &hit->capture_payload, capture_payload,
+                               capture_payload_size);
+               if (ret) {
+                       ERR("Failed to initialize capture payload of event rule evaluation");
+                       goto error;
+               }
+
+               if (decode_capture_payload) {
+                       hit->captured_values =
+                                       event_field_value_from_capture_payload(
+                                               condition,
+                                               capture_payload,
+                                               capture_payload_size);
+                       if (!hit->captured_values) {
+                               ERR("Failed to decode the capture payload: size = %zu",
+                                               capture_payload_size);
+                               goto error;
+                       }
+               }
+       }
+
+       hit->parent.type = LTTNG_CONDITION_TYPE_ON_EVENT;
+       hit->parent.serialize = lttng_evaluation_event_rule_serialize;
+       hit->parent.destroy = lttng_evaluation_event_rule_destroy;
+
+       evaluation = &hit->parent;
+       hit = NULL;
+
+error:
+       if (hit) {
+               lttng_evaluation_event_rule_destroy(&hit->parent);
+       }
+
+       return evaluation;
+}
+
+enum lttng_evaluation_status lttng_evaluation_get_captured_values(
+               const struct lttng_evaluation *evaluation,
+               const struct lttng_event_field_value **field_val)
+{
+       struct lttng_evaluation_event_rule *hit;
+       enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
+
+       /*
+        * Event rule is currently the only type that can provide captured
+        * values.
+        */
+       if (!evaluation || !is_event_rule_evaluation(evaluation) ||
+                       !field_val) {
+               status = LTTNG_EVALUATION_STATUS_INVALID;
+               goto end;
+       }
+
+       hit = container_of(evaluation, struct lttng_evaluation_event_rule,
+                       parent);
+       if (!hit->captured_values) {
+               status = LTTNG_EVALUATION_STATUS_INVALID;
+               goto end;
+       }
+
+       *field_val = hit->captured_values;
+
+end:
+       return status;
+}
+
+enum lttng_evaluation_status lttng_evaluation_event_rule_get_trigger_name(
+               const struct lttng_evaluation *evaluation, const char **name)
+{
+       struct lttng_evaluation_event_rule *hit;
+       enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
+
+       if (!evaluation || !is_event_rule_evaluation(evaluation) || !name) {
+               status = LTTNG_EVALUATION_STATUS_INVALID;
+               goto end;
+       }
+
+       hit = container_of(
+                       evaluation, struct lttng_evaluation_event_rule, parent);
+       *name = hit->name;
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+enum lttng_error_code
+lttng_condition_on_event_generate_capture_descriptor_bytecode(
+               struct lttng_condition *condition)
+{
+       enum lttng_error_code ret;
+       enum lttng_condition_status status;
+       unsigned int capture_count, i;
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
+               ret = LTTNG_ERR_FATAL;
+               goto end;
+       }
+
+       status = lttng_condition_on_event_get_capture_descriptor_count(
+                       condition, &capture_count);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               ret = LTTNG_ERR_FATAL;
+               goto end;
+       }
+
+       for (i = 0; i < capture_count; i++) {
+               struct lttng_capture_descriptor *local_capture_desc =
+                               lttng_condition_on_event_get_internal_capture_descriptor_at_index(
+                                               condition, i);
+
+               if (local_capture_desc == NULL) {
+                       ret = LTTNG_ERR_FATAL;
+                       goto end;
+               }
+
+               /* Generate the bytecode. */
+               status = lttng_event_expr_to_bytecode(
+                               local_capture_desc->event_expression,
+                               &local_capture_desc->bytecode);
+               if (status < 0 || local_capture_desc->bytecode == NULL) {
+                       ret = LTTNG_ERR_INVALID_CAPTURE_EXPRESSION;
+                       goto end;
+               }
+       }
+
+       /* Everything went better than expected */
+       ret = LTTNG_OK;
+
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+const struct lttng_bytecode *
+lttng_condition_on_event_get_capture_bytecode_at_index(
+               const struct lttng_condition *condition, unsigned int index)
+{
+       const struct lttng_condition_on_event *on_event_cond =
+                       container_of(condition,
+                               const struct lttng_condition_on_event,
+                               parent);
+       struct lttng_capture_descriptor *desc = NULL;
+       struct lttng_bytecode *bytecode = NULL;
+       unsigned int count;
+       enum lttng_condition_status status;
+
+       if (!condition || !IS_EVENT_RULE_CONDITION(condition)) {
+               goto end;
+       }
+
+       status = lttng_condition_on_event_get_capture_descriptor_count(
+                       condition, &count);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               goto end;
+       }
+
+       if (index >= count) {
+               goto end;
+       }
+
+       desc = lttng_dynamic_pointer_array_get_pointer(
+                       &on_event_cond->capture_descriptors, index);
+       if (desc == NULL) {
+               goto end;
+       }
+
+       bytecode = desc->bytecode;
+end:
+       return bytecode;
+}
index 75ff303d49a818dbf34f0b489bee520d97cb3255..85ff4ed144e489ef6719e138a440c4f09fb0d479 100644 (file)
@@ -11,6 +11,8 @@
 extern const char * const config_element_all;
 extern const char * const config_element_channel;
 extern const char * const config_element_channels;
+extern const char * const config_element_map;
+extern const char * const config_element_maps;
 extern const char * const config_element_domain;
 extern const char * const config_element_domains;
 extern const char * const config_element_event;
@@ -99,6 +101,15 @@ extern const char * const config_element_rotation_timer_interval;
 extern const char * const config_element_rotation_size;
 extern const char * const config_element_rotation_schedule;
 
+extern const char * const config_element_bitness;
+extern const char * const config_element_boundary_policy;
+extern const char * const config_element_coalesce_hits;
+extern const char * const config_element_dimensions;
+extern const char * const config_element_dimension;
+extern const char * const config_element_dimension_size;
+
+extern const char * const config_boundary_policy_overflow;
+
 extern const char * const config_domain_type_kernel;
 extern const char * const config_domain_type_ust;
 extern const char * const config_domain_type_jul;
index 49c06a3531b874d734ac03659f8b09f14d1f0132..70668470c4445a70494c0bf1b98ea91f35e77efd 100644 (file)
@@ -24,6 +24,7 @@
 #include <common/macros.h>
 #include <common/utils.h>
 #include <common/dynamic-buffer.h>
+#include <common/dynamic-array.h>
 #include <common/compat/getenv.h>
 #include <lttng/lttng-error.h>
 #include <libxml/parser.h>
@@ -67,6 +68,8 @@ const char * const config_xml_false = "false";
 
 const char * const config_element_channel = "channel";
 const char * const config_element_channels = "channels";
+const char * const config_element_map = "map";
+const char * const config_element_maps = "maps";
 const char * const config_element_domain = "domain";
 const char * const config_element_domains = "domains";
 const char * const config_element_event = "event";
@@ -183,6 +186,15 @@ const char * const config_overwrite_mode_overwrite = "OVERWRITE";
 const char * const config_output_type_splice = "SPLICE";
 const char * const config_output_type_mmap = "MMAP";
 
+LTTNG_HIDDEN const char * const config_element_bitness = "bitness";
+LTTNG_HIDDEN const char * const config_element_boundary_policy = "boundary_policy";
+LTTNG_HIDDEN const char * const config_element_coalesce_hits = "coalesce_hits";
+LTTNG_HIDDEN const char * const config_element_dimensions = "dimensions";
+LTTNG_HIDDEN const char * const config_element_dimension = "dimension";
+LTTNG_HIDDEN const char * const config_element_dimension_size = "size";
+
+LTTNG_HIDDEN const char * const config_boundary_policy_overflow = "OVERFLOW";
+
 const char * const config_loglevel_type_all = "ALL";
 const char * const config_loglevel_type_range = "RANGE";
 const char * const config_loglevel_type_single = "SINGLE";
@@ -3054,14 +3066,299 @@ end:
        return ret;
 }
 
+static
+int process_channel_node(xmlNodePtr channel_node, struct lttng_handle *handle,
+               struct lttng_domain *domain,
+               enum lttng_domain_type original_domain)
+{
+       int ret;
+       struct lttng_channel *channel = NULL;
+       xmlNodePtr contexts_node = NULL;
+       xmlNodePtr events_node = NULL;
+       xmlNodePtr channel_attr_node;
+
+       /*
+        * Channels of the "agent" types cannot be created directly.
+        * They are meant to be created implicitly through the
+        * activation of events in their domain. However, a user
+        * can override the default channel configuration attributes
+        * by creating the underlying UST channel _before_ enabling
+        * an agent domain event.
+        *
+        * Hence, the channel's type is substituted before the creation
+        * and restored by the time the events are created.
+        */
+       switch (domain->type) {
+       case LTTNG_DOMAIN_JUL:
+       case LTTNG_DOMAIN_LOG4J:
+       case LTTNG_DOMAIN_PYTHON:
+               domain->type = LTTNG_DOMAIN_UST;
+       default:
+               break;
+       }
+
+       channel = lttng_channel_create(domain);
+       if (!channel) {
+               ret = -1;
+               goto end;
+       }
+
+       for (channel_attr_node = xmlFirstElementChild(channel_node);
+               channel_attr_node; channel_attr_node =
+               xmlNextElementSibling(channel_attr_node)) {
+               ret = process_channel_attr_node(channel_attr_node,
+                       channel, &contexts_node, &events_node);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = lttng_enable_channel(handle, channel);
+       if (ret < 0) {
+               goto end;
+       }
+
+       /* Restore the original channel domain-> */
+       domain->type = original_domain;
+
+       ret = process_events_node(events_node, handle, channel->name);
+       if (ret) {
+               goto end;
+       }
+
+       ret = process_contexts_node(contexts_node, handle,
+               channel->name);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       lttng_channel_destroy(channel);
+       return ret;
+}
+
+static int process_dimension_node(xmlNodePtr dimension_node,
+               struct lttng_dynamic_array *dimension_sizes)
+{
+       int ret;
+       xmlNodePtr node;
+       xmlChar *size_str = NULL;
+       uint64_t size;
+
+       assert(strcmp((const char *) dimension_node->name,
+                              config_element_dimension) == 0);
+       assert(dimension_sizes->element_size == sizeof(uint64_t));
+
+       for (node = xmlFirstElementChild(dimension_node); node;
+                       node = xmlNextElementSibling(node)) {
+               if (strcmp((const char *) node->name,
+                                   config_element_dimension_size) == 0) {
+                       assert(!size_str);
+                       size_str = xmlNodeGetContent(node);
+                       if (!size_str) {
+                               ERR("Failed to get dimension size node content.");
+                               ret = -LTTNG_ERR_NOMEM;
+                               goto end;
+                       }
+
+                       ret = parse_uint(size_str, &size);
+                       assert(!ret);
+
+                       ret = lttng_dynamic_array_add_element(dimension_sizes, &size);
+                       if (ret) {
+                               goto end;
+                       }
+               } else {
+                       assert(false);
+               }
+       }
+
+       ret = 0;
+
+end:
+       xmlFree(size_str);
+       return ret;
+}
+
+/* `dimensions_sizes` must be initialized to hold uint64_t elements. */
+
+static int process_dimensions_node(xmlNodePtr dimensions_node,
+               struct lttng_dynamic_array *dimension_sizes)
+{
+       xmlNodePtr dimension_node;
+       int ret = 0;
+
+       assert(strcmp((const char *) dimensions_node->name,
+                              config_element_dimensions) == 0);
+       assert(dimension_sizes->element_size == sizeof(uint64_t));
+       assert(lttng_dynamic_array_get_count(dimension_sizes) == 0);
+
+       for (dimension_node = xmlFirstElementChild(dimensions_node);
+                       dimension_node; dimension_node = xmlNextElementSibling(
+                                                       dimension_node)) {
+               ret = process_dimension_node(dimension_node, dimension_sizes);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       assert(lttng_dynamic_array_get_count(dimension_sizes) > 0);
+
+end:
+       return ret;
+}
+
+static int process_map_node(xmlNodePtr map_node, struct lttng_handle *handle)
+{
+       int ret;
+       xmlNodePtr node;
+       xmlChar *name = NULL;
+       xmlChar *enabled_str = NULL;
+       int enabled;
+       xmlChar *bitness_str = NULL;
+       enum lttng_map_bitness bitness = LTTNG_MAP_BITNESS_32BITS;
+       xmlChar *boundary_policy_str = NULL;
+       enum lttng_map_boundary_policy boundary_policy = LTTNG_MAP_BOUNDARY_POLICY_OVERFLOW;
+       xmlChar *coalesce_hits_str = NULL;
+       int coalesce_hits;
+       enum lttng_map_status map_status;
+       struct lttng_map *map = NULL;
+       struct lttng_dynamic_array dimension_sizes;
+       enum lttng_error_code error_code;
+
+       assert(strcmp((const char *) map_node->name, config_element_map) == 0);
+
+       lttng_dynamic_array_init(&dimension_sizes, sizeof(uint64_t), NULL);
+
+       for (node = xmlFirstElementChild(map_node); node;
+                       node = xmlNextElementSibling(node)) {
+               if (strcmp((const char *) node->name, config_element_name) ==
+                               0) {
+                       assert(!name);
+                       name = xmlNodeGetContent(node);
+                       if (!name) {
+                               ERR("Failed to get map name node content.");
+                               ret = -LTTNG_ERR_NOMEM;
+                               goto end;
+                       }
+               } else if (strcmp((const char *) node->name,
+                                          config_element_enabled) == 0) {
+                       assert(!enabled_str);
+                       enabled_str = xmlNodeGetContent(node);
+                       if (!enabled_str) {
+                               ERR("Failed to get map enabled node content.");
+                               ret = -LTTNG_ERR_NOMEM;
+                               goto end;
+                       }
+
+                       ret = parse_bool(enabled_str, &enabled);
+                       assert(!ret);
+               } else if (strcmp((const char *) node->name,
+                                          config_element_bitness) == 0) {
+                       assert(!bitness_str);
+                       bitness_str = xmlNodeGetContent(node);
+                       if (!bitness_str) {
+                               ERR("Failed to get map bitness node content.");
+                               ret = -LTTNG_ERR_NOMEM;
+                               goto end;
+                       }
+
+                       if (strcmp((const char *) bitness_str, "32") == 0) {
+                               bitness = LTTNG_MAP_BITNESS_32BITS;
+                       } else {
+                               assert(strcmp((const char *) bitness_str,
+                                                      "64") == 0);
+                               bitness = LTTNG_MAP_BITNESS_64BITS;
+                       }
+               } else if (strcmp((const char *) node->name,
+                                          config_element_boundary_policy) ==
+                               0) {
+                       assert(!boundary_policy_str);
+                       boundary_policy_str = xmlNodeGetContent(node);
+                       if (!boundary_policy_str) {
+                               ERR("Failed to get map boundary policy node content.");
+                               ret = -LTTNG_ERR_NOMEM;
+                               goto end;
+                       }
+
+                       assert(strcmp((const char *) boundary_policy_str,
+                                              config_boundary_policy_overflow) ==
+                                       0);
+                       boundary_policy = LTTNG_MAP_BOUNDARY_POLICY_OVERFLOW;
+               } else if (strcmp((const char *) node->name,
+                                          config_element_coalesce_hits) == 0) {
+                       assert(!coalesce_hits_str);
+                       coalesce_hits_str = xmlNodeGetContent(node);
+                       if (!coalesce_hits_str) {
+                               ERR("Failed to get map coalesce hits node content.");
+                               ret = -LTTNG_ERR_NOMEM;
+                               goto end;
+                       }
+
+                       ret = parse_bool(coalesce_hits_str, &coalesce_hits);
+                       assert(!ret);
+               } else if (strcmp((const char *) node->name,
+                                          config_element_dimensions) == 0) {
+                       ret = process_dimensions_node(node, &dimension_sizes);
+                       if (ret) {
+                               goto end;
+                       }
+               } else {
+                       assert(false);
+               }
+       }
+
+       assert(name);
+       map_status = lttng_map_create((const char *) name,
+                       lttng_dynamic_array_get_count(&dimension_sizes),
+                       (uint64_t *) dimension_sizes.buffer.data,
+                       handle->domain.type, handle->domain.buf_type, bitness,
+                       boundary_policy, coalesce_hits, &map);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               ERR("Failed to create map.");
+               ret = -LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       error_code = lttng_add_map(handle, map);
+       if (error_code != LTTNG_OK) {
+               ERR("Adding map \"%s\": %s", (const char *) name,
+                               lttng_strerror(error_code));
+               ret = error_code;
+               goto end;
+       }
+
+       // FIXME: disabling the map after creating leaves a window of time
+       // where it is enabled, does it matter?
+       if (!enabled) {
+               ret = lttng_disable_map(handle, (const char *) name);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = 0;
+
+end:
+       xmlFree(name);
+       xmlFree(enabled_str);
+       xmlFree(bitness_str);
+       xmlFree(boundary_policy_str);
+       xmlFree(coalesce_hits_str);
+       lttng_dynamic_array_reset(&dimension_sizes);
+       lttng_map_destroy(map);
+
+       return ret;
+}
+
 static
 int process_domain_node(xmlNodePtr domain_node, const char *session_name)
 {
        int ret;
        struct lttng_domain domain = { 0 };
        struct lttng_handle *handle = NULL;
-       struct lttng_channel *channel = NULL;
        xmlNodePtr channels_node = NULL;
+       xmlNodePtr maps_node = NULL;
        xmlNodePtr trackers_node = NULL;
        xmlNodePtr pid_tracker_node = NULL;
        xmlNodePtr vpid_tracker_node = NULL;
@@ -3094,76 +3391,39 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name)
                }
        }
 
-       if (!channels_node) {
-               goto end;
-       }
-
-       /* create all channels */
-       for (node = xmlFirstElementChild(channels_node); node;
-               node = xmlNextElementSibling(node)) {
-               const enum lttng_domain_type original_domain = domain.type;
-               xmlNodePtr contexts_node = NULL;
-               xmlNodePtr events_node = NULL;
-               xmlNodePtr channel_attr_node;
-
-               /*
-                * Channels of the "agent" types cannot be created directly.
-                * They are meant to be created implicitly through the
-                * activation of events in their domain. However, a user
-                * can override the default channel configuration attributes
-                * by creating the underlying UST channel _before_ enabling
-                * an agent domain event.
-                *
-                * Hence, the channel's type is substituted before the creation
-                * and restored by the time the events are created.
-                */
-               switch (domain.type) {
-               case LTTNG_DOMAIN_JUL:
-               case LTTNG_DOMAIN_LOG4J:
-               case LTTNG_DOMAIN_PYTHON:
-                       domain.type = LTTNG_DOMAIN_UST;
-               default:
-                       break;
-               }
-
-               channel = lttng_channel_create(&domain);
-               if (!channel) {
-                       ret = -1;
-                       goto end;
-               }
+       if (channels_node) {
+               /* create all channels */
+               for (node = xmlFirstElementChild(channels_node); node;
+                       node = xmlNextElementSibling(node)) {
+                       const enum lttng_domain_type original_domain = domain.type;
 
-               for (channel_attr_node = xmlFirstElementChild(node);
-                       channel_attr_node; channel_attr_node =
-                       xmlNextElementSibling(channel_attr_node)) {
-                       ret = process_channel_attr_node(channel_attr_node,
-                               channel, &contexts_node, &events_node);
+                       ret = process_channel_node(node, handle, &domain,
+                                       original_domain);
                        if (ret) {
                                goto end;
                        }
                }
+       }
 
-               ret = lttng_enable_channel(handle, channel);
-               if (ret < 0) {
-                       goto end;
-               }
-
-               /* Restore the original channel domain. */
-               domain.type = original_domain;
-
-               ret = process_events_node(events_node, handle, channel->name);
-               if (ret) {
-                       goto end;
+       /* get the maps node */
+       for (node = xmlFirstElementChild(domain_node); node;
+                       node = xmlNextElementSibling(node)) {
+               if (!strcmp((const char *) node->name, config_element_maps)) {
+                       maps_node = node;
+                       break;
                }
+       }
 
-               ret = process_contexts_node(contexts_node, handle,
-                       channel->name);
-               if (ret) {
-                       goto end;
+       if (maps_node) {
+               /* create all maps */
+               for (node = xmlFirstElementChild(maps_node); node;
+                               node = xmlNextElementSibling(node)) {
+                       ret = process_map_node(node, handle);
+                       if (ret) {
+                               goto end;
+                       }
                }
-
-               lttng_channel_destroy(channel);
        }
-       channel = NULL;
 
        /* get the trackers node */
        for (node = xmlFirstElementChild(domain_node); node;
@@ -3254,7 +3514,6 @@ int process_domain_node(xmlNodePtr domain_node, const char *session_name)
        }
 
 end:
-       lttng_channel_destroy(channel);
        lttng_destroy_handle(handle);
        return ret;
 }
index 986fb2dda175a8df19f3cec1be20264ab92e4052..c8f8ea0fb2b27156485161527b699b8506e24934 100644 (file)
@@ -254,6 +254,48 @@ by its signed 32-bit representation when converted to msec.
        </xs:sequence>
 </xs:complexType>
 
+<xs:complexType name="map_list_type">
+       <xs:sequence>
+               <xs:element name="map" type="map_type" minOccurs="0" maxOccurs="unbounded" />
+       </xs:sequence>
+</xs:complexType>
+
+<xs:complexType name="map_type">
+       <xs:all>
+               <xs:element name="name" type="name_type"/>
+               <xs:element name="enabled" type="xs:boolean" />
+               <xs:element name="bitness" type="bitness_type" />
+               <xs:element name="boundary_policy" type="boundary_policy_type" />
+               <xs:element name="coalesce_hits" type="xs:boolean" />
+               <xs:element name="dimensions" type="dimension_list_type" />
+       </xs:all>
+</xs:complexType>
+
+<xs:simpleType name="bitness_type">
+       <xs:restriction base="xs:integer">
+               <xs:enumeration value="32"/>
+               <xs:enumeration value="64"/>
+       </xs:restriction>
+</xs:simpleType>
+
+<xs:simpleType name="boundary_policy_type">
+       <xs:restriction base="xs:string">
+               <xs:enumeration value="OVERFLOW"/>
+       </xs:restriction>
+</xs:simpleType>
+
+<xs:complexType name="dimension_list_type">
+       <xs:sequence>
+               <xs:element name="dimension" type="dimension_type" maxOccurs="unbounded"/>
+       </xs:sequence>
+</xs:complexType>
+
+<xs:complexType name="dimension_type">
+       <xs:all>
+               <xs:element name="size" type="uint64_type" />
+       </xs:all>
+</xs:complexType>
+
 <xs:complexType name="pid_value_type">
        <xs:choice minOccurs="0">
                <xs:element name="id" type="xs:integer" />
@@ -429,6 +471,7 @@ by its signed 32-bit representation when converted to msec.
                <xs:element name="type" type="domain_type_type"/>
                <xs:element name="buffer_type" type="domain_buffer_type"/>
                <xs:element name="channels" type="channel_list_type" minOccurs="0"/>
+               <xs:element name="maps" type="map_list_type" minOccurs="0"/>
                <xs:element name="process_attr_trackers" type="process_attr_tracker_type" minOccurs="0"/>
                <!-- Support of legacy tracker specification -->
                <xs:element name="trackers" type="trackers_type" minOccurs="0"/>
index e03bee350d0e2c07bf0b7cb56f4463492ba0ec12..66859670a3ccb127b81354cacebaa032ef4a00a8 100644 (file)
@@ -241,6 +241,20 @@ static const char *error_string_array[] = {
        [ ERROR_INDEX(LTTNG_ERR_PROCESS_ATTR_TRACKER_INVALID_TRACKING_POLICY) ] = "Operation does not apply to the process attribute tracker's tracking policy",
        [ ERROR_INDEX(LTTNG_ERR_EVENT_NOTIFIER_GROUP_NOTIFICATION_FD) ] = "Failed to create an event notifier group notification file descriptor",
        [ ERROR_INDEX(LTTNG_ERR_INVALID_CAPTURE_EXPRESSION) ] = "Invalid capture expression",
+       [ ERROR_INDEX(LTTNG_ERR_EVENT_NOTIFIER_REGISTRATION) ] = "Failed to create event notifier",
+       [ ERROR_INDEX(LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING) ] = "Failed to initialize event notifier error accounting",
+       [ ERROR_INDEX(LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING_FULL) ] = "No index available in event notifier error accounting",
+       [ ERROR_INDEX(LTTNG_ERR_INVALID_MAP) ] = "Invalid map",
+       [ ERROR_INDEX(LTTNG_ERR_MAP_NOT_FOUND) ] = "Map name not found",
+       [ ERROR_INDEX(LTTNG_ERR_UST_MAP_ENABLE_FAIL) ]  = "Enable UST map failed",
+       [ ERROR_INDEX(LTTNG_ERR_UST_MAP_DISABLE_FAIL) ]  = "Disable UST map failed",
+       [ ERROR_INDEX(LTTNG_ERR_UST_MAP_NOT_FOUND) ] = "UST map not found",
+       [ ERROR_INDEX(LTTNG_ERR_UST_MAP_EXIST) ] = "UST map already exists",
+       [ ERROR_INDEX(LTTNG_ERR_KERNEL_MAP_ENABLE_FAIL) ]  = "Enable Kernel map failed",
+       [ ERROR_INDEX(LTTNG_ERR_KERNEL_MAP_DISABLE_FAIL) ]  = "Disable Kernel map failed",
+       [ ERROR_INDEX(LTTNG_ERR_KERNEL_MAP_NOT_FOUND) ] = "Kernel map not found",
+       [ ERROR_INDEX(LTTNG_ERR_KERNEL_MAP_EXIST) ] = "Kernel map already exists",
+       [ ERROR_INDEX(LTTNG_ERR_MAP_VALUES_LIST_FAIL) ] = "Listing map values failed",
 
        /* Last element */
        [ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code"
index d8a68a7840429b44bf73679bd3b0abc1b30f6273..c51ec2bd9a316d1946e1900437031cd3a0a30678 100644 (file)
@@ -5,11 +5,12 @@
  *
  */
 
+#include <lttng/condition/condition-internal.h>
 #include <lttng/condition/evaluation-internal.h>
 #include <lttng/condition/buffer-usage-internal.h>
 #include <lttng/condition/session-consumed-size-internal.h>
 #include <lttng/condition/session-rotation-internal.h>
-#include <lttng/condition/event-rule-internal.h>
+#include <lttng/condition/on-event-internal.h>
 #include <common/macros.h>
 #include <common/error.h>
 #include <stdbool.h>
@@ -49,6 +50,7 @@ end:
 
 LTTNG_HIDDEN
 ssize_t lttng_evaluation_create_from_payload(
+               const struct lttng_condition *condition,
                struct lttng_payload_view *src_view,
                struct lttng_evaluation **evaluation)
 {
@@ -115,8 +117,14 @@ ssize_t lttng_evaluation_create_from_payload(
                }
                evaluation_size += ret;
                break;
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
-               ret = lttng_evaluation_event_rule_create_from_payload(&evaluation_view, evaluation);
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
+               assert(condition);
+               assert(condition->type == LTTNG_CONDITION_TYPE_ON_EVENT);
+               ret = lttng_evaluation_event_rule_create_from_payload(
+                               container_of(condition,
+                                               const struct lttng_condition_on_event,
+                                               parent),
+                               &evaluation_view, evaluation);
                if (ret < 0) {
                        goto end;
                }
index 3a5be731b3fffe7c48d1613c538dd996c63dc930..6071bb8dcef5059c088c671a796d2510432df188 100644 (file)
 #include <common/hashtable/hashtable.h>
 #include <common/hashtable/utils.h>
 #include <lttng/event-rule/event-rule-internal.h>
-#include <lttng/event-rule/kprobe-internal.h>
+#include <lttng/event-rule/kernel-function-internal.h>
+#include <lttng/event-rule/kernel-probe-internal.h>
 #include <lttng/event-rule/syscall-internal.h>
 #include <lttng/event-rule/tracepoint-internal.h>
-#include <lttng/event-rule/uprobe-internal.h>
+#include <lttng/event-rule/userspace-probe-internal.h>
 #include <stdbool.h>
 
 enum lttng_event_rule_type lttng_event_rule_get_type(
@@ -41,9 +42,9 @@ enum lttng_domain_type lttng_event_rule_get_domain_type(
                break;
        }
        case LTTNG_EVENT_RULE_TYPE_SYSCALL:
-       case LTTNG_EVENT_RULE_TYPE_KPROBE:
-       case LTTNG_EVENT_RULE_TYPE_KRETPROBE:
-       case LTTNG_EVENT_RULE_TYPE_UPROBE:
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE:
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION:
+       case LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE:
                domain_type = LTTNG_DOMAIN_KERNEL;
                break;
        case LTTNG_EVENT_RULE_TYPE_UNKNOWN:
@@ -172,14 +173,14 @@ ssize_t lttng_event_rule_create_from_payload(
                create_from_payload =
                                lttng_event_rule_tracepoint_create_from_payload;
                break;
-       case LTTNG_EVENT_RULE_TYPE_KPROBE:
-               create_from_payload = lttng_event_rule_kprobe_create_from_payload;
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE:
+               create_from_payload = lttng_event_rule_kernel_probe_create_from_payload;
                break;
-       case LTTNG_EVENT_RULE_TYPE_KRETPROBE:
-               /* TODO */
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION:
+               create_from_payload = lttng_event_rule_kernel_function_create_from_payload;
                break;
-       case LTTNG_EVENT_RULE_TYPE_UPROBE:
-               create_from_payload = lttng_event_rule_uprobe_create_from_payload;
+       case LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE:
+               create_from_payload = lttng_event_rule_userspace_probe_create_from_payload;
                break;
        case LTTNG_EVENT_RULE_TYPE_SYSCALL:
                create_from_payload =
@@ -315,11 +316,11 @@ const char *lttng_event_rule_type_str(enum lttng_event_rule_type type)
                return "tracepoint";
        case LTTNG_EVENT_RULE_TYPE_SYSCALL:
                return "syscall";
-       case LTTNG_EVENT_RULE_TYPE_KPROBE:
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE:
                return "probe";
-       case LTTNG_EVENT_RULE_TYPE_KRETPROBE:
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION:
                return "function";
-       case LTTNG_EVENT_RULE_TYPE_UPROBE:
+       case LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE:
                return "userspace-probe";
        default:
                abort();
diff --git a/src/common/event-rule/kernel-function.c b/src/common/event-rule/kernel-function.c
new file mode 100644 (file)
index 0000000..c5dd619
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <common/credentials.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/payload.h>
+#include <common/payload-view.h>
+#include <common/runas.h>
+#include <common/hashtable/hashtable.h>
+#include <common/hashtable/utils.h>
+#include <ctype.h>
+#include <lttng/constant.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/kernel-function-internal.h>
+#include <lttng/kernel-function.h>
+#include <lttng/kernel-function-internal.h>
+#include <stdio.h>
+
+#define IS_KERNEL_FUNCTION_EVENT_RULE(rule) \
+       (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION)
+
+#if (LTTNG_SYMBOL_NAME_LEN == 256)
+#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
+#endif
+
+static void lttng_event_rule_kernel_function_destroy(struct lttng_event_rule *rule)
+{
+       struct lttng_event_rule_kernel_function *kfunction;
+
+       kfunction = container_of(rule, struct lttng_event_rule_kernel_function, parent);
+
+       lttng_kernel_function_location_destroy(kfunction->location);
+       free(kfunction->name);
+       free(kfunction);
+}
+
+static bool lttng_event_rule_kernel_function_validate(
+               const struct lttng_event_rule *rule)
+{
+       bool valid = false;
+       struct lttng_event_rule_kernel_function *kfunction;
+
+       if (!rule) {
+               goto end;
+       }
+
+       kfunction = container_of(rule, struct lttng_event_rule_kernel_function, parent);
+
+       /* Required field. */
+       if (!kfunction->name) {
+               ERR("Invalid name event rule: a name must be set.");
+               goto end;
+       }
+
+       /* Required field. */
+       if(!kfunction->location) {
+               ERR("Invalid name event rule: a location must be set.");
+               goto end;
+       }
+
+       valid = true;
+end:
+       return valid;
+}
+
+static int lttng_event_rule_kernel_function_serialize(
+               const struct lttng_event_rule *rule,
+               struct lttng_payload *payload)
+{
+       int ret;
+       size_t name_len, header_offset, size_before_location;
+       struct lttng_event_rule_kernel_function *kfunction;
+       struct lttng_event_rule_kernel_function_comm kfunction_comm;
+       struct lttng_event_rule_kernel_function_comm *header;
+
+       if (!rule || !IS_KERNEL_FUNCTION_EVENT_RULE(rule)) {
+               ret = -1;
+               goto end;
+       }
+
+       header_offset = payload->buffer.size;
+
+       DBG("Serializing kfunction event rule.");
+       kfunction = container_of(rule, struct lttng_event_rule_kernel_function, parent);
+
+       name_len = strlen(kfunction->name) + 1;
+       kfunction_comm.name_len = name_len;
+
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, &kfunction_comm, sizeof(kfunction_comm));
+       if (ret) {
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, kfunction->name, name_len);
+       if (ret) {
+               goto end;
+       }
+
+       size_before_location = payload->buffer.size;
+
+       ret = lttng_kernel_function_location_serialize(kfunction->location, payload);
+       if (ret < 0) {
+               goto end;
+       }
+
+       /* Update the header regarding the function size. */
+       header = (struct lttng_event_rule_kernel_function_comm*) (
+                       (char *) payload->buffer.data + header_offset);
+       header->location_len = payload->buffer.size - size_before_location;
+
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static bool lttng_event_rule_kernel_function_is_equal(const struct lttng_event_rule *_a,
+               const struct lttng_event_rule *_b)
+{
+       bool is_equal = false;
+       struct lttng_event_rule_kernel_function *a, *b;
+
+       a = container_of(_a, struct lttng_event_rule_kernel_function, parent);
+       b = container_of(_b, struct lttng_event_rule_kernel_function, parent);
+
+       /* Quick checks */
+       if (!!a->name != !!b->name) {
+               goto end;
+       }
+
+       /* Long check */
+       assert(a->name);
+       assert(b->name);
+       if (strcmp(a->name, b->name)) {
+               goto end;
+       }
+
+       is_equal = lttng_kernel_function_location_is_equal(
+                       a->location, b->location);
+end:
+       return is_equal;
+}
+
+static enum lttng_error_code lttng_event_rule_kernel_function_generate_filter_bytecode(
+               struct lttng_event_rule *rule,
+               const struct lttng_credentials *creds)
+{
+       /* Nothing to do. */
+       return LTTNG_OK;
+}
+
+static const char *lttng_event_rule_kernel_function_get_filter(
+               const struct lttng_event_rule *rule)
+{
+       /* Not supported. */
+       return NULL;
+}
+
+static const struct lttng_bytecode *
+lttng_event_rule_kernel_function_get_filter_bytecode(const struct lttng_event_rule *rule)
+{
+       /* Not supported. */
+       return NULL;
+}
+
+static enum lttng_event_rule_generate_exclusions_status
+lttng_event_rule_kernel_function_generate_exclusions(const struct lttng_event_rule *rule,
+               struct lttng_event_exclusion **exclusions)
+{
+       /* Not supported. */
+       *exclusions = NULL;
+       return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
+}
+
+static unsigned long
+lttng_event_rule_kernel_function_hash(
+               const struct lttng_event_rule *rule)
+{
+       unsigned long hash;
+       struct lttng_event_rule_kernel_function *krule =
+                       container_of(rule, typeof(*krule), parent);
+
+       hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION,
+                       lttng_ht_seed);
+       hash ^= hash_key_str(krule->name, lttng_ht_seed);
+       hash ^= lttng_kernel_function_location_hash(krule->location);
+
+       return hash;
+}
+
+static
+int kernel_function_set_location(
+               struct lttng_event_rule_kernel_function *kfunction,
+               const struct lttng_kernel_function_location *location)
+{
+       int ret;
+       struct lttng_kernel_function_location *location_copy = NULL;
+
+       if (!kfunction || !location || kfunction->location) {
+               ret = -1;
+               goto end;
+       }
+
+       location_copy = lttng_kernel_function_location_copy(location);
+       if (!location_copy) {
+               ret = -1;
+               goto end;
+       }
+
+       kfunction->location = location_copy;
+       location_copy = NULL;
+       ret = 0;
+end:
+       lttng_kernel_function_location_destroy(location_copy);
+       return ret;
+}
+
+struct lttng_event_rule *lttng_event_rule_kernel_function_create(
+               const struct lttng_kernel_function_location *location)
+{
+       struct lttng_event_rule *rule = NULL;
+       struct lttng_event_rule_kernel_function *krule;
+
+       krule = zmalloc(sizeof(struct lttng_event_rule_kernel_function));
+       if (!krule) {
+               goto end;
+       }
+
+       rule = &krule->parent;
+       lttng_event_rule_init(&krule->parent, LTTNG_EVENT_RULE_TYPE_KERNEL_FUNCTION);
+       krule->parent.validate = lttng_event_rule_kernel_function_validate;
+       krule->parent.serialize = lttng_event_rule_kernel_function_serialize;
+       krule->parent.equal = lttng_event_rule_kernel_function_is_equal;
+       krule->parent.destroy = lttng_event_rule_kernel_function_destroy;
+       krule->parent.generate_filter_bytecode =
+                       lttng_event_rule_kernel_function_generate_filter_bytecode;
+       krule->parent.get_filter = lttng_event_rule_kernel_function_get_filter;
+       krule->parent.get_filter_bytecode =
+                       lttng_event_rule_kernel_function_get_filter_bytecode;
+       krule->parent.generate_exclusions =
+                       lttng_event_rule_kernel_function_generate_exclusions;
+       krule->parent.hash = lttng_event_rule_kernel_function_hash;
+
+       if (kernel_function_set_location(krule, location)) {
+               lttng_event_rule_destroy(rule);
+               rule = NULL;
+       }
+
+end:
+       return rule;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_kernel_function_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_event_rule **_event_rule)
+{
+       ssize_t ret, offset = 0;
+       enum lttng_event_rule_status status;
+       const struct lttng_event_rule_kernel_function_comm *kfunction_comm;
+       const char *name;
+       struct lttng_buffer_view current_buffer_view;
+       struct lttng_event_rule *rule = NULL;
+       struct lttng_kernel_function_location *location = NULL;
+
+       if (!_event_rule) {
+               ret = -1;
+               goto end;
+       }
+
+       current_buffer_view = lttng_buffer_view_from_view(
+                       &view->buffer, offset, sizeof(*kfunction_comm));
+       if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
+               ERR("Failed to initialize from malformed event rule kfunction: buffer too short to contain header.");
+               ret = -1;
+               goto end;
+       }
+
+       kfunction_comm = (typeof(kfunction_comm)) current_buffer_view.data;
+
+       /* Skip to payload */
+       offset += current_buffer_view.size;
+
+       {
+               /* Map the name. */
+               struct lttng_payload_view current_payload_view =
+                               lttng_payload_view_from_view(view, offset,
+                                               kfunction_comm->name_len);
+
+               if (!lttng_payload_view_is_valid(&current_payload_view)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               name = current_payload_view.buffer.data;
+               if (!lttng_buffer_view_contains_string(
+                               &current_payload_view.buffer, name,
+                               kfunction_comm->name_len)) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /* Skip after the name. */
+       offset += kfunction_comm->name_len;
+
+       /* Map the kernel function location. */
+       {
+               struct lttng_payload_view current_payload_view =
+                               lttng_payload_view_from_view(view, offset,
+                                               kfunction_comm->location_len);
+
+               if (!lttng_payload_view_is_valid(&current_payload_view)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = lttng_kernel_function_location_create_from_payload(
+                               &current_payload_view, &location);
+               if (ret < 0) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       if (ret != kfunction_comm->location_len) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Skip after the location */
+       offset += kfunction_comm->location_len;
+
+       rule = lttng_event_rule_kernel_function_create(location);
+       if (!rule) {
+               ERR("Failed to create event rule kfunction.");
+               ret = -1;
+               goto end;
+       }
+
+       status = lttng_event_rule_kernel_function_set_event_name(rule, name);
+       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+               ERR("Failed to set event rule kfunction name.");
+               ret = -1;
+               goto end;
+       }
+
+       *_event_rule = rule;
+       rule = NULL;
+       ret = offset;
+end:
+       lttng_kernel_function_location_destroy(location);
+       lttng_event_rule_destroy(rule);
+       return ret;
+}
+
+enum lttng_event_rule_status lttng_event_rule_kernel_function_get_location(
+               const struct lttng_event_rule *rule,
+               const struct lttng_kernel_function_location **location)
+{
+       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
+       struct lttng_event_rule_kernel_function *kfunction;
+
+       if (!rule || !IS_KERNEL_FUNCTION_EVENT_RULE(rule) || !location) {
+               status = LTTNG_EVENT_RULE_STATUS_INVALID;
+               goto end;
+       }
+
+       kfunction = container_of(rule, struct lttng_event_rule_kernel_function, parent);
+       *location = kfunction->location;
+
+       if (!*location) {
+               status = LTTNG_EVENT_RULE_STATUS_UNSET;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+enum lttng_event_rule_status lttng_event_rule_kernel_function_set_event_name(
+               struct lttng_event_rule *rule, const char *name)
+{
+       char *name_copy = NULL;
+       struct lttng_event_rule_kernel_function *kfunction;
+       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
+
+       if (!rule || !IS_KERNEL_FUNCTION_EVENT_RULE(rule) || !name ||
+                       strlen(name) == 0) {
+               status = LTTNG_EVENT_RULE_STATUS_INVALID;
+               goto end;
+       }
+
+       kfunction = container_of(rule, struct lttng_event_rule_kernel_function, parent);
+       name_copy = strdup(name);
+       if (!name_copy) {
+               status = LTTNG_EVENT_RULE_STATUS_ERROR;
+               goto end;
+       }
+
+       free(kfunction->name);
+
+       kfunction->name = name_copy;
+       name_copy = NULL;
+end:
+       return status;
+}
+
+enum lttng_event_rule_status lttng_event_rule_kernel_function_get_event_name(
+               const struct lttng_event_rule *rule, const char **name)
+{
+       struct lttng_event_rule_kernel_function *kfunction;
+       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
+
+       if (!rule || !IS_KERNEL_FUNCTION_EVENT_RULE(rule) || !name) {
+               status = LTTNG_EVENT_RULE_STATUS_INVALID;
+               goto end;
+       }
+
+       kfunction = container_of(rule, struct lttng_event_rule_kernel_function, parent);
+       if (!kfunction->name) {
+               status = LTTNG_EVENT_RULE_STATUS_UNSET;
+               goto end;
+       }
+
+       *name = kfunction->name;
+end:
+       return status;
+}
diff --git a/src/common/event-rule/kernel-probe.c b/src/common/event-rule/kernel-probe.c
new file mode 100644 (file)
index 0000000..f53e924
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <common/credentials.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/payload.h>
+#include <common/payload-view.h>
+#include <common/runas.h>
+#include <common/hashtable/hashtable.h>
+#include <common/hashtable/utils.h>
+#include <ctype.h>
+#include <lttng/constant.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/kernel-probe-internal.h>
+#include <lttng/kernel-probe.h>
+#include <lttng/kernel-probe-internal.h>
+#include <stdio.h>
+
+#define IS_KPROBE_EVENT_RULE(rule) \
+       (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE)
+
+#if (LTTNG_SYMBOL_NAME_LEN == 256)
+#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
+#endif
+
+static void lttng_event_rule_kernel_probe_destroy(struct lttng_event_rule *rule)
+{
+       struct lttng_event_rule_kernel_probe *kprobe;
+
+       kprobe = container_of(rule, struct lttng_event_rule_kernel_probe, parent);
+
+       lttng_kernel_probe_location_destroy(kprobe->location);
+       free(kprobe->name);
+       free(kprobe);
+}
+
+static bool lttng_event_rule_kernel_probe_validate(
+               const struct lttng_event_rule *rule)
+{
+       bool valid = false;
+       struct lttng_event_rule_kernel_probe *kprobe;
+
+       if (!rule) {
+               goto end;
+       }
+
+       kprobe = container_of(rule, struct lttng_event_rule_kernel_probe, parent);
+
+       /* Required field. */
+       if (!kprobe->name) {
+               ERR("Invalid name event rule: a name must be set.");
+               goto end;
+       }
+
+       /* Required field. */
+       if(!kprobe->location) {
+               ERR("Invalid name event rule: a location must be set.");
+               goto end;
+       }
+
+       valid = true;
+end:
+       return valid;
+}
+
+static int lttng_event_rule_kernel_probe_serialize(
+               const struct lttng_event_rule *rule,
+               struct lttng_payload *payload)
+{
+       int ret;
+       size_t name_len, header_offset, size_before_location;
+       struct lttng_event_rule_kernel_probe *kprobe;
+       struct lttng_event_rule_kernel_probe_comm kprobe_comm;
+       struct lttng_event_rule_kernel_probe_comm *header;
+
+       if (!rule || !IS_KPROBE_EVENT_RULE(rule)) {
+               ret = -1;
+               goto end;
+       }
+
+       header_offset = payload->buffer.size;
+
+       DBG("Serializing kprobe event rule.");
+       kprobe = container_of(rule, struct lttng_event_rule_kernel_probe, parent);
+
+       name_len = strlen(kprobe->name) + 1;
+       kprobe_comm.name_len = name_len;
+
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, &kprobe_comm, sizeof(kprobe_comm));
+       if (ret) {
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, kprobe->name, name_len);
+       if (ret) {
+               goto end;
+       }
+
+       size_before_location = payload->buffer.size;
+
+       ret = lttng_kernel_probe_location_serialize(kprobe->location, payload);
+       if (ret < 0) {
+               goto end;
+       }
+
+       /* Update the header regarding the probe size. */
+       header = (struct lttng_event_rule_kernel_probe_comm*) (
+                       (char *) payload->buffer.data + header_offset);
+       header->location_len = payload->buffer.size - size_before_location;
+
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static bool lttng_event_rule_kernel_probe_is_equal(const struct lttng_event_rule *_a,
+               const struct lttng_event_rule *_b)
+{
+       bool is_equal = false;
+       struct lttng_event_rule_kernel_probe *a, *b;
+
+       a = container_of(_a, struct lttng_event_rule_kernel_probe, parent);
+       b = container_of(_b, struct lttng_event_rule_kernel_probe, parent);
+
+       /* Quick checks */
+       if (!!a->name != !!b->name) {
+               goto end;
+       }
+
+       /* Long check */
+       assert(a->name);
+       assert(b->name);
+       if (strcmp(a->name, b->name)) {
+               goto end;
+       }
+
+       is_equal = lttng_kernel_probe_location_is_equal(
+                       a->location, b->location);
+end:
+       return is_equal;
+}
+
+static enum lttng_error_code lttng_event_rule_kernel_probe_generate_filter_bytecode(
+               struct lttng_event_rule *rule,
+               const struct lttng_credentials *creds)
+{
+       /* Nothing to do. */
+       return LTTNG_OK;
+}
+
+static const char *lttng_event_rule_kernel_probe_get_filter(
+               const struct lttng_event_rule *rule)
+{
+       /* Not supported. */
+       return NULL;
+}
+
+static const struct lttng_bytecode *
+lttng_event_rule_kernel_probe_get_filter_bytecode(const struct lttng_event_rule *rule)
+{
+       /* Not supported. */
+       return NULL;
+}
+
+static enum lttng_event_rule_generate_exclusions_status
+lttng_event_rule_kernel_probe_generate_exclusions(const struct lttng_event_rule *rule,
+               struct lttng_event_exclusion **exclusions)
+{
+       /* Not supported. */
+       *exclusions = NULL;
+       return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
+}
+
+static unsigned long
+lttng_event_rule_kernel_probe_hash(
+               const struct lttng_event_rule *rule)
+{
+       unsigned long hash;
+       struct lttng_event_rule_kernel_probe *krule =
+                       container_of(rule, typeof(*krule), parent);
+
+       hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE,
+                       lttng_ht_seed);
+       hash ^= hash_key_str(krule->name, lttng_ht_seed);
+       hash ^= lttng_kernel_probe_location_hash(krule->location);
+
+       return hash;
+}
+
+static
+int kernel_probe_set_location(
+               struct lttng_event_rule_kernel_probe *kprobe,
+               const struct lttng_kernel_probe_location *location)
+{
+       int ret;
+       struct lttng_kernel_probe_location *location_copy = NULL;
+
+       if (!kprobe || !location || kprobe->location) {
+               ret = -1;
+               goto end;
+       }
+
+       location_copy = lttng_kernel_probe_location_copy(location);
+       if (!location_copy) {
+               ret = -1;
+               goto end;
+       }
+
+       kprobe->location = location_copy;
+       location_copy = NULL;
+       ret = 0;
+end:
+       lttng_kernel_probe_location_destroy(location_copy);
+       return ret;
+}
+
+struct lttng_event_rule *lttng_event_rule_kernel_probe_create(
+               const struct lttng_kernel_probe_location *location)
+{
+       struct lttng_event_rule *rule = NULL;
+       struct lttng_event_rule_kernel_probe *krule;
+
+       krule = zmalloc(sizeof(struct lttng_event_rule_kernel_probe));
+       if (!krule) {
+               goto end;
+       }
+
+       rule = &krule->parent;
+       lttng_event_rule_init(&krule->parent, LTTNG_EVENT_RULE_TYPE_KERNEL_PROBE);
+       krule->parent.validate = lttng_event_rule_kernel_probe_validate;
+       krule->parent.serialize = lttng_event_rule_kernel_probe_serialize;
+       krule->parent.equal = lttng_event_rule_kernel_probe_is_equal;
+       krule->parent.destroy = lttng_event_rule_kernel_probe_destroy;
+       krule->parent.generate_filter_bytecode =
+                       lttng_event_rule_kernel_probe_generate_filter_bytecode;
+       krule->parent.get_filter = lttng_event_rule_kernel_probe_get_filter;
+       krule->parent.get_filter_bytecode =
+                       lttng_event_rule_kernel_probe_get_filter_bytecode;
+       krule->parent.generate_exclusions =
+                       lttng_event_rule_kernel_probe_generate_exclusions;
+       krule->parent.hash = lttng_event_rule_kernel_probe_hash;
+
+       if (kernel_probe_set_location(krule, location)) {
+               lttng_event_rule_destroy(rule);
+               rule = NULL;
+       }
+
+end:
+       return rule;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_kernel_probe_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_event_rule **_event_rule)
+{
+       ssize_t ret, offset = 0;
+       enum lttng_event_rule_status status;
+       const struct lttng_event_rule_kernel_probe_comm *kprobe_comm;
+       const char *name;
+       struct lttng_buffer_view current_buffer_view;
+       struct lttng_event_rule *rule = NULL;
+       struct lttng_kernel_probe_location *location = NULL;
+
+       if (!_event_rule) {
+               ret = -1;
+               goto end;
+       }
+
+       current_buffer_view = lttng_buffer_view_from_view(
+                       &view->buffer, offset, sizeof(*kprobe_comm));
+       if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
+               ERR("Failed to initialize from malformed event rule kprobe: buffer too short to contain header.");
+               ret = -1;
+               goto end;
+       }
+
+       kprobe_comm = (typeof(kprobe_comm)) current_buffer_view.data;
+
+       /* Skip to payload */
+       offset += current_buffer_view.size;
+
+       {
+               /* Map the name. */
+               struct lttng_payload_view current_payload_view =
+                               lttng_payload_view_from_view(view, offset,
+                                               kprobe_comm->name_len);
+
+               if (!lttng_payload_view_is_valid(&current_payload_view)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               name = current_payload_view.buffer.data;
+               if (!lttng_buffer_view_contains_string(
+                               &current_payload_view.buffer, name,
+                               kprobe_comm->name_len)) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /* Skip after the name. */
+       offset += kprobe_comm->name_len;
+
+       /* Map the kernel probe location. */
+       {
+               struct lttng_payload_view current_payload_view =
+                               lttng_payload_view_from_view(view, offset,
+                                               kprobe_comm->location_len);
+
+               if (!lttng_payload_view_is_valid(&current_payload_view)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = lttng_kernel_probe_location_create_from_payload(
+                               &current_payload_view, &location);
+               if (ret < 0) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       if (ret != kprobe_comm->location_len) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Skip after the location */
+       offset += kprobe_comm->location_len;
+
+       rule = lttng_event_rule_kernel_probe_create(location);
+       if (!rule) {
+               ERR("Failed to create event rule kprobe.");
+               ret = -1;
+               goto end;
+       }
+
+       status = lttng_event_rule_kernel_probe_set_event_name(rule, name);
+       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+               ERR("Failed to set event rule kprobe name.");
+               ret = -1;
+               goto end;
+       }
+
+       *_event_rule = rule;
+       rule = NULL;
+       ret = offset;
+end:
+       lttng_kernel_probe_location_destroy(location);
+       lttng_event_rule_destroy(rule);
+       return ret;
+}
+
+enum lttng_event_rule_status lttng_event_rule_kernel_probe_get_location(
+               const struct lttng_event_rule *rule,
+               const struct lttng_kernel_probe_location **location)
+{
+       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
+       struct lttng_event_rule_kernel_probe *kprobe;
+
+       if (!rule || !IS_KPROBE_EVENT_RULE(rule) || !location) {
+               status = LTTNG_EVENT_RULE_STATUS_INVALID;
+               goto end;
+       }
+
+       kprobe = container_of(rule, struct lttng_event_rule_kernel_probe, parent);
+       *location = kprobe->location;
+
+       if (!*location) {
+               status = LTTNG_EVENT_RULE_STATUS_UNSET;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+enum lttng_event_rule_status lttng_event_rule_kernel_probe_set_event_name(
+               struct lttng_event_rule *rule, const char *name)
+{
+       char *name_copy = NULL;
+       struct lttng_event_rule_kernel_probe *kprobe;
+       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
+
+       if (!rule || !IS_KPROBE_EVENT_RULE(rule) || !name ||
+                       strlen(name) == 0) {
+               status = LTTNG_EVENT_RULE_STATUS_INVALID;
+               goto end;
+       }
+
+       kprobe = container_of(rule, struct lttng_event_rule_kernel_probe, parent);
+       name_copy = strdup(name);
+       if (!name_copy) {
+               status = LTTNG_EVENT_RULE_STATUS_ERROR;
+               goto end;
+       }
+
+       free(kprobe->name);
+
+       kprobe->name = name_copy;
+       name_copy = NULL;
+end:
+       return status;
+}
+
+enum lttng_event_rule_status lttng_event_rule_kernel_probe_get_event_name(
+               const struct lttng_event_rule *rule, const char **name)
+{
+       struct lttng_event_rule_kernel_probe *kprobe;
+       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
+
+       if (!rule || !IS_KPROBE_EVENT_RULE(rule) || !name) {
+               status = LTTNG_EVENT_RULE_STATUS_INVALID;
+               goto end;
+       }
+
+       kprobe = container_of(rule, struct lttng_event_rule_kernel_probe, parent);
+       if (!kprobe->name) {
+               status = LTTNG_EVENT_RULE_STATUS_UNSET;
+               goto end;
+       }
+
+       *name = kprobe->name;
+end:
+       return status;
+}
diff --git a/src/common/event-rule/kprobe.c b/src/common/event-rule/kprobe.c
deleted file mode 100644 (file)
index 12e6010..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <assert.h>
-#include <common/credentials.h>
-#include <common/error.h>
-#include <common/macros.h>
-#include <common/payload.h>
-#include <common/payload-view.h>
-#include <common/runas.h>
-#include <common/hashtable/hashtable.h>
-#include <common/hashtable/utils.h>
-#include <ctype.h>
-#include <lttng/constant.h>
-#include <lttng/event-rule/event-rule-internal.h>
-#include <lttng/event-rule/kprobe-internal.h>
-#include <lttng/kernel-probe.h>
-#include <lttng/kernel-probe-internal.h>
-#include <stdio.h>
-
-#define IS_KPROBE_EVENT_RULE(rule) \
-       (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_KPROBE)
-
-#if (LTTNG_SYMBOL_NAME_LEN == 256)
-#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
-#endif
-
-static void lttng_event_rule_kprobe_destroy(struct lttng_event_rule *rule)
-{
-       struct lttng_event_rule_kprobe *kprobe;
-
-       kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
-
-       lttng_kernel_probe_location_destroy(kprobe->location);
-       free(kprobe->name);
-       free(kprobe);
-}
-
-static bool lttng_event_rule_kprobe_validate(
-               const struct lttng_event_rule *rule)
-{
-       bool valid = false;
-       struct lttng_event_rule_kprobe *kprobe;
-
-       if (!rule) {
-               goto end;
-       }
-
-       kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
-
-       /* Required field. */
-       if (!kprobe->name) {
-               ERR("Invalid name event rule: a name must be set.");
-               goto end;
-       }
-
-       /* Required field. */
-       if(!kprobe->location) {
-               ERR("Invalid name event rule: a location must be set.");
-               goto end;
-       }
-
-       valid = true;
-end:
-       return valid;
-}
-
-static int lttng_event_rule_kprobe_serialize(
-               const struct lttng_event_rule *rule,
-               struct lttng_payload *payload)
-{
-       int ret;
-       size_t name_len, header_offset, size_before_location;
-       struct lttng_event_rule_kprobe *kprobe;
-       struct lttng_event_rule_kprobe_comm kprobe_comm;
-       struct lttng_event_rule_kprobe_comm *header;
-
-       if (!rule || !IS_KPROBE_EVENT_RULE(rule)) {
-               ret = -1;
-               goto end;
-       }
-
-       header_offset = payload->buffer.size;
-
-       DBG("Serializing kprobe event rule.");
-       kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
-
-       name_len = strlen(kprobe->name) + 1;
-       kprobe_comm.name_len = name_len;
-
-       ret = lttng_dynamic_buffer_append(
-                       &payload->buffer, &kprobe_comm, sizeof(kprobe_comm));
-       if (ret) {
-               goto end;
-       }
-
-       ret = lttng_dynamic_buffer_append(&payload->buffer, kprobe->name, name_len);
-       if (ret) {
-               goto end;
-       }
-
-       size_before_location = payload->buffer.size;
-
-       ret = lttng_kernel_probe_location_serialize(kprobe->location, payload);
-       if (ret < 0) {
-               goto end;
-       }
-
-       /* Update the header regarding the probe size. */
-       header = (struct lttng_event_rule_kprobe_comm*) (
-                       (char *) payload->buffer.data + header_offset);
-       header->location_len = payload->buffer.size - size_before_location;
-
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static bool lttng_event_rule_kprobe_is_equal(const struct lttng_event_rule *_a,
-               const struct lttng_event_rule *_b)
-{
-       bool is_equal = false;
-       struct lttng_event_rule_kprobe *a, *b;
-
-       a = container_of(_a, struct lttng_event_rule_kprobe, parent);
-       b = container_of(_b, struct lttng_event_rule_kprobe, parent);
-
-       /* Quick checks */
-       if (!!a->name != !!b->name) {
-               goto end;
-       }
-
-       /* Long check */
-       assert(a->name);
-       assert(b->name);
-       if (strcmp(a->name, b->name)) {
-               goto end;
-       }
-
-       is_equal = lttng_kernel_probe_location_is_equal(
-                       a->location, b->location);
-end:
-       return is_equal;
-}
-
-static enum lttng_error_code lttng_event_rule_kprobe_generate_filter_bytecode(
-               struct lttng_event_rule *rule,
-               const struct lttng_credentials *creds)
-{
-       /* Nothing to do. */
-       return LTTNG_OK;
-}
-
-static const char *lttng_event_rule_kprobe_get_filter(
-               const struct lttng_event_rule *rule)
-{
-       /* Not supported. */
-       return NULL;
-}
-
-static const struct lttng_bytecode *
-lttng_event_rule_kprobe_get_filter_bytecode(const struct lttng_event_rule *rule)
-{
-       /* Not supported. */
-       return NULL;
-}
-
-static enum lttng_event_rule_generate_exclusions_status
-lttng_event_rule_kprobe_generate_exclusions(const struct lttng_event_rule *rule,
-               struct lttng_event_exclusion **exclusions)
-{
-       /* Not supported. */
-       *exclusions = NULL;
-       return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
-}
-
-static unsigned long
-lttng_event_rule_kprobe_hash(
-               const struct lttng_event_rule *rule)
-{
-       unsigned long hash;
-       struct lttng_event_rule_kprobe *krule =
-                       container_of(rule, typeof(*krule), parent);
-
-       hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_KPROBE,
-                       lttng_ht_seed);
-       hash ^= hash_key_str(krule->name, lttng_ht_seed);
-       hash ^= lttng_kernel_probe_location_hash(krule->location);
-
-       return hash;
-}
-
-struct lttng_event_rule *lttng_event_rule_kprobe_create(void)
-{
-       struct lttng_event_rule *rule = NULL;
-       struct lttng_event_rule_kprobe *krule;
-
-       krule = zmalloc(sizeof(struct lttng_event_rule_kprobe));
-       if (!krule) {
-               goto end;
-       }
-
-       rule = &krule->parent;
-       lttng_event_rule_init(&krule->parent, LTTNG_EVENT_RULE_TYPE_KPROBE);
-       krule->parent.validate = lttng_event_rule_kprobe_validate;
-       krule->parent.serialize = lttng_event_rule_kprobe_serialize;
-       krule->parent.equal = lttng_event_rule_kprobe_is_equal;
-       krule->parent.destroy = lttng_event_rule_kprobe_destroy;
-       krule->parent.generate_filter_bytecode =
-                       lttng_event_rule_kprobe_generate_filter_bytecode;
-       krule->parent.get_filter = lttng_event_rule_kprobe_get_filter;
-       krule->parent.get_filter_bytecode =
-                       lttng_event_rule_kprobe_get_filter_bytecode;
-       krule->parent.generate_exclusions =
-                       lttng_event_rule_kprobe_generate_exclusions;
-       krule->parent.hash = lttng_event_rule_kprobe_hash;
-end:
-       return rule;
-}
-
-LTTNG_HIDDEN
-ssize_t lttng_event_rule_kprobe_create_from_payload(
-               struct lttng_payload_view *view,
-               struct lttng_event_rule **_event_rule)
-{
-       ssize_t ret, offset = 0;
-       enum lttng_event_rule_status status;
-       const struct lttng_event_rule_kprobe_comm *kprobe_comm;
-       const char *name;
-       struct lttng_buffer_view current_buffer_view;
-       struct lttng_event_rule *rule = NULL;
-       struct lttng_event_rule_kprobe *kprobe = NULL;
-       struct lttng_kernel_probe_location *location;
-
-       if (!_event_rule) {
-               ret = -1;
-               goto end;
-       }
-
-       current_buffer_view = lttng_buffer_view_from_view(
-                       &view->buffer, offset, sizeof(*kprobe_comm));
-       if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
-               ERR("Failed to initialize from malformed event rule kprobe: buffer too short to contain header.");
-               ret = -1;
-               goto end;
-       }
-
-       kprobe_comm = (typeof(kprobe_comm)) current_buffer_view.data;
-
-       rule = lttng_event_rule_kprobe_create();
-       if (!rule) {
-               ERR("Failed to create event rule kprobe.");
-               ret = -1;
-               goto end;
-       }
-
-       kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
-
-       /* Skip to payload */
-       offset += current_buffer_view.size;
-
-       {
-               /* Map the name. */
-               struct lttng_payload_view current_payload_view =
-                               lttng_payload_view_from_view(view, offset,
-                                               kprobe_comm->name_len);
-
-               if (!lttng_payload_view_is_valid(&current_payload_view)) {
-                       ret = -1;
-                       goto end;
-               }
-
-               name = current_payload_view.buffer.data;
-               if (!lttng_buffer_view_contains_string(
-                               &current_payload_view.buffer, name,
-                               kprobe_comm->name_len)) {
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /* Skip after the name. */
-       offset += kprobe_comm->name_len;
-
-       /* Map the kernel probe location. */
-       {
-               struct lttng_payload_view current_payload_view =
-                               lttng_payload_view_from_view(view, offset,
-                                               kprobe_comm->location_len);
-
-               if (!lttng_payload_view_is_valid(&current_payload_view)) {
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = lttng_kernel_probe_location_create_from_payload(
-                               &current_payload_view, &location);
-               if (ret < 0) {
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       if (ret != kprobe_comm->location_len) {
-               ret = -1;
-               goto end;
-       }
-
-       kprobe->location = location;
-
-       /* Skip after the location */
-       offset += kprobe_comm->location_len;
-
-       status = lttng_event_rule_kprobe_set_name(rule, name);
-       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
-               ERR("Failed to set event rule kprobe name.");
-               ret = -1;
-               goto end;
-       }
-
-       *_event_rule = rule;
-       rule = NULL;
-       ret = offset;
-end:
-       lttng_event_rule_destroy(rule);
-       return ret;
-}
-
-enum lttng_event_rule_status lttng_event_rule_kprobe_set_location(
-               struct lttng_event_rule *rule,
-               const struct lttng_kernel_probe_location *location)
-{
-       struct lttng_kernel_probe_location *location_copy = NULL;
-       struct lttng_event_rule_kprobe *kprobe;
-       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
-
-       if (!rule || !IS_KPROBE_EVENT_RULE(rule) || !location) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
-               goto end;
-       }
-
-       kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
-       location_copy = lttng_kernel_probe_location_copy(location);
-       if (!location_copy) {
-               status = LTTNG_EVENT_RULE_STATUS_ERROR;
-               goto end;
-       }
-
-       if (kprobe->location) {
-               lttng_kernel_probe_location_destroy(kprobe->location);
-       }
-
-       kprobe->location = location_copy;
-       location_copy = NULL;
-end:
-       lttng_kernel_probe_location_destroy(location_copy);
-       return status;
-}
-
-enum lttng_event_rule_status lttng_event_rule_kprobe_get_location(
-               const struct lttng_event_rule *rule,
-               const struct lttng_kernel_probe_location **location)
-{
-       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
-       struct lttng_event_rule_kprobe *kprobe;
-
-       if (!rule || !IS_KPROBE_EVENT_RULE(rule) || !location) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
-               goto end;
-       }
-
-       kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
-       *location = kprobe->location;
-
-       if (!*location) {
-               status = LTTNG_EVENT_RULE_STATUS_UNSET;
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-enum lttng_event_rule_status lttng_event_rule_kprobe_set_name(
-               struct lttng_event_rule *rule, const char *name)
-{
-       char *name_copy = NULL;
-       struct lttng_event_rule_kprobe *kprobe;
-       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
-
-       if (!rule || !IS_KPROBE_EVENT_RULE(rule) || !name ||
-                       strlen(name) == 0) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
-               goto end;
-       }
-
-       kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
-       name_copy = strdup(name);
-       if (!name_copy) {
-               status = LTTNG_EVENT_RULE_STATUS_ERROR;
-               goto end;
-       }
-
-       free(kprobe->name);
-
-       kprobe->name = name_copy;
-       name_copy = NULL;
-end:
-       return status;
-}
-
-enum lttng_event_rule_status lttng_event_rule_kprobe_get_name(
-               const struct lttng_event_rule *rule, const char **name)
-{
-       struct lttng_event_rule_kprobe *kprobe;
-       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
-
-       if (!rule || !IS_KPROBE_EVENT_RULE(rule) || !name) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
-               goto end;
-       }
-
-       kprobe = container_of(rule, struct lttng_event_rule_kprobe, parent);
-       if (!kprobe->name) {
-               status = LTTNG_EVENT_RULE_STATUS_UNSET;
-               goto end;
-       }
-
-       *name = kprobe->name;
-end:
-       return status;
-}
index b1b556aba3aa6bf5b7dcc45b65d0e408a2a7f832..22353028fc4c20e703287e7c19a3a93289bbaafd 100644 (file)
@@ -249,6 +249,7 @@ struct lttng_event_rule *lttng_event_rule_syscall_create(void)
 {
        struct lttng_event_rule *rule = NULL;
        struct lttng_event_rule_syscall *syscall_rule;
+       enum lttng_event_rule_status status;
 
        syscall_rule = zmalloc(sizeof(struct lttng_event_rule_syscall));
        if (!syscall_rule) {
@@ -271,6 +272,14 @@ struct lttng_event_rule *lttng_event_rule_syscall_create(void)
        syscall_rule->parent.generate_exclusions =
                        lttng_event_rule_syscall_generate_exclusions;
        syscall_rule->parent.hash = lttng_event_rule_syscall_hash;
+
+       /* Default pattern is '*' */
+       status = lttng_event_rule_syscall_set_pattern(rule, "*");
+       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+               lttng_event_rule_destroy(rule);
+               rule = NULL;
+       }
+
 end:
        return rule;
 }
index c8111a3725b5f236da76dab52117b3646a2cee71..c3bac05c29504730176e319e98b34bd80b0deff8 100644 (file)
@@ -9,6 +9,7 @@
 #include <common/credentials.h>
 #include <common/error.h>
 #include <common/macros.h>
+#include <common/optional.h>
 #include <common/payload.h>
 #include <common/payload-view.h>
 #include <common/runas.h>
@@ -16,6 +17,7 @@
 #include <common/hashtable/utils.h>
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/event-rule/tracepoint-internal.h>
+#include <lttng/log-level-rule.h>
 #include <lttng/event.h>
 
 #define IS_TRACEPOINT_EVENT_RULE(rule) \
@@ -75,18 +77,22 @@ static int lttng_event_rule_tracepoint_serialize(
                struct lttng_payload *payload)
 {
        int ret, i;
-       size_t pattern_len, filter_expression_len, exclusions_len;
+       size_t pattern_len, filter_expression_len, exclusions_len, header_offset;
+       size_t size_before_log_level_rule;
        struct lttng_event_rule_tracepoint *tracepoint;
        struct lttng_event_rule_tracepoint_comm tracepoint_comm;
        enum lttng_event_rule_status status;
        unsigned int exclusion_count;
        size_t exclusions_appended_len = 0;
+       struct lttng_event_rule_tracepoint_comm *header;
 
        if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
                ret = -1;
                goto end;
        }
 
+       header_offset = payload->buffer.size;
+
        DBG("Serializing tracepoint event rule.");
        tracepoint = container_of(
                        rule, struct lttng_event_rule_tracepoint, parent);
@@ -118,8 +124,6 @@ static int lttng_event_rule_tracepoint_serialize(
        }
 
        tracepoint_comm.domain_type = (int8_t) tracepoint->domain;
-       tracepoint_comm.loglevel_type = (int8_t) tracepoint->loglevel.type;
-       tracepoint_comm.loglevel_value = tracepoint->loglevel.value;
        tracepoint_comm.pattern_len = pattern_len;
        tracepoint_comm.filter_expression_len = filter_expression_len;
        tracepoint_comm.exclusions_count = exclusion_count;
@@ -143,6 +147,16 @@ static int lttng_event_rule_tracepoint_serialize(
                goto end;
        }
 
+       size_before_log_level_rule = payload->buffer.size;
+
+       ret = lttng_log_level_rule_serialize(tracepoint->log_level_rule, payload);
+       if (ret < 0) {
+               goto end;
+       }
+
+       header = (typeof(header)) ((char *) payload->buffer.data + header_offset);
+       header->log_level_rule_len = payload->buffer.size - size_before_log_level_rule;
+
        for (i = 0; i < exclusion_count; i++) {
                size_t len;
                const char *exclusion;
@@ -224,11 +238,7 @@ static bool lttng_event_rule_tracepoint_is_equal(
                goto end;
        }
 
-       if (a->loglevel.type != b->loglevel.type) {
-               goto end;
-       }
-
-       if (a->loglevel.value != b->loglevel.value) {
+       if (!lttng_log_level_rule_is_equal(a->log_level_rule, b->log_level_rule)) {
                goto end;
        }
 
@@ -266,7 +276,7 @@ static int generate_agent_filter(
        char *agent_filter = NULL;
        const char *pattern;
        const char *filter;
-       enum lttng_loglevel_type loglevel_type;
+       const struct lttng_log_level_rule *log_level_rule = NULL;
        enum lttng_event_rule_status status;
 
        assert(rule);
@@ -286,12 +296,6 @@ static int generate_agent_filter(
                goto end;
        }
 
-       status = lttng_event_rule_tracepoint_get_log_level_type(
-                       rule, &loglevel_type);
-       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
-               ret = -1;
-               goto end;
-       }
 
        /* Don't add filter for the '*' event. */
        if (strcmp(pattern, "*") != 0) {
@@ -311,21 +315,32 @@ static int generate_agent_filter(
                }
        }
 
-       if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
+       status = lttng_event_rule_tracepoint_get_log_level_rule(
+                       rule, &log_level_rule);
+       if (status == LTTNG_EVENT_RULE_STATUS_OK) {
+               enum lttng_log_level_rule_status llr_status;
                const char *op;
-               int loglevel_value;
+               int level;
 
-               status = lttng_event_rule_tracepoint_get_log_level(
-                               rule, &loglevel_value);
-               if (status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       ret = -1;
-                       goto end;
+               switch (lttng_log_level_rule_get_type(log_level_rule))
+               {
+               case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+                       llr_status = lttng_log_level_rule_exactly_get_level(
+                                       log_level_rule, &level);
+                       op = "==";
+                       break;
+               case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+                       llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level(
+                                       log_level_rule, &level);
+                       op = ">=";
+                       break;
+               default:
+                       abort();
                }
 
-               if (loglevel_type == LTTNG_EVENT_LOGLEVEL_RANGE) {
-                       op = ">=";
-               } else {
-                       op = "==";
+               if (llr_status != LTTNG_LOG_LEVEL_RULE_STATUS_OK) {
+                       ret = -1;
+                       goto end;
                }
 
                if (filter || agent_filter) {
@@ -334,14 +349,14 @@ static int generate_agent_filter(
                        err = asprintf(&new_filter,
                                        "(%s) && (int_loglevel %s %d)",
                                        agent_filter ? agent_filter : filter,
-                                       op, loglevel_value);
+                                       op, level);
                        if (agent_filter) {
                                free(agent_filter);
                        }
                        agent_filter = new_filter;
                } else {
                        err = asprintf(&agent_filter, "int_loglevel %s %d", op,
-                                       loglevel_value);
+                                       level);
                }
 
                if (err < 0) {
@@ -576,12 +591,8 @@ static unsigned long lttng_event_rule_tracepoint_hash(
                hash ^= hash_key_str(tp_rule->filter_expression, lttng_ht_seed);
        }
 
-       hash ^= hash_key_ulong((void *) tp_rule->loglevel.type,
-                              lttng_ht_seed);
-       if (tp_rule->loglevel.type != LTTNG_EVENT_LOGLEVEL_ALL) {
-               hash ^= hash_key_ulong(
-                               (void *) (unsigned long) tp_rule->loglevel.value,
-                               lttng_ht_seed);
+       if (tp_rule->log_level_rule) {
+               hash ^= lttng_log_level_rule_hash(tp_rule->log_level_rule);
        }
 
        status = lttng_event_rule_tracepoint_get_exclusions_count(rule,
@@ -607,6 +618,10 @@ static struct lttng_event *lttng_event_rule_tracepoint_generate_lttng_event(
        const struct lttng_event_rule_tracepoint *tracepoint;
        struct lttng_event *local_event = NULL;
        struct lttng_event *event = NULL;
+       enum lttng_loglevel_type loglevel_type;
+       int loglevel_value = 0;
+       enum lttng_event_rule_status status;
+       const struct lttng_log_level_rule *log_level_rule;
 
        tracepoint = container_of(
                        rule, const struct lttng_event_rule_tracepoint, parent);
@@ -625,8 +640,40 @@ static struct lttng_event *lttng_event_rule_tracepoint_generate_lttng_event(
                goto error;
        }
 
-       local_event->loglevel_type = tracepoint->loglevel.type;
-       local_event->loglevel = tracepoint->loglevel.value;
+
+       /* Map the log level rule to an equivalent lttng_loglevel */
+       status = lttng_event_rule_tracepoint_get_log_level_rule(rule, &log_level_rule);
+       if (status == LTTNG_EVENT_RULE_STATUS_UNSET) {
+               loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
+               loglevel_value = 0;
+       } else if (status == LTTNG_EVENT_RULE_STATUS_OK) {
+               enum lttng_log_level_rule_status llr_status;
+
+               switch (lttng_log_level_rule_get_type(log_level_rule)) {
+               case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+                       llr_status = lttng_log_level_rule_exactly_get_level(
+                                       log_level_rule, &loglevel_value);
+                       loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE;
+                       break;
+               case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+                       llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level(
+                                       log_level_rule, &loglevel_value);
+                       loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE;
+                       break;
+               default:
+                       abort();
+                       break;
+               }
+
+               if (llr_status != LTTNG_LOG_LEVEL_RULE_STATUS_OK) {
+                       goto error;
+               }
+       } else {
+               goto error;
+       }
+
+       local_event->loglevel_type = loglevel_type;
+       local_event->loglevel = loglevel_value;
 
        event = local_event;
        local_event = NULL;
@@ -640,6 +687,7 @@ struct lttng_event_rule *lttng_event_rule_tracepoint_create(
 {
        struct lttng_event_rule *rule = NULL;
        struct lttng_event_rule_tracepoint *tp_rule;
+       enum lttng_event_rule_status status;
 
        if (domain_type == LTTNG_DOMAIN_NONE) {
                goto end;
@@ -669,10 +717,18 @@ struct lttng_event_rule *lttng_event_rule_tracepoint_create(
                        lttng_event_rule_tracepoint_generate_lttng_event;
 
        tp_rule->domain = domain_type;
-       tp_rule->loglevel.type = LTTNG_EVENT_LOGLEVEL_ALL;
+       tp_rule->log_level_rule = NULL;
 
        lttng_dynamic_pointer_array_init(&tp_rule->exclusions,
                        destroy_lttng_exclusions_element);
+
+       /* Default pattern is '*' */
+       status = lttng_event_rule_tracepoint_set_pattern(rule, "*");
+       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+               lttng_event_rule_destroy(rule);
+               rule = NULL;
+       }
+       
 end:
        return rule;
 }
@@ -686,7 +742,6 @@ ssize_t lttng_event_rule_tracepoint_create_from_payload(
        int i;
        enum lttng_event_rule_status status;
        enum lttng_domain_type domain_type;
-       enum lttng_loglevel_type loglevel_type;
        const struct lttng_event_rule_tracepoint_comm *tracepoint_comm;
        const char *pattern;
        const char *filter_expression = NULL;
@@ -695,6 +750,7 @@ ssize_t lttng_event_rule_tracepoint_create_from_payload(
        const char *exclusion;
        struct lttng_buffer_view current_buffer_view;
        struct lttng_event_rule *rule = NULL;
+       struct lttng_log_level_rule *log_level_rule = NULL;
 
        if (!_event_rule) {
                ret = -1;
@@ -728,32 +784,6 @@ ssize_t lttng_event_rule_tracepoint_create_from_payload(
                goto end;
        }
 
-       loglevel_type = (enum lttng_loglevel_type)
-                                       tracepoint_comm->loglevel_type;
-       switch (loglevel_type) {
-       case LTTNG_EVENT_LOGLEVEL_ALL:
-               status = lttng_event_rule_tracepoint_set_log_level_all(rule);
-               break;
-       case LTTNG_EVENT_LOGLEVEL_RANGE:
-               status = lttng_event_rule_tracepoint_set_log_level_range_lower_bound(rule,
-                               (enum lttng_loglevel_type) tracepoint_comm
-                                               ->loglevel_value);
-               break;
-       case LTTNG_EVENT_LOGLEVEL_SINGLE:
-               status = lttng_event_rule_tracepoint_set_log_level(rule,
-                               (enum lttng_loglevel_type) tracepoint_comm
-                                               ->loglevel_value);
-               break;
-       default:
-               ERR("Failed to set event rule tracepoint loglevel: unknown loglevel type.");
-               ret = -1;
-               goto end;
-       }
-
-       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
-               ERR("Failed to set event rule tracepoint loglevel.");
-       }
-
        /* Skip to payload. */
        offset += current_buffer_view.size;
 
@@ -800,6 +830,29 @@ ssize_t lttng_event_rule_tracepoint_create_from_payload(
        offset += tracepoint_comm->filter_expression_len;
 
 skip_filter_expression:
+       if (!tracepoint_comm->log_level_rule_len) {
+               goto skip_log_level_rule;
+       }
+
+       {
+               /* Map the log level rule. */
+               struct lttng_payload_view current_payload_view =
+                               lttng_payload_view_from_view(view, offset,
+                                               tracepoint_comm->log_level_rule_len);
+               ret = lttng_log_level_rule_create_from_payload(
+                               &current_payload_view, &log_level_rule);
+               if (ret < 0) {
+                       ret = -1;
+                       goto end;
+               }
+
+               assert(ret == tracepoint_comm->log_level_rule_len);
+       }
+
+       /* Skip after the log level rule. */
+       offset += tracepoint_comm->log_level_rule_len;
+
+skip_log_level_rule:
        for (i = 0; i < tracepoint_comm->exclusions_count; i++) {
                current_buffer_view = lttng_buffer_view_from_view(
                                &view->buffer, offset, sizeof(*exclusion_len));
@@ -854,11 +907,22 @@ skip_filter_expression:
                }
        }
 
+       if (log_level_rule) {
+               status = lttng_event_rule_tracepoint_set_log_level_rule(
+                               rule, log_level_rule);
+               if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       ERR("Failed to set event rule tracepoint log level rule.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
        *_event_rule = rule;
        rule = NULL;
        ret = offset;
 end:
        free(exclusions);
+       lttng_log_level_rule_destroy(log_level_rule);
        lttng_event_rule_destroy(rule);
        return ret;
 }
@@ -989,10 +1053,25 @@ end:
        return status;
 }
 
-static bool log_level_value_valid(
-               int level, enum lttng_domain_type domain)
+static bool log_level_rule_valid(
+               const struct lttng_log_level_rule *rule , enum lttng_domain_type domain)
 {
        bool valid = false;
+       enum lttng_log_level_rule_status status;
+       int level;
+
+       switch(lttng_log_level_rule_get_type(rule)) {
+       case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+               status = lttng_log_level_rule_exactly_get_level(rule, &level);
+               break;
+       case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+               status = lttng_log_level_rule_at_least_as_severe_as_get_level(rule, &level);
+               break;
+       default:
+               abort();
+       }
+
+       assert(status == LTTNG_LOG_LEVEL_RULE_STATUS_OK);
 
        switch (domain) {
        case LTTNG_DOMAIN_KERNEL:
@@ -1031,11 +1110,13 @@ end:
        return valid;
 }
 
-enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level(
-               struct lttng_event_rule *rule, int level)
+enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level_rule(
+               struct lttng_event_rule *rule,
+               const struct lttng_log_level_rule *log_level_rule)
 {
        struct lttng_event_rule_tracepoint *tracepoint;
        enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
+       struct lttng_log_level_rule *copy = NULL;
 
        if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
                status = LTTNG_EVENT_RULE_STATUS_INVALID;
@@ -1045,99 +1126,48 @@ enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level(
        tracepoint = container_of(
                        rule, struct lttng_event_rule_tracepoint, parent);
 
-       if (!log_level_value_valid(level, tracepoint->domain)) {
+       if (!log_level_rule_valid(log_level_rule, tracepoint->domain)) {
                status = LTTNG_EVENT_RULE_STATUS_INVALID;
                goto end;
        }
 
-       tracepoint->loglevel.value = level;
-       tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_SINGLE;
-end:
-       return status;
-}
-
-enum lttng_event_rule_status
-lttng_event_rule_tracepoint_set_log_level_range_lower_bound(
-               struct lttng_event_rule *rule, int level)
-{
-       struct lttng_event_rule_tracepoint *tracepoint;
-       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
-
-       if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
+       copy = lttng_log_level_rule_copy(log_level_rule);
+       if (copy == NULL) {
+               status = LTTNG_EVENT_RULE_STATUS_ERROR;
                goto end;
        }
 
-       tracepoint = container_of(
-                       rule, struct lttng_event_rule_tracepoint, parent);
-
-       if (!log_level_value_valid(level, tracepoint->domain)) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
-               goto end;
+       if (tracepoint->log_level_rule) {
+               lttng_log_level_rule_destroy(tracepoint->log_level_rule);
        }
 
-       tracepoint->loglevel.value = level;
-       tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_RANGE;
-end:
-       return status;
-}
-
-enum lttng_event_rule_status lttng_event_rule_tracepoint_set_log_level_all(
-               struct lttng_event_rule *rule)
-{
-       struct lttng_event_rule_tracepoint *tracepoint;
-       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
+       tracepoint->log_level_rule = copy;
 
-       if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule)) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
-               goto end;
-       }
-
-       tracepoint = container_of(
-                       rule, struct lttng_event_rule_tracepoint, parent);
-       tracepoint->loglevel.type = LTTNG_EVENT_LOGLEVEL_ALL;
 end:
        return status;
 }
 
-enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level_type(
+enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level_rule(
                const struct lttng_event_rule *rule,
-               enum lttng_loglevel_type *type)
-{
-       struct lttng_event_rule_tracepoint *tracepoint;
-       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
-
-       if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !type) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
-               goto end;
-       }
-
-       tracepoint = container_of(
-                       rule, struct lttng_event_rule_tracepoint, parent);
-       *type = tracepoint->loglevel.type;
-end:
-       return status;
-}
-
-enum lttng_event_rule_status lttng_event_rule_tracepoint_get_log_level(
-               const struct lttng_event_rule *rule, int *level)
+               const struct lttng_log_level_rule **log_level_rule
+               )
 {
        struct lttng_event_rule_tracepoint *tracepoint;
        enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
 
-       if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !level) {
+       if (!rule || !IS_TRACEPOINT_EVENT_RULE(rule) || !log_level_rule) {
                status = LTTNG_EVENT_RULE_STATUS_INVALID;
                goto end;
        }
 
        tracepoint = container_of(
                        rule, struct lttng_event_rule_tracepoint, parent);
-       if (tracepoint->loglevel.type == LTTNG_EVENT_LOGLEVEL_ALL) {
+       if (tracepoint->log_level_rule == NULL) {
                status = LTTNG_EVENT_RULE_STATUS_UNSET;
                goto end;
        }
 
-       *level = tracepoint->loglevel.value;
+       *log_level_rule = tracepoint->log_level_rule;
 end:
        return status;
 }
diff --git a/src/common/event-rule/uprobe.c b/src/common/event-rule/uprobe.c
deleted file mode 100644 (file)
index 67f99c4..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <assert.h>
-#include <common/credentials.h>
-#include <common/error.h>
-#include <common/macros.h>
-#include <common/payload.h>
-#include <common/payload-view.h>
-#include <common/runas.h>
-#include <common/hashtable/hashtable.h>
-#include <common/hashtable/utils.h>
-#include <lttng/event-rule/event-rule-internal.h>
-#include <lttng/event-rule/uprobe-internal.h>
-#include <lttng/userspace-probe-internal.h>
-
-#define IS_UPROBE_EVENT_RULE(rule) \
-       (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_UPROBE)
-
-static void lttng_event_rule_uprobe_destroy(struct lttng_event_rule *rule)
-{
-       struct lttng_event_rule_uprobe *uprobe;
-
-       uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
-
-       lttng_userspace_probe_location_destroy(uprobe->location);
-       free(uprobe->name);
-       free(uprobe);
-}
-
-static bool lttng_event_rule_uprobe_validate(
-               const struct lttng_event_rule *rule)
-{
-       bool valid = false;
-       struct lttng_event_rule_uprobe *uprobe;
-
-       if (!rule) {
-               goto end;
-       }
-
-       uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
-
-       /* Required field. */
-       if (!uprobe->name) {
-               ERR("Invalid uprobe event rule: a pattern must be set.");
-               goto end;
-       }
-
-       if (!uprobe->location) {
-               ERR("Invalid uprobe event rule: a location must be set.");
-               goto end;
-       }
-
-       valid = true;
-end:
-       return valid;
-}
-
-static int lttng_event_rule_uprobe_serialize(
-               const struct lttng_event_rule *rule,
-               struct lttng_payload *payload)
-{
-       int ret;
-       size_t name_len, header_offset, size_before_probe;
-       struct lttng_event_rule_uprobe *uprobe;
-       struct lttng_event_rule_uprobe_comm uprobe_comm = {};
-       struct lttng_event_rule_uprobe_comm *header;
-
-       if (!rule || !IS_UPROBE_EVENT_RULE(rule)) {
-               ret = -1;
-               goto end;
-       }
-
-       header_offset = payload->buffer.size;
-
-       DBG("Serializing uprobe event rule.");
-       uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
-
-       name_len = strlen(uprobe->name) + 1;
-
-       uprobe_comm.name_len = name_len;
-
-       ret = lttng_dynamic_buffer_append(
-                       &payload->buffer, &uprobe_comm, sizeof(uprobe_comm));
-       if (ret) {
-               goto end;
-       }
-       ret = lttng_dynamic_buffer_append(
-                       &payload->buffer, uprobe->name, name_len);
-       if (ret) {
-               goto end;
-       }
-
-       size_before_probe = payload->buffer.size;
-
-       /* This serialize return the size taken in the buffer. */
-       ret = lttng_userspace_probe_location_serialize(
-                       uprobe->location, payload);
-       if (ret < 0) {
-               goto end;
-       }
-
-       /* Update the header regarding the probe size. */
-       header = (struct lttng_event_rule_uprobe_comm
-                                       *) ((char *) payload->buffer.data +
-                       header_offset);
-       header->location_len = payload->buffer.size - size_before_probe;
-
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static bool lttng_event_rule_uprobe_is_equal(const struct lttng_event_rule *_a,
-               const struct lttng_event_rule *_b)
-{
-       bool is_equal = false;
-       struct lttng_event_rule_uprobe *a, *b;
-
-       a = container_of(_a, struct lttng_event_rule_uprobe, parent);
-       b = container_of(_b, struct lttng_event_rule_uprobe, parent);
-
-       /* uprobe is invalid if this is not true. */
-       assert(a->name);
-       assert(b->name);
-       if (strcmp(a->name, b->name)) {
-               goto end;
-       }
-
-       assert(a->location);
-       assert(b->location);
-       is_equal = lttng_userspace_probe_location_is_equal(
-                       a->location, b->location);
-end:
-       return is_equal;
-}
-
-static enum lttng_error_code lttng_event_rule_uprobe_generate_filter_bytecode(
-               struct lttng_event_rule *rule,
-               const struct lttng_credentials *creds)
-{
-       /* Nothing to do. */
-       return LTTNG_OK;
-}
-
-static const char *lttng_event_rule_uprobe_get_filter(
-               const struct lttng_event_rule *rule)
-{
-       /* Unsupported. */
-       return NULL;
-}
-
-static const struct lttng_bytecode *
-lttng_event_rule_uprobe_get_filter_bytecode(const struct lttng_event_rule *rule)
-{
-       /* Unsupported. */
-       return NULL;
-}
-
-static enum lttng_event_rule_generate_exclusions_status
-lttng_event_rule_uprobe_generate_exclusions(const struct lttng_event_rule *rule,
-               struct lttng_event_exclusion **exclusions)
-{
-       /* Unsupported. */
-       *exclusions = NULL;
-       return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
-}
-
-static unsigned long
-lttng_event_rule_uprobe_hash(
-               const struct lttng_event_rule *rule)
-{
-       unsigned long hash;
-       struct lttng_event_rule_uprobe *urule =
-                       container_of(rule, typeof(*urule), parent);
-
-       hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_UPROBE,
-                       lttng_ht_seed);
-       hash ^= hash_key_str(urule->name, lttng_ht_seed);
-       hash ^= lttng_userspace_probe_location_hash(urule->location);
-
-       return hash;
-}
-
-struct lttng_event_rule *lttng_event_rule_uprobe_create(void)
-{
-       struct lttng_event_rule *rule = NULL;
-       struct lttng_event_rule_uprobe *urule;
-
-       urule = zmalloc(sizeof(struct lttng_event_rule_uprobe));
-       if (!urule) {
-               goto end;
-       }
-
-       rule = &urule->parent;
-       lttng_event_rule_init(&urule->parent, LTTNG_EVENT_RULE_TYPE_UPROBE);
-       urule->parent.validate = lttng_event_rule_uprobe_validate;
-       urule->parent.serialize = lttng_event_rule_uprobe_serialize;
-       urule->parent.equal = lttng_event_rule_uprobe_is_equal;
-       urule->parent.destroy = lttng_event_rule_uprobe_destroy;
-       urule->parent.generate_filter_bytecode =
-                       lttng_event_rule_uprobe_generate_filter_bytecode;
-       urule->parent.get_filter = lttng_event_rule_uprobe_get_filter;
-       urule->parent.get_filter_bytecode =
-                       lttng_event_rule_uprobe_get_filter_bytecode;
-       urule->parent.generate_exclusions =
-                       lttng_event_rule_uprobe_generate_exclusions;
-       urule->parent.hash = lttng_event_rule_uprobe_hash;
-end:
-       return rule;
-}
-
-LTTNG_HIDDEN
-ssize_t lttng_event_rule_uprobe_create_from_payload(
-               struct lttng_payload_view *view,
-               struct lttng_event_rule **_event_rule)
-{
-       ssize_t ret, offset = 0;
-       const struct lttng_event_rule_uprobe_comm *uprobe_comm;
-       const char *name;
-       struct lttng_buffer_view current_buffer_view;
-       struct lttng_event_rule *rule = NULL;
-       struct lttng_userspace_probe_location *location;
-       struct lttng_event_rule_uprobe *uprobe;
-       enum lttng_event_rule_status status;
-
-       if (!_event_rule) {
-               ret = -1;
-               goto end;
-       }
-
-       current_buffer_view = lttng_buffer_view_from_view(
-                       &view->buffer, offset, sizeof(*uprobe_comm));
-       if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
-               ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain header");
-               ret = -1;
-               goto end;
-       }
-
-       uprobe_comm = (typeof(uprobe_comm)) current_buffer_view.data;
-
-       rule = lttng_event_rule_uprobe_create();
-       if (!rule) {
-               ERR("Failed to create event rule uprobe");
-               ret = -1;
-               goto end;
-       }
-
-       /* Skip to payload. */
-       offset += current_buffer_view.size;
-
-       /* Map the name. */
-       current_buffer_view = lttng_buffer_view_from_view(
-                       &view->buffer, offset, uprobe_comm->name_len);
-       if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
-               ret = -1;
-               goto end;
-       }
-
-       name = current_buffer_view.data;
-       if (!lttng_buffer_view_contains_string(&current_buffer_view, name,
-                       uprobe_comm->name_len)) {
-               ret = -1;
-               goto end;
-       }
-
-       /* Skip after the name. */
-       offset += uprobe_comm->name_len;
-
-       /* Map the location. */
-       {
-               struct lttng_payload_view current_payload_view =
-                               lttng_payload_view_from_view(view, offset,
-                                               uprobe_comm->location_len);
-
-               if (!lttng_payload_view_is_valid(&current_payload_view)) {
-                       ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain location");
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = lttng_userspace_probe_location_create_from_payload(
-                               &current_payload_view, &location);
-               if (ret < 0) {
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       assert(ret == uprobe_comm->location_len);
-
-       /* Skip after the location. */
-       offset += uprobe_comm->location_len;
-
-       uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
-       uprobe->location = location;
-
-       status = lttng_event_rule_uprobe_set_name(rule, name);
-       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
-               ret = -1;
-               goto end;
-       }
-
-       if (!lttng_event_rule_uprobe_validate(rule)) {
-               ret = -1;
-               goto end;
-       }
-
-       *_event_rule = rule;
-       rule = NULL;
-       ret = offset;
-end:
-       lttng_event_rule_destroy(rule);
-       return ret;
-}
-
-enum lttng_event_rule_status lttng_event_rule_uprobe_set_location(
-               struct lttng_event_rule *rule,
-               const struct lttng_userspace_probe_location *location)
-{
-       struct lttng_userspace_probe_location *location_copy = NULL;
-       struct lttng_event_rule_uprobe *uprobe;
-       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
-
-       if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !location) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
-               goto end;
-       }
-
-       uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
-       location_copy = lttng_userspace_probe_location_copy(location);
-       if (!location_copy) {
-               status = LTTNG_EVENT_RULE_STATUS_ERROR;
-               goto end;
-       }
-
-       if (uprobe->location) {
-               lttng_userspace_probe_location_destroy(uprobe->location);
-       }
-
-       uprobe->location = location_copy;
-       location_copy = NULL;
-end:
-       lttng_userspace_probe_location_destroy(location_copy);
-       return status;
-}
-
-enum lttng_event_rule_status lttng_event_rule_uprobe_get_location(
-               const struct lttng_event_rule *rule,
-               const struct lttng_userspace_probe_location **location)
-{
-       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
-
-       if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !location) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
-               goto end;
-       }
-
-       *location = lttng_event_rule_uprobe_get_location_mutable(rule);
-       if (!*location) {
-               status = LTTNG_EVENT_RULE_STATUS_UNSET;
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-LTTNG_HIDDEN
-struct lttng_userspace_probe_location *
-lttng_event_rule_uprobe_get_location_mutable(
-               const struct lttng_event_rule *rule)
-{
-       struct lttng_event_rule_uprobe *uprobe;
-
-       assert(rule);
-       uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
-
-       return uprobe->location;
-}
-
-enum lttng_event_rule_status lttng_event_rule_uprobe_set_name(
-               struct lttng_event_rule *rule, const char *name)
-{
-       char *name_copy = NULL;
-       struct lttng_event_rule_uprobe *uprobe;
-       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
-
-       if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name ||
-                       strlen(name) == 0) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
-               goto end;
-       }
-
-       uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
-       name_copy = strdup(name);
-       if (!name_copy) {
-               status = LTTNG_EVENT_RULE_STATUS_ERROR;
-               goto end;
-       }
-
-       if (uprobe->name) {
-               free(uprobe->name);
-       }
-
-       uprobe->name = name_copy;
-       name_copy = NULL;
-end:
-       return status;
-}
-
-enum lttng_event_rule_status lttng_event_rule_uprobe_get_name(
-               const struct lttng_event_rule *rule, const char **name)
-{
-       struct lttng_event_rule_uprobe *uprobe;
-       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
-
-       if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name) {
-               status = LTTNG_EVENT_RULE_STATUS_INVALID;
-               goto end;
-       }
-
-       uprobe = container_of(rule, struct lttng_event_rule_uprobe, parent);
-       if (!uprobe->name) {
-               status = LTTNG_EVENT_RULE_STATUS_UNSET;
-               goto end;
-       }
-
-       *name = uprobe->name;
-end:
-       return status;
-}
diff --git a/src/common/event-rule/userspace-probe.c b/src/common/event-rule/userspace-probe.c
new file mode 100644 (file)
index 0000000..52c7553
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <common/credentials.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/payload.h>
+#include <common/payload-view.h>
+#include <common/runas.h>
+#include <common/hashtable/hashtable.h>
+#include <common/hashtable/utils.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/userspace-probe-internal.h>
+#include <lttng/userspace-probe-internal.h>
+
+#define IS_UPROBE_EVENT_RULE(rule) \
+       (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE)
+
+static void lttng_event_rule_userspace_probe_destroy(struct lttng_event_rule *rule)
+{
+       struct lttng_event_rule_userspace_probe *uprobe;
+
+       uprobe = container_of(rule, struct lttng_event_rule_userspace_probe, parent);
+
+       lttng_userspace_probe_location_destroy(uprobe->location);
+       free(uprobe->name);
+       free(uprobe);
+}
+
+static bool lttng_event_rule_userspace_probe_validate(
+               const struct lttng_event_rule *rule)
+{
+       bool valid = false;
+       struct lttng_event_rule_userspace_probe *uprobe;
+
+       if (!rule) {
+               goto end;
+       }
+
+       uprobe = container_of(rule, struct lttng_event_rule_userspace_probe, parent);
+
+       /* Required field. */
+       if (!uprobe->name) {
+               ERR("Invalid uprobe event rule: a pattern must be set.");
+               goto end;
+       }
+
+       if (!uprobe->location) {
+               ERR("Invalid uprobe event rule: a location must be set.");
+               goto end;
+       }
+
+       valid = true;
+end:
+       return valid;
+}
+
+static int lttng_event_rule_userspace_probe_serialize(
+               const struct lttng_event_rule *rule,
+               struct lttng_payload *payload)
+{
+       int ret;
+       size_t name_len, header_offset, size_before_probe;
+       struct lttng_event_rule_userspace_probe *uprobe;
+       struct lttng_event_rule_userspace_probe_comm uprobe_comm = {};
+       struct lttng_event_rule_userspace_probe_comm *header;
+
+       if (!rule || !IS_UPROBE_EVENT_RULE(rule)) {
+               ret = -1;
+               goto end;
+       }
+
+       header_offset = payload->buffer.size;
+
+       DBG("Serializing uprobe event rule.");
+       uprobe = container_of(rule, struct lttng_event_rule_userspace_probe, parent);
+
+       name_len = strlen(uprobe->name) + 1;
+
+       uprobe_comm.name_len = name_len;
+
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, &uprobe_comm, sizeof(uprobe_comm));
+       if (ret) {
+               goto end;
+       }
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, uprobe->name, name_len);
+       if (ret) {
+               goto end;
+       }
+
+       size_before_probe = payload->buffer.size;
+
+       /* This serialize return the size taken in the buffer. */
+       ret = lttng_userspace_probe_location_serialize(
+                       uprobe->location, payload);
+       if (ret < 0) {
+               goto end;
+       }
+
+       /* Update the header regarding the probe size. */
+       header = (struct lttng_event_rule_userspace_probe_comm
+                                       *) ((char *) payload->buffer.data +
+                       header_offset);
+       header->location_len = payload->buffer.size - size_before_probe;
+
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static bool lttng_event_rule_userspace_probe_is_equal(const struct lttng_event_rule *_a,
+               const struct lttng_event_rule *_b)
+{
+       bool is_equal = false;
+       struct lttng_event_rule_userspace_probe *a, *b;
+
+       a = container_of(_a, struct lttng_event_rule_userspace_probe, parent);
+       b = container_of(_b, struct lttng_event_rule_userspace_probe, parent);
+
+       /* uprobe is invalid if this is not true. */
+       assert(a->name);
+       assert(b->name);
+       if (strcmp(a->name, b->name)) {
+               goto end;
+       }
+
+       assert(a->location);
+       assert(b->location);
+       is_equal = lttng_userspace_probe_location_is_equal(
+                       a->location, b->location);
+end:
+       return is_equal;
+}
+
+static enum lttng_error_code lttng_event_rule_userspace_probe_generate_filter_bytecode(
+               struct lttng_event_rule *rule,
+               const struct lttng_credentials *creds)
+{
+       /* Nothing to do. */
+       return LTTNG_OK;
+}
+
+static const char *lttng_event_rule_userspace_probe_get_filter(
+               const struct lttng_event_rule *rule)
+{
+       /* Unsupported. */
+       return NULL;
+}
+
+static const struct lttng_bytecode *
+lttng_event_rule_userspace_probe_get_filter_bytecode(const struct lttng_event_rule *rule)
+{
+       /* Unsupported. */
+       return NULL;
+}
+
+static enum lttng_event_rule_generate_exclusions_status
+lttng_event_rule_userspace_probe_generate_exclusions(const struct lttng_event_rule *rule,
+               struct lttng_event_exclusion **exclusions)
+{
+       /* Unsupported. */
+       *exclusions = NULL;
+       return LTTNG_EVENT_RULE_GENERATE_EXCLUSIONS_STATUS_NONE;
+}
+
+static unsigned long
+lttng_event_rule_userspace_probe_hash(
+               const struct lttng_event_rule *rule)
+{
+       unsigned long hash;
+       struct lttng_event_rule_userspace_probe *urule =
+                       container_of(rule, typeof(*urule), parent);
+
+       hash = hash_key_ulong((void *) LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE,
+                       lttng_ht_seed);
+       hash ^= hash_key_str(urule->name, lttng_ht_seed);
+       hash ^= lttng_userspace_probe_location_hash(urule->location);
+
+       return hash;
+}
+
+static
+int userspace_probe_set_location(
+               struct lttng_event_rule_userspace_probe *uprobe,
+               const struct lttng_userspace_probe_location *location)
+{
+       int ret;
+       struct lttng_userspace_probe_location *location_copy = NULL;
+
+       if (!uprobe || !location || uprobe->location) {
+               ret = -1;
+               goto end;
+       }
+
+       location_copy = lttng_userspace_probe_location_copy(location);
+       if (!location_copy) {
+               ret = -1;
+               goto end;
+       }
+
+       uprobe->location = location_copy;
+       location_copy = NULL;
+       ret = 0;
+end:
+       lttng_userspace_probe_location_destroy(location_copy);
+       return ret;
+}
+
+struct lttng_event_rule *lttng_event_rule_userspace_probe_create(
+               const struct lttng_userspace_probe_location *location)
+{
+       struct lttng_event_rule *rule = NULL;
+       struct lttng_event_rule_userspace_probe *urule;
+
+       urule = zmalloc(sizeof(struct lttng_event_rule_userspace_probe));
+       if (!urule) {
+               goto end;
+       }
+
+       rule = &urule->parent;
+       lttng_event_rule_init(&urule->parent, LTTNG_EVENT_RULE_TYPE_USERSPACE_PROBE);
+       urule->parent.validate = lttng_event_rule_userspace_probe_validate;
+       urule->parent.serialize = lttng_event_rule_userspace_probe_serialize;
+       urule->parent.equal = lttng_event_rule_userspace_probe_is_equal;
+       urule->parent.destroy = lttng_event_rule_userspace_probe_destroy;
+       urule->parent.generate_filter_bytecode =
+                       lttng_event_rule_userspace_probe_generate_filter_bytecode;
+       urule->parent.get_filter = lttng_event_rule_userspace_probe_get_filter;
+       urule->parent.get_filter_bytecode =
+                       lttng_event_rule_userspace_probe_get_filter_bytecode;
+       urule->parent.generate_exclusions =
+                       lttng_event_rule_userspace_probe_generate_exclusions;
+       urule->parent.hash = lttng_event_rule_userspace_probe_hash;
+
+       if (userspace_probe_set_location(urule, location)) {
+               lttng_event_rule_destroy(rule);
+               rule = NULL;
+       }
+
+end:
+       return rule;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_event_rule_userspace_probe_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_event_rule **_event_rule)
+{
+       ssize_t ret, offset = 0;
+       const struct lttng_event_rule_userspace_probe_comm *uprobe_comm;
+       const char *name;
+       struct lttng_buffer_view current_buffer_view;
+       struct lttng_event_rule *rule = NULL;
+       struct lttng_userspace_probe_location *location = NULL;
+       enum lttng_event_rule_status status;
+
+       if (!_event_rule) {
+               ret = -1;
+               goto end;
+       }
+
+       current_buffer_view = lttng_buffer_view_from_view(
+                       &view->buffer, offset, sizeof(*uprobe_comm));
+       if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
+               ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain header");
+               ret = -1;
+               goto end;
+       }
+
+       uprobe_comm = (typeof(uprobe_comm)) current_buffer_view.data;
+
+       /* Skip to payload. */
+       offset += current_buffer_view.size;
+
+       /* Map the name. */
+       current_buffer_view = lttng_buffer_view_from_view(
+                       &view->buffer, offset, uprobe_comm->name_len);
+       if (!lttng_buffer_view_is_valid(&current_buffer_view)) {
+               ret = -1;
+               goto end;
+       }
+
+       name = current_buffer_view.data;
+       if (!lttng_buffer_view_contains_string(&current_buffer_view, name,
+                       uprobe_comm->name_len)) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Skip after the name. */
+       offset += uprobe_comm->name_len;
+
+       /* Map the location. */
+       {
+               struct lttng_payload_view current_payload_view =
+                               lttng_payload_view_from_view(view, offset,
+                                               uprobe_comm->location_len);
+
+               if (!lttng_payload_view_is_valid(&current_payload_view)) {
+                       ERR("Failed to initialize from malformed event rule uprobe: buffer too short to contain location");
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = lttng_userspace_probe_location_create_from_payload(
+                               &current_payload_view, &location);
+               if (ret < 0) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       assert(ret == uprobe_comm->location_len);
+
+       /* Skip after the location. */
+       offset += uprobe_comm->location_len;
+
+       rule = lttng_event_rule_userspace_probe_create(location);
+       if (!rule) {
+               ERR("Failed to create event rule uprobe.");
+               ret = -1;
+               goto end;
+       }
+
+       status = lttng_event_rule_userspace_probe_set_event_name(rule, name);
+       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       if (!lttng_event_rule_userspace_probe_validate(rule)) {
+               ret = -1;
+               goto end;
+       }
+
+       *_event_rule = rule;
+       rule = NULL;
+       ret = offset;
+end:
+       lttng_userspace_probe_location_destroy(location);
+       lttng_event_rule_destroy(rule);
+       return ret;
+}
+
+
+enum lttng_event_rule_status lttng_event_rule_userspace_probe_get_location(
+               const struct lttng_event_rule *rule,
+               const struct lttng_userspace_probe_location **location)
+{
+       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
+
+       if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !location) {
+               status = LTTNG_EVENT_RULE_STATUS_INVALID;
+               goto end;
+       }
+
+       *location = lttng_event_rule_userspace_probe_get_location_mutable(rule);
+       if (!*location) {
+               status = LTTNG_EVENT_RULE_STATUS_UNSET;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+struct lttng_userspace_probe_location *
+lttng_event_rule_userspace_probe_get_location_mutable(
+               const struct lttng_event_rule *rule)
+{
+       struct lttng_event_rule_userspace_probe *uprobe;
+
+       assert(rule);
+       uprobe = container_of(rule, struct lttng_event_rule_userspace_probe, parent);
+
+       return uprobe->location;
+}
+
+enum lttng_event_rule_status lttng_event_rule_userspace_probe_set_event_name(
+               struct lttng_event_rule *rule, const char *name)
+{
+       char *name_copy = NULL;
+       struct lttng_event_rule_userspace_probe *uprobe;
+       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
+
+       if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name ||
+                       strlen(name) == 0) {
+               status = LTTNG_EVENT_RULE_STATUS_INVALID;
+               goto end;
+       }
+
+       uprobe = container_of(rule, struct lttng_event_rule_userspace_probe, parent);
+       name_copy = strdup(name);
+       if (!name_copy) {
+               status = LTTNG_EVENT_RULE_STATUS_ERROR;
+               goto end;
+       }
+
+       if (uprobe->name) {
+               free(uprobe->name);
+       }
+
+       uprobe->name = name_copy;
+       name_copy = NULL;
+end:
+       return status;
+}
+
+enum lttng_event_rule_status lttng_event_rule_userspace_probe_get_event_name(
+               const struct lttng_event_rule *rule, const char **name)
+{
+       struct lttng_event_rule_userspace_probe *uprobe;
+       enum lttng_event_rule_status status = LTTNG_EVENT_RULE_STATUS_OK;
+
+       if (!rule || !IS_UPROBE_EVENT_RULE(rule) || !name) {
+               status = LTTNG_EVENT_RULE_STATUS_INVALID;
+               goto end;
+       }
+
+       uprobe = container_of(rule, struct lttng_event_rule_userspace_probe, parent);
+       if (!uprobe->name) {
+               status = LTTNG_EVENT_RULE_STATUS_UNSET;
+               goto end;
+       }
+
+       *name = uprobe->name;
+end:
+       return status;
+}
index f449fab8bd6dabab89302b86c9222d0569fc5cf6..af16676cca349e21ba63868f2d2a026972593a13 100644 (file)
@@ -76,6 +76,24 @@ static int match_two_u64(struct cds_lfht_node *node, const void *key)
        return hash_match_key_two_u64((void *) &match_node->key, (void *) key);
 }
 
+static inline
+const char *lttng_ht_type_str(enum lttng_ht_type type)
+{
+       switch (type) {
+       case LTTNG_HT_TYPE_STRING:
+               return "STRING";
+       case LTTNG_HT_TYPE_ULONG:
+               return "ULONG";
+       case LTTNG_HT_TYPE_U64:
+               return "U64";
+       case LTTNG_HT_TYPE_TWO_U64:
+               return "TWO_U64";
+       default:
+               ERR("Unknown lttng hashtable type %d", type);
+               abort();
+       }
+}
+
 /*
  * Return an allocated lttng hashtable.
  */
@@ -132,7 +150,8 @@ struct lttng_ht *lttng_ht_new(unsigned long size, int type)
                goto error;
        }
 
-       DBG3("Created hashtable size %lu at %p of type %d", size, ht->ht, type);
+       DBG3("Created hashtable size %lu at %p of type %s", size, ht->ht,
+                       lttng_ht_type_str(type));
 
        return ht;
 
diff --git a/src/common/index-allocator.c b/src/common/index-allocator.c
new file mode 100644 (file)
index 0000000..ff5e2c8
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+
+#include <urcu.h>
+#include <urcu/list.h>
+
+#include "macros.h"
+#include "error.h"
+
+#include "index-allocator.h"
+
+struct lttng_index_allocator {
+       struct cds_list_head unused_list;
+       uint64_t size;
+       uint64_t position;
+};
+
+struct lttng_index {
+       uint64_t index;
+       struct cds_list_head head;
+};
+
+struct lttng_index_allocator *lttng_index_allocator_create(
+               uint64_t index_count)
+{
+       struct lttng_index_allocator *allocator = NULL;
+
+       allocator = zmalloc(sizeof(*allocator));
+       if (!allocator) {
+               PERROR("Failed to allocate free index queue");
+               goto end;
+       }
+       allocator->size = index_count;
+       allocator->position = 0;
+
+       CDS_INIT_LIST_HEAD(&allocator->unused_list);
+
+end:
+       return allocator;
+}
+
+uint64_t lttng_index_allocator_get_index_count(struct lttng_index_allocator *allocator)
+{
+       return allocator->size;
+}
+
+enum lttng_index_allocator_status lttng_index_allocator_alloc(
+               struct lttng_index_allocator *allocator,
+               uint64_t *allocated_index)
+{
+       enum lttng_index_allocator_status status =
+                       LTTNG_INDEX_ALLOCATOR_STATUS_OK;
+
+       if (cds_list_empty(&allocator->unused_list)) {
+               if (allocator->position >= allocator->size) {
+                       /* No indices left. */
+                       status = LTTNG_INDEX_ALLOCATOR_STATUS_EMPTY;
+                       goto end;
+               }
+
+               *allocated_index = allocator->position++;
+       } else {
+               struct lttng_index *index;
+
+               index = cds_list_first_entry(&allocator->unused_list,
+                               typeof(*index), head);
+               cds_list_del(&index->head);
+               *allocated_index = index->index;
+               free(index);
+       }
+
+end:
+       return status;
+}
+
+enum lttng_index_allocator_status lttng_index_allocator_release(
+               struct lttng_index_allocator *allocator, uint64_t idx)
+{
+       struct lttng_index *index = NULL;
+       enum lttng_index_allocator_status status =
+                       LTTNG_INDEX_ALLOCATOR_STATUS_OK;
+
+       assert(idx < allocator->size);
+
+       index = zmalloc(sizeof(*index));
+       if (!index) {
+               PERROR("Failed to allocate free index queue");
+               status = LTTNG_INDEX_ALLOCATOR_STATUS_ERROR;
+               goto end;
+       }
+
+       index->index = idx;
+       cds_list_add_tail(&index->head, &allocator->unused_list);
+
+end:
+       return status;
+}
+
+void lttng_index_allocator_destroy(struct lttng_index_allocator *allocator)
+{
+       struct lttng_index *index = NULL, *tmp_index = NULL;
+
+       if (!allocator) {
+               return;
+       }
+
+       cds_list_for_each_entry_safe(index, tmp_index,
+                       &allocator->unused_list, head) {
+               cds_list_del(&index->head);
+               free(index);
+       }
+
+       free(allocator);
+}
diff --git a/src/common/index-allocator.h b/src/common/index-allocator.h
new file mode 100644 (file)
index 0000000..cdc5750
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef _COMMON_INDEX_ALLOCATOR_H
+#define _COMMON_INDEX_ALLOCATOR_H
+
+#include <inttypes.h>
+
+struct lttng_index_allocator;
+
+enum lttng_index_allocator_status {
+       LTTNG_INDEX_ALLOCATOR_STATUS_OK,
+       LTTNG_INDEX_ALLOCATOR_STATUS_EMPTY,
+       LTTNG_INDEX_ALLOCATOR_STATUS_ERROR,
+};
+
+struct lttng_index_allocator *lttng_index_allocator_create(
+               uint64_t index_count);
+
+uint64_t lttng_index_allocator_get_index_count(
+       struct lttng_index_allocator *allocator);
+
+enum lttng_index_allocator_status lttng_index_allocator_alloc(
+               struct lttng_index_allocator *allocator,
+               uint64_t *index);
+
+enum lttng_index_allocator_status lttng_index_allocator_release(
+               struct lttng_index_allocator *allocator, uint64_t index);
+
+void lttng_index_allocator_destroy(struct lttng_index_allocator *allocator);
+
+#endif /* _COMMON_INDEX_ALLOCATOR_H */
index bb6602e2bffb57f676514313b462b5e8b62645e6..7bcfd5dc284f61f6d0e85b05f686c970622a4543 100644 (file)
@@ -155,6 +155,12 @@ int kernctl_create_channel(int fd, struct lttng_channel_attr *chops)
        return LTTNG_IOCTL_NO_CHECK(fd, LTTNG_KERNEL_CHANNEL, &channel);
 }
 
+int kernctl_create_session_counter(int session_fd, struct lttng_kernel_counter_conf *counter_conf)
+{
+       return LTTNG_IOCTL_NO_CHECK(session_fd, LTTNG_KERNEL_COUNTER, counter_conf);
+}
+
+
 int kernctl_syscall_mask(int fd, char **syscall_mask, uint32_t *nr_bits)
 {
        struct lttng_kernel_syscall_mask kmask_len, *kmask = NULL;
@@ -424,12 +430,64 @@ int kernctl_create_event_notifier_group(int fd)
                        LTTNG_KERNEL_EVENT_NOTIFIER_GROUP_CREATE);
 }
 
+int kernctl_create_counter_event(int fd, struct lttng_kernel_counter_event *ev)
+{
+       return LTTNG_IOCTL_NO_CHECK(fd, LTTNG_KERNEL_COUNTER_EVENT, ev);
+}
+
 int kernctl_create_event_notifier_group_notification_fd(int group_fd)
 {
        return LTTNG_IOCTL_NO_CHECK(group_fd,
                        LTTNG_KERNEL_EVENT_NOTIFIER_GROUP_NOTIFICATION_FD);
 }
 
+int kernctl_create_event_notifier_group_error_counter(int group_fd,
+               struct lttng_kernel_counter_conf *error_counter_conf)
+{
+       return LTTNG_IOCTL_NO_CHECK(group_fd, LTTNG_KERNEL_COUNTER,
+                       error_counter_conf);
+}
+
+int kernctl_counter_read_value(int counter_fd,
+               struct lttng_kernel_counter_read *value)
+{
+       return LTTNG_IOCTL_NO_CHECK(counter_fd, LTTNG_KERNEL_COUNTER_READ,
+                       value);
+}
+
+int kernctl_counter_get_aggregate_value(int counter_fd,
+               struct lttng_kernel_counter_aggregate *value)
+{
+       return LTTNG_IOCTL_NO_CHECK(counter_fd, LTTNG_KERNEL_COUNTER_AGGREGATE,
+                       value);
+}
+
+int kernctl_counter_clear(int counter_fd,
+               struct lttng_kernel_counter_clear *clear)
+{
+       return LTTNG_IOCTL_NO_CHECK(counter_fd, LTTNG_KERNEL_COUNTER_CLEAR,
+                       clear);
+}
+
+int kernctl_counter_map_descriptor_count(int counter_fd, uint64_t *count)
+{
+       struct lttng_kernel_counter_map_nr_descriptors nr_desc;
+       int ret;
+
+       ret = LTTNG_IOCTL_NO_CHECK(counter_fd,
+                       LTTNG_KERNEL_COUNTER_MAP_NR_DESCRIPTORS, &nr_desc);
+       *count = nr_desc.nr_descriptors;
+
+       return ret;
+}
+
+int kernctl_counter_map_descriptor(int counter_fd,
+               struct lttng_kernel_counter_map_descriptor *descriptor)
+{
+       return LTTNG_IOCTL_NO_CHECK(counter_fd,
+                       LTTNG_KERNEL_COUNTER_MAP_DESCRIPTOR, descriptor);
+}
+
 int kernctl_create_event_notifier(int group_fd,
                const struct lttng_kernel_event_notifier *event_notifier)
 {
@@ -437,6 +495,25 @@ int kernctl_create_event_notifier(int group_fd,
                        LTTNG_KERNEL_EVENT_NOTIFIER_CREATE, event_notifier);
 }
 
+int kernctl_capture(int fd, const struct lttng_bytecode *capture)
+{
+       struct lttng_kernel_capture_bytecode *kb;
+       uint32_t len;
+       int ret;
+
+       /* Translate bytecode to kernel bytecode */
+       kb = zmalloc(sizeof(*kb) + capture->len);
+       if (!kb)
+               return -ENOMEM;
+       kb->len = len = capture->len;
+       kb->reloc_offset = capture->reloc_table_offset;
+       kb->seqnum = capture->seqnum;
+       memcpy(kb->data, capture->data, len);
+       ret = LTTNG_IOCTL_CHECK(fd, LTTNG_KERNEL_CAPTURE, kb);
+       free(kb);
+       return ret;
+}
+
 int kernctl_filter(int fd, const struct lttng_bytecode *filter)
 {
        struct lttng_kernel_filter_bytecode *kb;
index 3bbe69f48ce41c9d8b163dc3d8032fed27133406..537590f35886fc2535a052c222fad809bc4c7f30 100644 (file)
 int kernctl_create_session(int fd);
 int kernctl_open_metadata(int fd, struct lttng_channel_attr *chops);
 int kernctl_create_channel(int fd, struct lttng_channel_attr *chops);
+int kernctl_create_session_counter(int session_fd, struct lttng_kernel_counter_conf *counter_conf);
 int kernctl_create_stream(int fd);
 int kernctl_create_event(int fd, struct lttng_kernel_event *ev);
+int kernctl_create_counter_event(int fd, struct lttng_kernel_counter_event *ev);
 int kernctl_add_context(int fd, struct lttng_kernel_context *ctx);
 
 int kernctl_enable(int fd);
@@ -32,12 +34,26 @@ int kernctl_create_event_notifier_group(int fd);
 
 /* Apply on event notifier_group file descriptor. */
 int kernctl_create_event_notifier_group_notification_fd(int fd);
+int kernctl_create_event_notifier_group_error_counter(int fd,
+               struct lttng_kernel_counter_conf *error_counter_conf);
 int kernctl_create_event_notifier(int fd,
                const struct lttng_kernel_event_notifier *event_notifier);
 
+int kernctl_counter_read_value(int counter_fd,
+               struct lttng_kernel_counter_read *value);
+int kernctl_counter_get_aggregate_value(int counter_fd,
+               struct lttng_kernel_counter_aggregate *value);
+int kernctl_counter_clear(int counter_fd,
+               struct lttng_kernel_counter_clear *clear);
+
+int kernctl_counter_map_descriptor_count(int counter_fd, uint64_t *count);
+int kernctl_counter_map_descriptor(int counter_fd,
+               struct lttng_kernel_counter_map_descriptor *descriptor);
+
 /* Apply on event file descriptor. */
 int kernctl_filter(int fd, const struct lttng_bytecode *filter);
 int kernctl_add_callsite(int fd, struct lttng_kernel_event_callsite *callsite);
+int kernctl_capture(int fd, const struct lttng_bytecode *capture);
 
 int kernctl_tracepoint_list(int fd);
 int kernctl_syscall_list(int fd);
index 8fa0a7d100c480ad8416ce06395d1fee2146fe73..e45359763858dbbfd780abdbe8af33422917b673 100644 (file)
 #define LTTNG_KERNEL_ENABLE                    _IO(0xF6, 0x82)
 #define LTTNG_KERNEL_DISABLE                   _IO(0xF6, 0x83)
 
+/* Event notifier group ioctl */
+#define LTTNG_KERNEL_COUNTER                   \
+       _IOW(0xF6, 0x84, struct lttng_kernel_counter_conf)
+
 /* Event and event notifier FD ioctl */
 #define LTTNG_KERNEL_FILTER                    _IO(0xF6, 0x90)
 #define LTTNG_KERNEL_ADD_CALLSITE      _IO(0xF6, 0x91)
 #define LTTNG_KERNEL_EVENT_NOTIFIER_GROUP_NOTIFICATION_FD      \
        _IO(0xF6, 0xB1)
 
+/* Event notifier file descriptor ioctl */
+#define LTTNG_KERNEL_CAPTURE                   _IO(0xF6, 0xB8)
+
+/* Counter file descriptor ioctl */
+#define LTTNG_KERNEL_COUNTER_READ              \
+       _IOWR(0xF6, 0xC0, struct lttng_kernel_counter_read)
+#define LTTNG_KERNEL_COUNTER_AGGREGATE         \
+       _IOWR(0xF6, 0xC1, struct lttng_kernel_counter_aggregate)
+#define LTTNG_KERNEL_COUNTER_CLEAR             \
+       _IOW(0xF6, 0xC2, struct lttng_kernel_counter_clear)
+#define LTTNG_KERNEL_COUNTER_MAP_NR_DESCRIPTORS        \
+       _IOR(0xF6, 0xC3, uint64_t)
+#define LTTNG_KERNEL_COUNTER_MAP_DESCRIPTOR    \
+       _IOWR(0xF6, 0xC4, struct lttng_kernel_counter_map_descriptor)
+#define LTTNG_KERNEL_COUNTER_EVENT             \
+       _IOW(0xF6, 0xC5, struct lttng_kernel_counter_event)
+
+/* LTTNG_KERNEL_EVENT also applies to counter fds. */
+
 #endif /* _LTT_KERNEL_IOCTL_H */
diff --git a/src/common/kernel-function.c b/src/common/kernel-function.c
new file mode 100644 (file)
index 0000000..c0b1cef
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include "lttng/lttng-error.h"
+#include <assert.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/payload.h>
+#include <common/payload-view.h>
+#include <common/hashtable/hashtable.h>
+#include <common/hashtable/utils.h>
+#include <fcntl.h>
+#include <lttng/constant.h>
+#include <lttng/kernel-function.h>
+#include <lttng/kernel-function-internal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/unistd.h>
+
+static
+int lttng_kernel_function_location_address_serialize(
+               const struct lttng_kernel_function_location *location,
+               struct lttng_payload *payload);
+
+static
+int lttng_kernel_function_location_symbol_serialize(
+               const struct lttng_kernel_function_location *location,
+               struct lttng_payload *payload);
+
+static
+bool lttng_kernel_function_location_address_is_equal(
+               const struct lttng_kernel_function_location *a,
+               const struct lttng_kernel_function_location *b);
+
+static
+bool lttng_kernel_function_location_symbol_is_equal(
+               const struct lttng_kernel_function_location *a,
+               const struct lttng_kernel_function_location *b);
+
+static
+unsigned long lttng_kernel_function_location_address_hash(
+               const struct lttng_kernel_function_location *location);
+
+static
+unsigned long lttng_kernel_function_location_symbol_hash(
+               const struct lttng_kernel_function_location *location);
+
+enum lttng_kernel_function_location_type lttng_kernel_function_location_get_type(
+               const struct lttng_kernel_function_location *location)
+{
+       return location ? location->type :
+                       LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_UNKNOWN;
+}
+
+static
+void lttng_kernel_function_location_address_destroy(
+               struct lttng_kernel_function_location *location)
+{
+       assert(location);
+       free(location);
+}
+
+static
+void lttng_kernel_function_location_symbol_destroy(
+               struct lttng_kernel_function_location *location)
+{
+       struct lttng_kernel_function_location_symbol *location_symbol = NULL;
+
+       assert(location);
+
+       location_symbol = container_of(location,
+                       struct lttng_kernel_function_location_symbol,
+                       parent);
+
+       assert(location_symbol);
+
+       free(location_symbol->symbol_name);
+       free(location);
+}
+
+void lttng_kernel_function_location_destroy(
+               struct lttng_kernel_function_location *location)
+{
+       if (!location) {
+               return;
+       }
+
+       switch (location->type) {
+       case LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_ADDRESS:
+               lttng_kernel_function_location_address_destroy(location);
+               break;
+       case LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_SYMBOL_OFFSET:
+               lttng_kernel_function_location_symbol_destroy(location);
+               break;
+       default:
+               abort();
+       }
+}
+
+struct lttng_kernel_function_location *
+lttng_kernel_function_location_address_create(uint64_t address)
+{
+       struct lttng_kernel_function_location *ret = NULL;
+       struct lttng_kernel_function_location_address *location;
+
+       location = zmalloc(sizeof(*location));
+       if (!location) {
+               PERROR("Error allocating userspace function location.");
+               goto end;
+       }
+
+       location->address = address;
+
+       ret = &location->parent;
+       ret->type = LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_ADDRESS;
+       ret->equal = lttng_kernel_function_location_address_is_equal;
+       ret->serialize = lttng_kernel_function_location_address_serialize;
+       ret->hash = lttng_kernel_function_location_address_hash;
+
+end:
+       return ret;
+}
+
+struct lttng_kernel_function_location *
+lttng_kernel_function_location_symbol_create(const char *symbol_name,
+               uint64_t offset)
+{
+       char *symbol_name_copy = NULL;
+       struct lttng_kernel_function_location *ret = NULL;
+       struct lttng_kernel_function_location_symbol *location;
+
+       if (!symbol_name || strlen(symbol_name) >= LTTNG_SYMBOL_NAME_LEN) {
+               goto error;
+       }
+
+       symbol_name_copy = strdup(symbol_name);
+       if (!symbol_name_copy) {
+               PERROR("Failed to copy symbol name '%s'", symbol_name);
+               goto error;
+       }
+
+       location = zmalloc(sizeof(*location));
+       if (!location) {
+               PERROR("Failed to allocate kernel symbol function location");
+               goto error;
+       }
+
+       location->symbol_name = symbol_name_copy;
+       location->offset = offset;
+
+       ret = &location->parent;
+       ret->type = LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_SYMBOL_OFFSET;
+       ret->equal = lttng_kernel_function_location_symbol_is_equal;
+       ret->serialize = lttng_kernel_function_location_symbol_serialize;
+       ret->hash = lttng_kernel_function_location_symbol_hash;
+       goto end;
+
+error:
+       free(symbol_name_copy);
+end:
+       return ret;
+}
+
+enum lttng_kernel_function_location_status
+lttng_kernel_function_location_address_get_address(
+               const struct lttng_kernel_function_location *location,
+               uint64_t *offset)
+{
+       enum lttng_kernel_function_location_status ret =
+                       LTTNG_KERNEL_FUNCTION_LOCATION_STATUS_OK;
+       struct lttng_kernel_function_location_address *address_location;
+
+       assert(offset);
+
+       if (!location || lttng_kernel_function_location_get_type(location) !=
+                       LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_ADDRESS) {
+               ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
+               ret = LTTNG_KERNEL_FUNCTION_LOCATION_STATUS_INVALID;
+               goto end;
+       }
+
+       address_location = container_of(location,
+                       struct lttng_kernel_function_location_address, parent);
+       *offset = address_location->address;
+end:
+       return ret;
+}
+
+const char *lttng_kernel_function_location_symbol_get_name(
+               const struct lttng_kernel_function_location *location)
+{
+       const char *ret = NULL;
+       struct lttng_kernel_function_location_symbol *symbol_location;
+
+       if (!location || lttng_kernel_function_location_get_type(location) !=
+                       LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_SYMBOL_OFFSET) {
+               ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
+               goto end;
+       }
+
+       symbol_location = container_of(location,
+                       struct lttng_kernel_function_location_symbol, parent);
+       ret = symbol_location->symbol_name;
+end:
+       return ret;
+}
+
+enum lttng_kernel_function_location_status
+lttng_kernel_function_location_symbol_get_offset(
+               const struct lttng_kernel_function_location *location,
+               uint64_t *offset)
+{
+       enum lttng_kernel_function_location_status ret =
+                       LTTNG_KERNEL_FUNCTION_LOCATION_STATUS_OK;
+       struct lttng_kernel_function_location_symbol *symbol_location;
+
+       assert(offset);
+
+       if (!location || lttng_kernel_function_location_get_type(location) !=
+                       LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_SYMBOL_OFFSET) {
+               ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
+               ret = LTTNG_KERNEL_FUNCTION_LOCATION_STATUS_INVALID;
+               goto end;
+       }
+
+       symbol_location = container_of(location,
+                       struct lttng_kernel_function_location_symbol, parent);
+       *offset = symbol_location->offset;
+end:
+       return ret;
+}
+
+static
+int lttng_kernel_function_location_symbol_serialize(
+               const struct lttng_kernel_function_location *location,
+               struct lttng_payload *payload)
+{
+       int ret;
+       size_t symbol_name_len;
+       size_t original_payload_size;
+       struct lttng_kernel_function_location_symbol *location_symbol;
+       struct lttng_kernel_function_location_symbol_comm location_symbol_comm;
+
+       if (!location || !payload) {
+               ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       assert(lttng_kernel_function_location_get_type(location) ==
+                       LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_SYMBOL_OFFSET);
+
+       original_payload_size = payload->buffer.size;
+       location_symbol = container_of(location,
+                       struct lttng_kernel_function_location_symbol, parent);
+
+       if (!location_symbol->symbol_name) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       symbol_name_len = strlen(location_symbol->symbol_name);
+       if (symbol_name_len == 0) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       location_symbol_comm.symbol_len = symbol_name_len + 1;
+       location_symbol_comm.offset = location_symbol->offset;
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                       &location_symbol_comm, sizeof(location_symbol_comm));
+       if (ret) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                       location_symbol->symbol_name,
+                       location_symbol_comm.symbol_len);
+       if (ret) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = (int) (payload->buffer.size - original_payload_size);
+end:
+       return ret;
+}
+
+static
+int lttng_kernel_function_location_address_serialize(
+               const struct lttng_kernel_function_location *location,
+               struct lttng_payload *payload)
+{
+       int ret;
+       size_t original_payload_size;
+       struct lttng_kernel_function_location_address *location_address;
+       struct lttng_kernel_function_location_address_comm location_address_comm;
+
+       assert(location);
+       assert(lttng_kernel_function_location_get_type(location) ==
+                       LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_ADDRESS);
+
+       original_payload_size = payload->buffer.size;
+       location_address = container_of(location,
+                       struct lttng_kernel_function_location_address,
+                       parent);
+
+       location_address_comm.address = location_address->address;
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                       &location_address_comm,
+                       sizeof(location_address_comm));
+       if (ret) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = (int) (payload->buffer.size - original_payload_size);
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_kernel_function_location_serialize(
+               const struct lttng_kernel_function_location *location,
+               struct lttng_payload *payload)
+{
+       int ret;
+       size_t original_payload_size;
+       struct lttng_kernel_function_location_comm location_generic_comm = {};
+
+       if (!location || !payload) {
+               ERR("Invalid argument(s) passed to '%s'", __FUNCTION__);
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       original_payload_size = payload->buffer.size;
+       location_generic_comm.type = (int8_t) location->type;
+       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                       &location_generic_comm,
+                       sizeof(location_generic_comm));
+       if (ret) {
+               goto end;
+       }
+
+       ret = location->serialize(location, payload);
+       if (ret < 0) {
+               goto end;
+       }
+
+       ret = (int) (payload->buffer.size - original_payload_size);
+end:
+       return ret;
+}
+
+static
+int lttng_kernel_function_location_symbol_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_kernel_function_location **location)
+{
+       struct lttng_kernel_function_location_symbol_comm *location_symbol_comm;
+       const char *symbol_name_src;
+       ssize_t ret = 0;
+       size_t expected_size;
+
+       assert(location);
+
+       if (view->buffer.size < sizeof(*location_symbol_comm)) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       location_symbol_comm =
+                       (typeof(location_symbol_comm)) view->buffer.data;
+
+       expected_size = sizeof(*location_symbol_comm) +
+                       location_symbol_comm->symbol_len;
+
+       if (view->buffer.size < expected_size) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       symbol_name_src = view->buffer.data + sizeof(*location_symbol_comm);
+
+       if (!lttng_buffer_view_contains_string(&view->buffer, symbol_name_src,
+                       location_symbol_comm->symbol_len)) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       *location = lttng_kernel_function_location_symbol_create(
+                       symbol_name_src, location_symbol_comm->offset);
+       if (!(*location)) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = (ssize_t) expected_size;
+end:
+       return ret;
+}
+
+static
+ssize_t lttng_kernel_function_location_address_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_kernel_function_location **location)
+{
+       struct lttng_kernel_function_location_address_comm *location_address_comm;
+       ssize_t ret = 0;
+       size_t expected_size;
+
+       assert(location);
+
+       expected_size = sizeof(*location_address_comm);
+
+       if (view->buffer.size < expected_size) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       location_address_comm =
+                       (typeof(location_address_comm)) view->buffer.data;
+
+       *location = lttng_kernel_function_location_address_create(location_address_comm->address);
+       if (!(*location)) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = (size_t) expected_size;
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_kernel_function_location_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_kernel_function_location **location)
+{
+       enum lttng_kernel_function_location_type type;
+       ssize_t consumed = 0;
+       ssize_t ret;
+       const struct lttng_kernel_function_location_comm *function_location_comm;
+       const struct lttng_payload_view function_location_comm_view =
+                       lttng_payload_view_from_view(
+                                       view, 0, sizeof(*function_location_comm));
+
+       assert(view);
+       assert(location);
+
+       if (!lttng_payload_view_is_valid(&function_location_comm_view)) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       function_location_comm = (typeof(function_location_comm)) function_location_comm_view.buffer.data;
+       type = (enum lttng_kernel_function_location_type) function_location_comm->type;
+       consumed += sizeof(*function_location_comm);
+
+       switch (type) {
+       case LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_SYMBOL_OFFSET:
+       {
+               struct lttng_payload_view location_view =
+                               lttng_payload_view_from_view(
+                                               view, consumed, -1);
+
+               ret = lttng_kernel_function_location_symbol_create_from_payload(
+                               &location_view, location);
+               break;
+       }
+       case LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_ADDRESS:
+       {
+               struct lttng_payload_view location_view =
+                               lttng_payload_view_from_view(view, consumed, -1);
+
+               ret = lttng_kernel_function_location_address_create_from_payload(
+                               &location_view, location);
+               break;
+       }
+       default:
+               ret = -LTTNG_ERR_INVALID;
+               break;
+       }
+
+       if (ret < 0) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret += consumed;
+
+end:
+       return ret;
+}
+
+static
+unsigned long lttng_kernel_function_location_address_hash(
+               const struct lttng_kernel_function_location *location)
+{
+       unsigned long hash = hash_key_ulong(
+                       (void *) LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_ADDRESS,
+                       lttng_ht_seed);
+       struct lttng_kernel_function_location_address *address_location =
+                       container_of(location, typeof(*address_location),
+                               parent);
+
+       hash ^= hash_key_u64(&address_location->address, lttng_ht_seed);
+
+       return hash;
+}
+
+static
+bool lttng_kernel_function_location_address_is_equal(
+               const struct lttng_kernel_function_location *_a,
+               const struct lttng_kernel_function_location *_b)
+{
+       bool is_equal = false;
+       struct lttng_kernel_function_location_address *a, *b;
+
+       a = container_of(_a, struct lttng_kernel_function_location_address,
+                       parent);
+       b = container_of(_b, struct lttng_kernel_function_location_address,
+                       parent);
+
+       if (a->address != b->address) {
+               goto end;
+       }
+
+       is_equal = true;
+
+end:
+       return is_equal;
+}
+
+static
+unsigned long lttng_kernel_function_location_symbol_hash(
+               const struct lttng_kernel_function_location *location)
+{
+       unsigned long hash = hash_key_ulong(
+                       (void *) LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_SYMBOL_OFFSET,
+                       lttng_ht_seed);
+       struct lttng_kernel_function_location_symbol *symbol_location =
+                       container_of(location, typeof(*symbol_location),
+                               parent);
+
+       hash ^= hash_key_str(symbol_location->symbol_name, lttng_ht_seed);
+       hash ^= hash_key_u64(&symbol_location->offset, lttng_ht_seed);
+
+       return hash;
+}
+
+static
+bool lttng_kernel_function_location_symbol_is_equal(
+               const struct lttng_kernel_function_location *_a,
+               const struct lttng_kernel_function_location *_b)
+{
+       bool is_equal = false;
+       struct lttng_kernel_function_location_symbol *a, *b;
+
+       a = container_of(_a, struct lttng_kernel_function_location_symbol,
+                       parent);
+       b = container_of(_b, struct lttng_kernel_function_location_symbol,
+                       parent);
+
+       assert(a->symbol_name);
+       assert(b->symbol_name);
+       if (strcmp(a->symbol_name, b->symbol_name)) {
+               goto end;
+       }
+
+       if (a->offset != b->offset) {
+               goto end;
+       }
+
+       is_equal = true;
+
+end:
+       return is_equal;
+}
+
+LTTNG_HIDDEN
+bool lttng_kernel_function_location_is_equal(
+               const struct lttng_kernel_function_location *a,
+               const struct lttng_kernel_function_location *b)
+{
+       bool is_equal = false;
+
+       if (!a || !b) {
+               goto end;
+       }
+
+       if (a == b) {
+               is_equal = true;
+               goto end;
+       }
+
+       if (a->type != b->type) {
+               goto end;
+       }
+
+       is_equal = a->equal ? a->equal(a, b) : true;
+end:
+       return is_equal;
+}
+
+static struct lttng_kernel_function_location *
+lttng_kernel_function_location_symbol_copy(
+               const struct lttng_kernel_function_location *location)
+{
+       struct lttng_kernel_function_location *new_location = NULL;
+       struct lttng_kernel_function_location_symbol *symbol_location;
+       enum lttng_kernel_function_location_status status;
+       const char *symbol_name = NULL;
+       uint64_t offset;
+
+       assert(location);
+       assert(location->type == LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_SYMBOL_OFFSET);
+       symbol_location = container_of(
+                       location, typeof(*symbol_location), parent);
+
+        /* Get function location offset */
+       status = lttng_kernel_function_location_symbol_get_offset(location, &offset);
+       if (status != LTTNG_KERNEL_FUNCTION_LOCATION_STATUS_OK) {
+               ERR("Get kernel function location offset failed.");
+               goto error;
+       }
+
+       symbol_name = lttng_kernel_function_location_symbol_get_name(location);
+       if (!symbol_name) {
+               ERR("Kernel function symbol name is NULL.");
+               goto error;
+       }
+
+       /* Create the function_location */
+       new_location = lttng_kernel_function_location_symbol_create(
+                       symbol_name, offset);
+
+       goto end;
+
+error:
+       new_location = NULL;
+end:
+       return new_location;
+}
+static struct lttng_kernel_function_location *
+lttng_kernel_function_location_address_copy(
+               const struct lttng_kernel_function_location *location)
+{
+       struct lttng_kernel_function_location *new_location = NULL;
+       struct lttng_kernel_function_location_address *address_location;
+       enum lttng_kernel_function_location_status status;
+       uint64_t address;
+
+       assert(location);
+       assert(location->type == LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_ADDRESS);
+       address_location = container_of(
+                       location, typeof(*address_location), parent);
+
+
+        /* Get function location fields */
+       status = lttng_kernel_function_location_address_get_address(location, &address);
+       if (status != LTTNG_KERNEL_FUNCTION_LOCATION_STATUS_OK) {
+               ERR("Get kernel function address failed.");
+               goto error;
+       }
+
+       /* Create the function_location */
+       new_location = lttng_kernel_function_location_address_create(address);
+
+       goto end;
+
+error:
+       new_location = NULL;
+end:
+       return new_location;
+}
+
+LTTNG_HIDDEN
+struct lttng_kernel_function_location *lttng_kernel_function_location_copy(
+               const struct lttng_kernel_function_location *location)
+{
+       struct lttng_kernel_function_location *new_location = NULL;
+       enum lttng_kernel_function_location_type type;
+
+       if (!location) {
+               goto err;
+       }
+
+       type = lttng_kernel_function_location_get_type(location);
+       switch (type) {
+       case LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_ADDRESS:
+               new_location =
+                       lttng_kernel_function_location_address_copy(location);
+               if (!new_location) {
+                       goto err;
+               }
+               break;
+       case LTTNG_KERNEL_FUNCTION_LOCATION_TYPE_SYMBOL_OFFSET:
+               new_location =
+                       lttng_kernel_function_location_symbol_copy(location);
+               if (!new_location) {
+                       goto err;
+               }
+               break;
+       default:
+               new_location = NULL;
+               goto err;
+       }
+err:
+       return new_location;
+}
+
+LTTNG_HIDDEN
+unsigned long lttng_kernel_function_location_hash(
+       const struct lttng_kernel_function_location *location)
+{
+       return location->hash(location);
+}
diff --git a/src/common/log-level-rule.c b/src/common/log-level-rule.c
new file mode 100644 (file)
index 0000000..b5d0e9d
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <common/dynamic-buffer.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/hashtable/hashtable.h>
+#include <common/hashtable/utils.h>
+#include <lttng/log-level-rule-internal.h>
+#include <lttng/log-level-rule.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+static bool is_log_level_rule_exactly_type(const struct lttng_log_level_rule *rule)
+{
+       enum lttng_log_level_rule_type type =
+                       lttng_log_level_rule_get_type(rule);
+
+       return type == LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY;
+}
+
+static bool is_log_level_rule_at_least_as_severe_type(const struct lttng_log_level_rule *rule)
+{
+
+       enum lttng_log_level_rule_type type =
+                       lttng_log_level_rule_get_type(rule);
+
+       return type == LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS;
+}
+
+enum lttng_log_level_rule_type lttng_log_level_rule_get_type(
+               const struct lttng_log_level_rule *rule)
+{
+       return rule ? rule->type : LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN;
+}
+
+struct lttng_log_level_rule *lttng_log_level_rule_exactly_create(
+               int level)
+{
+       struct lttng_log_level_rule *rule = NULL;
+
+       rule = zmalloc(sizeof(struct lttng_log_level_rule));
+       if (!rule) {
+               goto end;
+       }
+
+       rule->type = LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY;
+       rule->level = level;
+
+end:
+       return rule;
+}
+
+enum lttng_log_level_rule_status lttng_log_level_rule_exactly_get_level(
+               const struct lttng_log_level_rule *rule, int *level)
+{
+       enum lttng_log_level_rule_status status = LTTNG_LOG_LEVEL_RULE_STATUS_OK;
+       if (!rule || !level || !is_log_level_rule_exactly_type(rule)) {
+               status = LTTNG_LOG_LEVEL_RULE_STATUS_INVALID;
+               goto end;
+       }
+
+       *level = rule->level;
+end:
+       return status;
+}
+
+struct lttng_log_level_rule *
+lttng_log_level_rule_at_least_as_severe_as_create(int level)
+{
+       struct lttng_log_level_rule *rule = NULL;
+
+       rule = zmalloc(sizeof(struct lttng_log_level_rule));
+       if (!rule) {
+               goto end;
+       }
+
+       rule->type = LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS;
+       rule->level = level;
+
+end:
+       return rule;
+}
+
+enum lttng_log_level_rule_status
+lttng_log_level_rule_at_least_as_severe_as_get_level(
+               const struct lttng_log_level_rule *rule, int *level)
+{
+       enum lttng_log_level_rule_status status = LTTNG_LOG_LEVEL_RULE_STATUS_OK;
+       if (!rule || !level || !is_log_level_rule_at_least_as_severe_type(rule)) {
+               status = LTTNG_LOG_LEVEL_RULE_STATUS_INVALID;
+               goto end;
+       }
+
+       *level = rule->level;
+end:
+       return status;
+}
+
+void lttng_log_level_rule_destroy(struct lttng_log_level_rule *log_level_rule)
+{
+       free(log_level_rule);
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_log_level_rule_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_log_level_rule **_rule)
+{
+       ssize_t ret;
+       size_t offset = 0;
+       struct lttng_log_level_rule *rule = NULL;
+       const struct lttng_log_level_rule_comm *comm =
+                       (const struct lttng_log_level_rule_comm *)
+                                       view->buffer.data;
+
+       offset += sizeof(*comm);
+
+       if (!_rule) {
+               ret = -1;
+               goto end;
+       }
+
+       if (view->buffer.size < sizeof(*comm)) {
+               ret = -1;
+               goto end;
+       }
+
+       switch (comm->type) {
+       case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+               rule = lttng_log_level_rule_exactly_create((int) comm->level);
+               break;
+       case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+               rule = lttng_log_level_rule_at_least_as_severe_as_create(
+                               (int) comm->level);
+               break;
+       default:
+               abort();
+       }
+       
+       if (!rule) {
+               ret = -1;
+               goto end;
+       }
+
+       *_rule = rule;
+       ret = offset;
+
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_log_level_rule_serialize(const struct lttng_log_level_rule *rule,
+               struct lttng_payload *payload)
+{
+       int ret;
+       struct lttng_log_level_rule_comm comm;
+
+
+       if (!rule) {
+               ret = 0;
+               goto end;
+       }
+
+       comm.type = (int8_t) rule->type;
+       comm.level = (int32_t) rule->level;
+
+       DBG("Serializing log level rule of type %d", rule->type);
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &comm,
+                       sizeof(comm));
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+bool lttng_log_level_rule_is_equal(const struct lttng_log_level_rule *a,
+               const struct lttng_log_level_rule *b)
+{
+       bool is_equal = false;
+
+       if (a == NULL && b == NULL) {
+               /* Both are null. */
+               is_equal = true;
+               goto end;
+       }
+
+       if (a == NULL || b == NULL) {
+               /* One is NULL.*/
+               goto end;
+       }
+
+       if (a == b) {
+               /* Same object.*/
+               is_equal = true;
+               goto end;
+       }
+
+       if (a->type != b->type) {
+               goto end;
+       }
+
+       if (a->level != b->level) {
+               goto end;
+       }
+
+       is_equal = true;
+
+end:
+       return is_equal;
+}
+
+LTTNG_HIDDEN
+struct lttng_log_level_rule * lttng_log_level_rule_copy(const struct lttng_log_level_rule *source)
+{
+       struct lttng_log_level_rule *copy = NULL;
+
+       assert(source);
+
+       copy = zmalloc(sizeof(struct lttng_log_level_rule));
+       if (!copy) {
+               goto end;
+       }
+
+       copy->type = source->type;
+       copy->level = source->level;
+end:
+       return copy;
+}
+
+LTTNG_HIDDEN
+void lttng_log_level_rule_to_loglevel(
+               const struct lttng_log_level_rule *log_level_rule,
+               enum lttng_loglevel_type *loglevel_type,
+               int *loglevel_value)
+{
+       assert(log_level_rule);
+
+       switch(log_level_rule->type)
+       {
+       case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+               *loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE;
+               break;
+       case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+               *loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE;
+               break;
+       default:
+               abort();
+       }
+
+       *loglevel_value = log_level_rule->level;
+}
+
+LTTNG_HIDDEN
+unsigned long lttng_log_level_rule_hash(
+               const struct lttng_log_level_rule *log_level_rule)
+{
+       unsigned long hash;
+       enum lttng_log_level_rule_status llr_status;
+       int log_level_value;
+       enum lttng_log_level_rule_type type;
+
+       assert(log_level_rule);
+
+       type = lttng_log_level_rule_get_type(log_level_rule);
+
+       switch (type) {
+       case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+               llr_status = lttng_log_level_rule_exactly_get_level(
+                               log_level_rule, &log_level_value);
+               break;
+       case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+               llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level(
+                               log_level_rule, &log_level_value);
+               break;
+       default:
+               abort();
+               break;
+       }
+
+       assert(llr_status == LTTNG_LOG_LEVEL_RULE_STATUS_OK);
+
+       hash = hash_key_ulong((void *) (unsigned long) type, lttng_ht_seed);
+
+       hash ^= hash_key_ulong((void *) (unsigned long) log_level_value,
+                       lttng_ht_seed);
+
+       return hash;
+}
index cd343bb766c81ea39f7f2ae8dbcd6de058954679..343d68dab2735e39acf2135183cfa550d007961d 100644 (file)
@@ -178,18 +178,140 @@ struct lttng_kernel_event {
        } u;
 } LTTNG_PACKED;
 
-#define LTTNG_KERNEL_EVENT_NOTIFIER_PADDING    40
+#define LTTNG_KERNEL_EVENT_NOTIFIER_PADDING    32
 struct lttng_kernel_event_notifier {
        struct lttng_kernel_event event;
+       uint64_t error_counter_idx;
+
        char padding[LTTNG_KERNEL_EVENT_NOTIFIER_PADDING];
 } LTTNG_PACKED;
 
-#define LTTNG_KERNEL_EVENT_NOTIFIER_NOTIFICATION_PADDING 34
+enum lttng_kernel_key_token_type {
+       LTTNG_KERNEL_KEY_TOKEN_STRING = 0,      /* arg: strtab_offset. */
+       LTTNG_KERNEL_KEY_TOKEN_EVENT_NAME = 1,  /* no arg. */
+};
+
+#define LTTNG_KERNEL_KEY_ARG_PADDING1          60
+#define LTTNG_KERNEL_KEY_TOKEN_STRING_LEN_MAX  256
+struct lttng_kernel_key_token {
+       uint32_t type;  /* enum lttng_kernel_key_token_type */
+       union {
+               uint64_t string_ptr;
+               char padding[LTTNG_KERNEL_KEY_ARG_PADDING1];
+       } arg;
+} LTTNG_PACKED;
+
+#define LTTNG_KERNEL_NR_KEY_TOKEN 4
+struct lttng_kernel_counter_key_dimension {
+       uint32_t nr_key_tokens;
+       struct lttng_kernel_key_token key_tokens[LTTNG_KERNEL_NR_KEY_TOKEN];
+} LTTNG_PACKED;
+
+#define LTTNG_KERNEL_COUNTER_DIMENSION_MAX 4
+struct lttng_kernel_counter_key {
+       uint32_t nr_dimensions;
+       struct lttng_kernel_counter_key_dimension key_dimensions[LTTNG_KERNEL_COUNTER_DIMENSION_MAX];
+} LTTNG_PACKED;
+
+#define LTTNG_KERNEL_COUNTER_EVENT_PADDING1    16
+struct lttng_kernel_counter_event {
+       struct lttng_kernel_event event;
+       struct lttng_kernel_counter_key key;
+       char padding[LTTNG_KERNEL_COUNTER_EVENT_PADDING1];
+} LTTNG_PACKED;
+
+enum lttng_kernel_counter_arithmetic {
+       LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR = 0,
+};
+
+enum lttng_kernel_counter_bitness {
+       LTTNG_KERNEL_COUNTER_BITNESS_32 = 0,
+       LTTNG_KERNEL_COUNTER_BITNESS_64 = 1,
+};
+
+struct lttng_kernel_counter_dimension {
+       uint64_t size;
+       uint64_t underflow_index;
+       uint64_t overflow_index;
+       uint8_t has_underflow;
+       uint8_t has_overflow;
+} LTTNG_PACKED;
+
+#define LTTNG_KERNEL_COUNTER_CONF_PADDING1      67
+struct lttng_kernel_counter_conf {
+       uint32_t arithmetic;    /* enum lttng_kernel_counter_arithmetic */
+       uint32_t bitness;       /* enum lttng_kernel_counter_bitness */
+       uint32_t number_dimensions;
+       int64_t global_sum_step;
+       struct lttng_kernel_counter_dimension dimensions[LTTNG_KERNEL_COUNTER_DIMENSION_MAX];
+       uint8_t coalesce_hits;
+       char padding[LTTNG_KERNEL_COUNTER_CONF_PADDING1];
+} LTTNG_PACKED;
+
+struct lttng_kernel_counter_index {
+       uint32_t number_dimensions;
+       uint64_t dimension_indexes[LTTNG_KERNEL_COUNTER_DIMENSION_MAX];
+} LTTNG_PACKED;
+
+struct lttng_kernel_counter_value {
+       int64_t value;
+       uint8_t underflow;
+       uint8_t overflow;
+} LTTNG_PACKED;
+
+#define LTTNG_KERNEL_COUNTER_READ_PADDING 32
+struct lttng_kernel_counter_read {
+       struct lttng_kernel_counter_index index;
+       int32_t cpu;    /* -1 for global counter, >= 0 for specific cpu. */
+       struct lttng_kernel_counter_value value;        /* output */
+       char padding[LTTNG_KERNEL_COUNTER_READ_PADDING];
+} LTTNG_PACKED;
+
+#define LTTNG_KERNEL_COUNTER_AGGREGATE_PADDING 32
+struct lttng_kernel_counter_aggregate {
+       struct lttng_kernel_counter_index index;
+       struct lttng_kernel_counter_value value;        /* output */
+       char padding[LTTNG_KERNEL_COUNTER_AGGREGATE_PADDING];
+} LTTNG_PACKED;
+
+#define LTTNG_KERNEL_COUNTER_CLEAR_PADDING 32
+struct lttng_kernel_counter_clear {
+       struct lttng_kernel_counter_index index;
+       char padding[LTTNG_KERNEL_COUNTER_CLEAR_PADDING];
+} LTTNG_PACKED;
+
+#define LTTNG_KERNEL_COUNTER_MAP_NR_DESCRIPTORS_PADDING 32
+struct lttng_kernel_counter_map_nr_descriptors {
+       uint64_t nr_descriptors;
+};
+
+#define LTTNG_KERNEL_COUNTER_KEY_LEN 256
+#define LTTNG_KERNEL_COUNTER_MAP_DESCRIPTOR_PADDING 32
+struct lttng_kernel_counter_map_descriptor {
+       uint64_t descriptor_index;      /* input. [ 0 .. nr_descriptors - 1 ] */
+       uint32_t dimension;             /* outputs */
+       uint64_t array_index;
+       uint64_t user_token;
+       char key[LTTNG_KERNEL_COUNTER_KEY_LEN];
+
+       char padding[LTTNG_KERNEL_COUNTER_MAP_DESCRIPTOR_PADDING];
+} LTTNG_PACKED;
+
+#define LTTNG_KERNEL_EVENT_NOTIFIER_NOTIFICATION_PADDING 32
 struct lttng_kernel_event_notifier_notification {
        uint64_t token;
+       uint16_t capture_buf_size;
        char padding[LTTNG_KERNEL_EVENT_NOTIFIER_NOTIFICATION_PADDING];
 } LTTNG_PACKED;
 
+#define LTTNG_KERNEL_CAPTURE_BYTECODE_MAX_LEN          65536
+struct lttng_kernel_capture_bytecode {
+       uint32_t len;
+       uint32_t reloc_offset;
+       uint64_t seqnum;
+       char data[0];
+} LTTNG_PACKED;
+
 struct lttng_kernel_tracer_version {
        uint32_t major;
        uint32_t minor;
diff --git a/src/common/map-key/map-key.c b/src/common/map-key/map-key.c
new file mode 100644 (file)
index 0000000..1cce2b1
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <common/dynamic-array.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/payload.h>
+#include <common/payload-view.h>
+
+#include <lttng/map-key.h>
+#include <lttng/map-key-internal.h>
+
+#define TOKEN_VAR_EVENT_NAME "EVENT_NAME"
+#define TOKEN_VAR_PROVIDER_NAME "PROVIDER_NAME"
+
+static
+void destroy_map_key_token(void *ptr)
+{
+       struct lttng_map_key_token *token = (struct lttng_map_key_token *) ptr;
+       switch (token->type) {
+       case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
+       {
+               struct lttng_map_key_token_string *token_string =
+                               (struct lttng_map_key_token_string *) token;
+               free(token_string->string);
+               break;
+       }
+       case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
+               break;
+       default:
+               abort();
+       }
+
+       free(token);
+}
+
+struct lttng_map_key *lttng_map_key_create(void)
+{
+        struct lttng_map_key *key = NULL;
+
+        key = zmalloc(sizeof(*key));
+        if (!key) {
+                return NULL;
+        }
+
+       urcu_ref_init(&key->ref);
+       lttng_dynamic_pointer_array_init(&key->tokens,
+                       destroy_map_key_token);
+
+       return key;
+}
+
+ssize_t lttng_map_key_create_from_payload(struct lttng_payload_view *src_view,
+               struct lttng_map_key **out_key)
+{
+       ssize_t ret, consumed_len;
+       uint32_t i;
+       const struct lttng_map_key_comm *comm;
+       struct lttng_map_key *key;
+
+       if (!src_view || !out_key) {
+               ret = -1;
+               goto end;
+       }
+
+       key = lttng_map_key_create();
+       if (!key) {
+               ret = -1;
+               goto end;
+       }
+
+       comm = (typeof(comm)) src_view->buffer.data;
+       consumed_len = sizeof(*comm);
+
+       assert(comm->token_count > 0);
+
+       for (i = 0; i < comm->token_count; i++) {
+               enum lttng_map_key_status key_status;
+               const struct lttng_map_key_token_comm *token_comm;
+               struct lttng_payload_view child_view =
+                               lttng_payload_view_from_view(src_view, consumed_len,
+                                               src_view->buffer.size - consumed_len);
+               if (!lttng_payload_view_is_valid(&child_view)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               token_comm = (const struct lttng_map_key_token_comm *) child_view.buffer.data;
+
+               switch (token_comm->type) {
+               case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
+               {
+                       const char *str_val;
+                       const struct lttng_map_key_token_string_comm *comm;
+
+                       comm = (typeof(comm)) token_comm;
+                       str_val = (const char *) &comm->payload;
+
+                       if (!lttng_buffer_view_contains_string(&child_view.buffer,
+                                       str_val, comm->string_len)) {
+                               ret = -1;
+                               goto end;
+                       }
+
+                       key_status = lttng_map_key_append_token_string(key, str_val);
+                       if (key_status != LTTNG_MAP_KEY_STATUS_OK) {
+                               ret = -1;
+                               goto end;
+                       }
+
+                       consumed_len += sizeof(*comm) + comm->string_len;
+
+                       break;
+               }
+               case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
+               {
+                       const struct lttng_map_key_token_variable_comm *comm;
+
+                       comm = (typeof(comm)) token_comm;
+                       key_status = lttng_map_key_append_token_variable(key,
+                                       comm->var_type);
+                       if (key_status != LTTNG_MAP_KEY_STATUS_OK) {
+                               ret = -1;
+                               goto end;
+                       }
+
+                       consumed_len += sizeof(*comm);
+                       break;
+               }
+               default:
+                       abort();
+               }
+       }
+
+       *out_key = key;
+       ret = consumed_len;
+end:
+       return ret;
+}
+
+int lttng_map_key_serialize(const struct lttng_map_key *key,
+               struct lttng_payload *payload)
+{
+       int ret;
+       uint32_t i, nb_tokens;
+       enum lttng_map_key_status key_status;
+       struct lttng_map_key_comm comm = {0};
+
+       DBG("Serializing map key");
+
+       key_status = lttng_map_key_get_token_count(key, &nb_tokens);
+       if (key_status != LTTNG_MAP_KEY_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       if (nb_tokens == 0) {
+               ERR("Map key token number is zero");
+               ret = -1;
+               goto end;
+       }
+
+       DBG("Serializing map key token count: %" PRIu32, nb_tokens);
+       comm.token_count = nb_tokens;
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &comm,
+                       sizeof(comm));
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < nb_tokens; i++) {
+               uint8_t token_type;
+               const struct lttng_map_key_token *token =
+                               lttng_map_key_get_token_at_index(key, i);
+               DBG("Serializing map key token's type: %d", token->type);
+
+               token_type = (uint8_t) token->type;
+
+               switch (token->type) {
+               case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
+               {
+                       struct lttng_map_key_token_string *str_token =
+                                       (struct lttng_map_key_token_string *) token;
+                       struct lttng_map_key_token_string_comm comm = {0};
+                       uint32_t len = strlen(str_token->string) + 1;
+
+                       DBG("Serializing a string type key token");
+                       comm.parent_type = token_type;
+                       comm.string_len = len;
+
+                       /* Serialize the length, include the null character */
+                       DBG("Serializing map key token string length (include null character):"
+                               "%" PRIu32, len);
+                       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                               &comm, sizeof(comm));
+                       if (ret) {
+                               goto end;
+                       }
+
+                       /* Serialize the string */
+                       DBG("Serializing map key token string's value: \"%s\"",
+                                       str_token->string);
+                       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                                       str_token->string, len);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       break;
+               }
+               case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
+               {
+                       struct lttng_map_key_token_variable *var_token =
+                                       (struct lttng_map_key_token_variable *) token;
+                       struct lttng_map_key_token_variable_comm comm = {0};
+
+                       DBG("Serializing a variable type key token");
+
+                       comm.parent_type = token_type;
+                       comm.var_type = var_token->type;
+
+                       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                                       &comm, sizeof(comm));
+                       if (ret) {
+                               goto end;
+                       }
+
+                       break;
+               }
+               default:
+                       abort();
+               }
+       }
+
+end:
+       return ret;
+}
+
+static inline
+bool token_variable_type_is_valid(enum lttng_map_key_token_variable_type var_type)
+{
+       switch (var_type) {
+       case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME:
+       case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool lttng_map_key_token_variable_is_equal(
+               const struct lttng_map_key_token *_a,
+               const struct lttng_map_key_token *_b)
+{
+       struct lttng_map_key_token_variable *a, *b;
+       assert(_a->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE);
+       assert(_b->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE);
+
+       a = container_of(_a, struct lttng_map_key_token_variable, parent);
+       b = container_of(_b, struct lttng_map_key_token_variable, parent);
+
+       return lttng_map_key_token_variable_get_type(a) ==
+                       lttng_map_key_token_variable_get_type(b);
+}
+
+enum lttng_map_key_status lttng_map_key_append_token_variable(
+               struct lttng_map_key *key,
+               enum lttng_map_key_token_variable_type var_type)
+{
+       int ret;
+       enum lttng_map_key_status status;
+       struct lttng_map_key_token_variable *token = NULL;
+
+       if (!token_variable_type_is_valid(var_type)) {
+               ERR("Invalid token variable type");
+               status = LTTNG_MAP_KEY_STATUS_INVALID;
+               goto end;
+       }
+
+       token = zmalloc(sizeof(*token));
+       if (!token) {
+               status = LTTNG_MAP_KEY_STATUS_ERROR;
+               goto end;
+       }
+
+       token->parent.type = LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE;
+       token->parent.equal = lttng_map_key_token_variable_is_equal;
+       token->type = var_type;
+
+       ret = lttng_dynamic_pointer_array_add_pointer(
+                       &key->tokens, token);
+       if (ret) {
+               status = LTTNG_MAP_KEY_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_KEY_STATUS_OK;
+
+end:
+       return status;
+}
+
+static bool lttng_map_key_token_string_is_equal(
+               const struct lttng_map_key_token *_a,
+               const struct lttng_map_key_token *_b)
+{
+       struct lttng_map_key_token_string *a, *b;
+       const char *a_string, *b_string;
+
+       assert(_a->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING);
+       assert(_b->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING);
+
+       a = container_of(_a, struct lttng_map_key_token_string, parent);
+       b = container_of(_b, struct lttng_map_key_token_string, parent);
+
+       a_string = lttng_map_key_token_string_get_string(a);
+       b_string = lttng_map_key_token_string_get_string(b);
+
+       return !strcmp(a_string, b_string);
+}
+
+enum lttng_map_key_status lttng_map_key_append_token_string(
+               struct lttng_map_key *key, const char *string)
+{
+       int ret;
+       enum lttng_map_key_status status;
+       struct lttng_map_key_token_string *token = NULL;
+
+
+       token = zmalloc(sizeof(*token));
+       if (!token) {
+               status = LTTNG_MAP_KEY_STATUS_ERROR;
+               goto end;
+       }
+
+       token->parent.type = LTTNG_MAP_KEY_TOKEN_TYPE_STRING;
+       token->parent.equal = lttng_map_key_token_string_is_equal;
+       token->string = strdup(string);
+       if (!token->string) {
+               status = LTTNG_MAP_KEY_STATUS_ERROR;
+               goto end;
+       }
+
+       ret = lttng_dynamic_pointer_array_add_pointer(
+                       &key->tokens, token);
+       if (ret) {
+               status = LTTNG_MAP_KEY_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_KEY_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_key_status lttng_map_key_get_token_count(
+               const struct lttng_map_key *key, unsigned int *count)
+{
+       enum lttng_map_key_status status;
+       if (!key || !count) {
+               status = LTTNG_MAP_KEY_STATUS_INVALID;
+               goto end;
+
+       }
+
+       *count = lttng_dynamic_pointer_array_get_count(
+                       &key->tokens);
+
+       status = LTTNG_MAP_KEY_STATUS_OK;
+end:
+       return status;
+}
+
+const struct lttng_map_key_token *
+lttng_map_key_get_token_at_index(const struct lttng_map_key *key,
+               unsigned int index)
+{
+       const struct lttng_map_key_token *token = NULL;
+       enum lttng_map_key_status status;
+       unsigned int count;
+
+       if (!key) {
+               goto end;
+       }
+
+       status = lttng_map_key_get_token_count(key, &count);
+       if (status != LTTNG_MAP_KEY_STATUS_OK) {
+               goto end;
+       }
+
+       if (index >= count) {
+               goto end;
+       }
+
+       token = lttng_dynamic_pointer_array_get_pointer(&key->tokens,
+                       index);
+
+end:
+       return token;
+}
+
+enum lttng_map_key_token_variable_type lttng_map_key_token_variable_get_type(
+               const struct lttng_map_key_token_variable *token)
+{
+       assert(token->parent.type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE);
+
+       return token->type;
+}
+
+const char *lttng_map_key_token_string_get_string(
+               const struct lttng_map_key_token_string *token)
+{
+       assert(token->parent.type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING);
+
+       return token->string;
+}
+
+void lttng_map_key_destroy(struct lttng_map_key *key)
+{
+       lttng_map_key_put(key);
+}
+
+LTTNG_HIDDEN
+struct lttng_map_key *lttng_map_key_parse_from_string(const char *_key_str)
+{
+       struct lttng_map_key *key = NULL;
+       enum lttng_map_key_status status;
+       char *key_str = NULL, *curr_pos;
+
+       key = lttng_map_key_create();
+       if (!key) {
+               goto end;
+       }
+
+       key_str = strdup(_key_str);
+
+       curr_pos = key_str;
+
+       curr_pos = strtok(curr_pos, "$}");
+       while (curr_pos) {
+               if (curr_pos[0] == '{') {
+                       if (strncmp(&curr_pos[1], TOKEN_VAR_EVENT_NAME, strlen(TOKEN_VAR_EVENT_NAME)) == 0) {
+                               status = lttng_map_key_append_token_variable(key,
+                                               LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME);
+                               if (status != LTTNG_MAP_KEY_STATUS_OK) {
+                                       goto error;
+                               }
+                       } else if (strncmp(&curr_pos[1], TOKEN_VAR_PROVIDER_NAME, strlen(TOKEN_VAR_PROVIDER_NAME)) == 0) {
+                               status = lttng_map_key_append_token_variable(key,
+                                               LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME);
+                               if (status != LTTNG_MAP_KEY_STATUS_OK) {
+                                       goto error;
+                               }
+                       } else {
+                               goto error;
+                       }
+               } else {
+                       status = lttng_map_key_append_token_string(key, curr_pos);
+                       if (status != LTTNG_MAP_KEY_STATUS_OK) {
+                               goto error;
+                       }
+               }
+               curr_pos = strtok(NULL, "$}");
+       }
+       goto end;
+
+error:
+       lttng_map_key_destroy(key);
+       key = NULL;
+end:
+       free(key_str);
+
+       return key;
+}
+
+LTTNG_HIDDEN
+bool lttng_map_key_is_equal(
+               const struct lttng_map_key *a, const struct lttng_map_key *b)
+{
+       bool is_equal = false;
+       enum lttng_map_key_status status;
+       unsigned int a_count, b_count, i;
+
+       if (!!a != !!b) {
+               goto end;
+       }
+
+       if (a == NULL && b == NULL) {
+               is_equal = true;
+               goto end;
+       }
+
+       if (a == b) {
+               is_equal = true;
+               goto end;
+       }
+
+       status = lttng_map_key_get_token_count(a, &a_count);
+       assert(status == LTTNG_MAP_KEY_STATUS_OK);
+       status = lttng_map_key_get_token_count(b, &b_count);
+       assert(status == LTTNG_MAP_KEY_STATUS_OK);
+
+       if (a_count != b_count) {
+               goto end;
+       }
+
+       for (i = 0; i < a_count; i++) {
+               const struct lttng_map_key_token *token_a = NULL, *token_b = NULL;
+
+               token_a = lttng_map_key_get_token_at_index(a, i);
+               token_b = lttng_map_key_get_token_at_index(b, i);
+
+               /* JORAJ TODO: is order important for the map key token? */
+               if(token_a->type != token_b->type) {
+                       goto end;
+               }
+
+               if(!token_a->equal(token_a, token_b)) {
+                       goto end;
+               }
+       }
+
+       is_equal = true;
+
+end:
+       return is_equal;
+
+
+}
+
+static void map_key_destroy_ref(struct urcu_ref *ref)
+{
+       struct lttng_map_key *key = container_of(ref, struct lttng_map_key, ref);
+
+       lttng_dynamic_pointer_array_reset(&key->tokens);
+       free(key);
+}
+
+LTTNG_HIDDEN
+void lttng_map_key_get(struct lttng_map_key *key)
+{
+       urcu_ref_get(&key->ref);
+}
+
+LTTNG_HIDDEN
+void lttng_map_key_put(struct lttng_map_key *key)
+{
+       if (!key) {
+               return;
+       }
+
+       urcu_ref_put(&key->ref, map_key_destroy_ref);
+}
diff --git a/src/common/map-query.c b/src/common/map-query.c
new file mode 100644 (file)
index 0000000..f25001f
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/optional.h>
+#include <common/payload.h>
+
+#include <lttng/map/map-query-internal.h>
+
+struct lttng_map_query *lttng_map_query_create(
+               enum lttng_map_query_config_cpu cpu,
+               enum lttng_map_query_config_buffer buffer,
+               enum lttng_map_query_config_app_bitness bitness)
+{
+       struct lttng_map_query *query = NULL;
+
+       if ((buffer == LTTNG_MAP_QUERY_CONFIG_BUFFER_KERNEL_GLOBAL) ^
+                       (bitness == LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_KERNEL)) {
+               /*
+                * If any of the buffer or bitness config is set to kernel,
+                * they other has to as well.
+                */
+               goto end;
+       }
+
+       if (bitness != LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_ALL &&
+                       bitness != LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_KERNEL) {
+               /* We currently don't support targetting a specific bitness. */
+               goto end;
+       }
+
+       query = zmalloc(sizeof(struct lttng_map_query));
+       if (!query) {
+               goto end;
+       }
+
+       query->config_cpu = cpu;
+       query->config_buffer = buffer;
+       query->config_bitness = bitness;
+
+       query->sum_by_uid = false;
+       query->sum_by_pid = false;
+       query->sum_by_cpu = false;
+       // defaults to true for now.
+       query->sum_by_app_bitness = true;
+
+       if (query->config_cpu == LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+               lttng_dynamic_array_init(&query->cpu_array, sizeof(int), NULL);
+       }
+
+       switch(query->config_buffer) {
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET:
+               lttng_dynamic_array_init(&query->uid_array, sizeof(uid_t), NULL);
+               break;
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_SUBSET:
+               lttng_dynamic_array_init(&query->pid_array, sizeof(pid_t), NULL);
+               break;
+       default:
+               break;
+       }
+end:
+       return query;
+}
+
+enum lttng_map_query_status lttng_map_query_set_sum_by_cpu(
+       struct lttng_map_query *query, bool sum_by_cpu)
+{
+       query->sum_by_cpu = sum_by_cpu;
+
+       return LTTNG_MAP_QUERY_STATUS_OK;
+}
+
+enum lttng_map_query_status lttng_map_query_set_sum_by_app_bitness(
+       struct lttng_map_query *query, bool sum_by_app_bitness)
+{
+       enum lttng_map_query_status status;
+
+       if (query->config_bitness != LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_ALL) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       query->sum_by_app_bitness = sum_by_app_bitness;
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+
+end:
+       return status;
+}
+
+enum lttng_map_query_status lttng_map_query_set_sum_by_pid(
+       struct lttng_map_query *query, bool sum_by_pid)
+{
+       enum lttng_map_query_status status;
+
+       switch (query->config_buffer) {
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_ALL:
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_SUBSET:
+               break;
+       default:
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       query->sum_by_pid = sum_by_pid;
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+
+end:
+       return status;
+}
+
+enum lttng_map_query_status lttng_map_query_set_sum_by_uid(
+               struct lttng_map_query *query, bool sum_by_uid)
+{
+       enum lttng_map_query_status status;
+
+       switch (query->config_buffer) {
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_ALL:
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET:
+               break;
+       default:
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       query->sum_by_uid = sum_by_uid;
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+
+end:
+       return status;
+}
+
+enum lttng_map_query_status lttng_map_query_add_cpu(
+               struct lttng_map_query *query, int cpu_id)
+{
+       enum lttng_map_query_status status;
+       unsigned int cpu_count;
+       int ret;
+
+       if (query->config_cpu != LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       lttng_map_query_get_cpu_count(query, &cpu_count);
+       if (cpu_count > 0) {
+               ERR("Only one CPU can be targeted in a query at the moment");
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       ret = lttng_dynamic_array_add_element(&query->cpu_array, &cpu_id);
+       if (ret) {
+               status = LTTNG_MAP_QUERY_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_query_status lttng_map_query_add_uid(
+       struct lttng_map_query *query, uid_t uid)
+{
+       int ret;
+       unsigned int uid_count;
+       enum lttng_map_query_status status;
+
+       if (query->config_buffer != LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       lttng_map_query_get_uid_count(query, &uid_count);
+       if (uid_count > 0) {
+               ERR("Only one UID can be targeted in a query at the moment");
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       ret = lttng_dynamic_array_add_element(&query->uid_array, &uid);
+       if (ret) {
+               status = LTTNG_MAP_QUERY_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_query_status lttng_map_query_add_pid(
+       struct lttng_map_query *query, pid_t pid)
+{
+       int ret;
+       unsigned int pid_count;
+       enum lttng_map_query_status status;
+
+       if (query->config_buffer != LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_SUBSET) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       lttng_map_query_get_pid_count(query, &pid_count);
+       if (pid_count > 0) {
+               ERR("Only one PID can be targeted in a query at the moment");
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       ret = lttng_dynamic_array_add_element(&query->pid_array, &pid);
+       if (ret) {
+               status = LTTNG_MAP_QUERY_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_query_status lttng_map_query_add_key_filter(
+       struct lttng_map_query *query, const char *key_filter)
+{
+       enum lttng_map_query_status status;
+
+       query->key_filter = strdup(key_filter);
+       if (!query->key_filter) {
+               status = LTTNG_MAP_QUERY_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_query_config_cpu lttng_map_query_get_config_cpu(
+               const struct lttng_map_query *query)
+{
+       return query->config_cpu;
+}
+
+enum lttng_map_query_config_buffer lttng_map_query_get_config_buffer(
+               const struct lttng_map_query *query)
+{
+       return query->config_buffer;
+}
+
+enum lttng_map_query_config_app_bitness lttng_map_query_get_config_app_bitness(
+               const struct lttng_map_query *query)
+{
+       return query->config_bitness;
+}
+
+bool lttng_map_query_get_config_sum_by_cpu(
+               const struct lttng_map_query *query)
+{
+       return query->sum_by_cpu;
+}
+
+bool lttng_map_query_get_config_sum_by_pid(
+               const struct lttng_map_query *query)
+{
+       return query->sum_by_pid;
+}
+
+bool lttng_map_query_get_config_sum_by_uid(
+               const struct lttng_map_query *query)
+{
+       return query->sum_by_uid;
+}
+
+bool lttng_map_query_get_config_sum_by_app_bitness(
+               const struct lttng_map_query *query)
+{
+       return query->sum_by_app_bitness;
+}
+
+enum lttng_map_query_status lttng_map_query_get_cpu_count(
+               const struct lttng_map_query *query, unsigned int *count)
+{
+       enum lttng_map_query_status status;
+
+       assert(query);
+       if (query->config_cpu != LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       if (!count) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       *count = lttng_dynamic_array_get_count(&query->cpu_array);
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+
+end:
+       return status;
+}
+
+enum lttng_map_query_status lttng_map_query_get_cpu_at_index(
+               const struct lttng_map_query *query, unsigned int index,
+               int *cpu)
+{
+       enum lttng_map_query_status status;
+
+       assert(query);
+
+       if (query->config_cpu != LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+
+       *cpu = *(int *) lttng_dynamic_array_get_element(&query->cpu_array, index);
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_query_status lttng_map_query_get_uid_count(
+               const struct lttng_map_query *query, unsigned int *count)
+{
+       enum lttng_map_query_status status;
+
+       assert(query);
+       if (query->config_buffer != LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       if (!count) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       *count = lttng_dynamic_array_get_count(&query->uid_array);
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+
+end:
+       return status;
+}
+
+enum lttng_map_query_status lttng_map_query_get_uid_at_index(
+               const struct lttng_map_query *query, unsigned int index,
+               uid_t *uid)
+{
+       enum lttng_map_query_status status;
+
+       assert(query);
+
+       if (query->config_buffer != LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+
+       *uid = *(uid_t *) lttng_dynamic_array_get_element(&query->uid_array, index);
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_query_status lttng_map_query_get_pid_count(
+               const struct lttng_map_query *query, unsigned int *count)
+{
+       enum lttng_map_query_status status;
+
+       assert(query);
+       if (query->config_buffer != LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_SUBSET) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       if (!count) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+       *count = lttng_dynamic_array_get_count(&query->pid_array);
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+
+end:
+       return status;
+}
+
+enum lttng_map_query_status lttng_map_query_get_pid_at_index(
+               const struct lttng_map_query *query, unsigned int index,
+               pid_t *pid)
+{
+       enum lttng_map_query_status status;
+
+       assert(query);
+
+       if (query->config_buffer != LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_SUBSET) {
+               status = LTTNG_MAP_QUERY_STATUS_INVALID;
+               goto end;
+       }
+
+
+       *pid = *(pid_t *) lttng_dynamic_array_get_element(&query->pid_array, index);
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+end:
+       return status;
+}
+
+
+enum lttng_map_query_status lttng_map_query_get_key_filter(
+               const struct lttng_map_query *query, const char **key_filter)
+{
+       enum lttng_map_query_status status;
+
+       if (query->key_filter == NULL) {
+               status = LTTNG_MAP_QUERY_STATUS_NONE;
+               goto end;
+       }
+
+       *key_filter = query->key_filter;
+       status = LTTNG_MAP_QUERY_STATUS_OK;
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_map_query_create_from_payload(struct lttng_payload_view *src_view,
+               struct lttng_map_query **query)
+{
+       ssize_t ret, offset = 0;
+       struct lttng_map_query *local_query;
+       const struct lttng_map_query_comm *query_comm;
+
+       if (!src_view || !query) {
+               ret = -1;
+               goto end;
+       }
+
+       query_comm = (typeof(query_comm)) src_view->buffer.data;
+       offset += sizeof(*query_comm);
+
+       local_query = lttng_map_query_create(query_comm->config_cpu,
+                       query_comm->config_buffer, query_comm->config_app_bitness);
+       if (!local_query) {
+               ret = -1;
+               goto end;
+       }
+
+       local_query->sum_by_cpu = query_comm->sum_by_cpu;
+       local_query->sum_by_pid = query_comm->sum_by_pid;
+       local_query->sum_by_uid = query_comm->sum_by_uid;
+       local_query->sum_by_app_bitness = query_comm->sum_by_app_bitness;
+
+       if (query_comm->key_filter_length != 0) {
+               const char *key_filter;
+               struct lttng_payload_view key_filter_view =
+                               lttng_payload_view_from_view(
+                                               src_view, offset,
+                                               query_comm->key_filter_length);
+
+               key_filter = key_filter_view.buffer.data;
+               if (!lttng_buffer_view_contains_string(&key_filter_view.buffer,
+                                       key_filter, query_comm->key_filter_length)){
+                       ret = -1;
+                       goto end;
+               }
+
+               lttng_map_query_add_key_filter(local_query, key_filter);
+
+               offset += query_comm->key_filter_length;
+       }
+
+       if (local_query->config_cpu == LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+               unsigned int cpu_idx;
+
+               assert(query_comm->cpu_count > 0);
+
+               for (cpu_idx = 0; cpu_idx < query_comm->cpu_count; cpu_idx++) {
+                       int cpu_id;
+                       struct lttng_payload_view cpu_id_view =
+                                       lttng_payload_view_from_view( src_view,
+                                               offset, sizeof(cpu_id));
+                        cpu_id = *(int *) cpu_id_view.buffer.data;
+                        lttng_map_query_add_cpu(local_query, cpu_id);
+                        offset+=sizeof(cpu_id);
+               }
+       }
+
+       switch (local_query->config_buffer){
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_SUBSET:
+       {
+               unsigned int pid_idx;
+
+               assert(query_comm->pid_count > 0);
+
+               for (pid_idx = 0; pid_idx < query_comm->pid_count; pid_idx++) {
+                       pid_t pid;
+                       struct lttng_payload_view pid_view =
+                                       lttng_payload_view_from_view( src_view,
+                                               offset, sizeof(pid));
+                        pid = *(pid_t *) pid_view.buffer.data;
+                        lttng_map_query_add_pid(local_query, pid);
+                        offset+=sizeof(pid);
+               }
+               break;
+       }
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET:
+       {
+               unsigned int uid_idx;
+
+               assert(query_comm->uid_count > 0);
+
+               for (uid_idx = 0; uid_idx < query_comm->uid_count; uid_idx++) {
+                       uid_t uid;
+                       struct lttng_payload_view uid_view =
+                                       lttng_payload_view_from_view( src_view,
+                                               offset, sizeof(uid));
+                        uid = *(uid_t *) uid_view.buffer.data;
+                        lttng_map_query_add_uid(local_query, uid);
+                        offset+=sizeof(uid);
+               }
+       }
+       default:
+               break;
+       }
+
+       ret = offset;
+       *query = local_query;
+       local_query = NULL;
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_map_query_serialize(const struct lttng_map_query *query,
+               struct lttng_payload *payload)
+{
+       int ret;
+       struct lttng_map_query_comm query_comm = {};
+       enum lttng_map_query_status status;
+
+       query_comm.config_cpu = (uint8_t) query->config_cpu;
+       query_comm.config_buffer = (uint8_t) query->config_buffer;
+       query_comm.config_app_bitness = (uint8_t) query->config_bitness;
+
+       query_comm.sum_by_cpu = (uint8_t) query->sum_by_cpu;
+       query_comm.sum_by_uid = (uint8_t) query->sum_by_uid;
+       query_comm.sum_by_pid = (uint8_t) query->sum_by_pid;
+       query_comm.sum_by_app_bitness = (uint8_t) query->sum_by_app_bitness;
+
+       if (query->config_cpu == LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+               unsigned int cpu_count;
+               status = lttng_map_query_get_cpu_count(query, &cpu_count);
+               if (status != LTTNG_MAP_QUERY_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+
+               query_comm.cpu_count = cpu_count;
+       }
+
+       switch (query->config_buffer){
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_SUBSET:
+       {
+               unsigned int pid_count;
+               status = lttng_map_query_get_pid_count(query, &pid_count);
+               if (status != LTTNG_MAP_QUERY_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+               query_comm.pid_count = pid_count;
+               break;
+       }
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET:
+       {
+               unsigned int uid_count;
+               status = lttng_map_query_get_uid_count(query, &uid_count);
+               if (status != LTTNG_MAP_QUERY_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+               query_comm.uid_count = uid_count;
+       }
+       default:
+               break;
+       }
+
+       if (query->key_filter) {
+               query_comm.key_filter_length = strlen(query->key_filter) + 1;
+       } else {
+               query_comm.key_filter_length = 0;
+       }
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &query_comm,
+                       sizeof(query_comm));
+       if (ret) {
+               goto end;
+       }
+
+       /* key_filter */
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, query->key_filter,
+                       query_comm.key_filter_length);
+       if (ret) {
+               goto end;
+       }
+
+       if (query->config_cpu == LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+               ret = lttng_dynamic_buffer_append(&payload->buffer,
+                               query->cpu_array.buffer.data,
+                               query->cpu_array.buffer.size);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       switch (query->config_buffer){
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_SUBSET:
+       {
+               ret = lttng_dynamic_buffer_append(&payload->buffer,
+                               query->pid_array.buffer.data,
+                               query->pid_array.buffer.size);
+               if (ret) {
+                       goto end;
+               }
+       }
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET:
+       {
+               ret = lttng_dynamic_buffer_append(&payload->buffer,
+                               query->uid_array.buffer.data,
+                               query->uid_array.buffer.size);
+               if (ret) {
+                       goto end;
+               }
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+void lttng_map_query_destroy(struct lttng_map_query *query)
+{
+       assert(query);
+
+       if (query->config_cpu == LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET) {
+               lttng_dynamic_array_reset(&query->cpu_array);
+       }
+
+       switch(query->config_buffer) {
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET:
+               lttng_dynamic_array_reset(&query->uid_array);
+               break;
+       case LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_SUBSET:
+               lttng_dynamic_array_reset(&query->pid_array);
+               break;
+       default:
+               break;
+       }
+       free(query->key_filter);
+       free(query);
+}
diff --git a/src/common/map.c b/src/common/map.c
new file mode 100644 (file)
index 0000000..c4de9a6
--- /dev/null
@@ -0,0 +1,1239 @@
+/*
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/optional.h>
+#include <common/payload.h>
+
+#include <lttng/lttng.h>
+#include <lttng/map/map-internal.h>
+
+enum lttng_map_status lttng_map_set_name(struct lttng_map *map,
+               const char *name)
+{
+       char *name_copy = NULL;
+       enum lttng_map_status status;
+
+       if (!map || !name || strlen(name) == 0) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       name_copy = strdup(name);
+       if (!name_copy) {
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto end;
+       }
+
+       free(map->name);
+
+       map->name = name_copy;
+       name_copy = NULL;
+
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_status lttng_map_get_name(const struct lttng_map *map,
+               const char **name)
+{
+       enum lttng_map_status status;
+
+       if (!map || !name) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       if (!map->name) {
+               status = LTTNG_MAP_STATUS_UNSET;
+       }
+
+       *name = map->name;
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_status lttng_map_create(const char *name,
+               unsigned int dimension_count,
+               uint64_t *dimension_sizes,
+               enum lttng_domain_type domain,
+               enum lttng_buffer_type buffer_type,
+               enum lttng_map_bitness bitness,
+               enum lttng_map_boundary_policy boundary_policy,
+               bool coalesce_hits,
+               struct lttng_map **map_out)
+{
+       enum lttng_map_status status;
+       struct lttng_map *map;
+
+       if (dimension_count != 1) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       map = zmalloc(sizeof(struct lttng_map));
+       if (!map) {
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto end;
+       }
+
+       if (name) {
+               status = lttng_map_set_name(map, name);
+               if (status != LTTNG_MAP_STATUS_OK) {
+                       goto free_map;
+               }
+       } else {
+               map->name = NULL;
+       }
+
+       map->dimension_count = dimension_count;
+       map->dimension_sizes = zmalloc(
+                       sizeof(*map->dimension_sizes) * dimension_count);
+       if (!map->dimension_sizes) {
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto free_name;
+       }
+
+       memcpy(map->dimension_sizes, dimension_sizes,
+                       sizeof(*map->dimension_sizes) * dimension_count);
+
+       map->domain = domain;
+       map->buffer_type = buffer_type;
+       map->bitness = bitness;
+       map->boundary_policy = boundary_policy;
+       map->coalesce_hits = coalesce_hits;
+
+       lttng_map_set_is_enabled(map, true);
+
+       urcu_ref_init(&map->ref);
+
+       *map_out = map;
+
+       status = LTTNG_MAP_STATUS_OK;
+
+       goto end;
+free_name:
+       free(map->name);
+free_map:
+       free(map);
+end:
+       return status;
+}
+
+unsigned int lttng_map_get_dimension_count(
+               const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->dimension_count;
+}
+
+enum lttng_map_status lttng_map_get_dimension_length(
+               const struct lttng_map *map, unsigned int dimension,
+               uint64_t *dimension_length)
+{
+       enum lttng_map_status status;
+
+       assert(map);
+
+       if (dimension >= map->dimension_count) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       *dimension_length = map->dimension_sizes[dimension];
+
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_bitness lttng_map_get_bitness(
+               const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->bitness;
+}
+
+enum lttng_domain_type lttng_map_get_domain(
+               const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->domain;
+}
+
+enum lttng_buffer_type lttng_map_get_buffer_type(
+               const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->buffer_type;
+}
+
+enum lttng_map_boundary_policy lttng_map_get_boundary_policy(
+               const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->boundary_policy;
+}
+
+bool lttng_map_get_coalesce_hits(const struct lttng_map *map)
+{
+       assert(map);
+
+       return map->coalesce_hits;
+}
+
+LTTNG_HIDDEN
+int lttng_map_serialize(const struct lttng_map *map,
+               struct lttng_payload *payload)
+{
+       int ret;
+       size_t header_offset, size_before_payload, size_name;
+       struct lttng_map_comm map_comm = {};
+       struct lttng_map_comm *header;
+
+       if (map->name != NULL) {
+               size_name = strlen(map->name) + 1;
+       } else {
+               size_name = 0;
+       }
+
+       map_comm.name_length = size_name;
+       map_comm.is_enabled = LTTNG_OPTIONAL_GET(map->is_enabled);
+       map_comm.bitness = map->bitness;
+       map_comm.domain = map->domain;
+       map_comm.buffer_type = map->buffer_type;
+       map_comm.boundary_policy = map->boundary_policy;
+       map_comm.dimension_count = map->dimension_count;
+       map_comm.coalesce_hits = map->coalesce_hits;
+
+       header_offset = payload->buffer.size;
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &map_comm,
+                       sizeof(map_comm));
+       if (ret) {
+               goto end;
+       }
+
+       size_before_payload = payload->buffer.size;
+
+       /* map name */
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, map->name, size_name);
+       if (ret) {
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, map->dimension_sizes,
+                       sizeof(*map->dimension_sizes) * map->dimension_count);
+       if (ret) {
+               goto end;
+       }
+
+       /* Update payload size. */
+       header = (typeof(header)) (payload->buffer.data + header_offset);
+       header->length = payload->buffer.size - size_before_payload;
+
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_map_create_from_payload(
+               struct lttng_payload_view *src_view,
+               struct lttng_map **map)
+{
+       ssize_t ret, offset = 0;
+       const struct lttng_map_comm *map_comm;
+       enum lttng_map_status status;
+       unsigned int dimension_count;
+       uint64_t *dimension_sizes = NULL;
+       bool coalesce_hits;
+       const char *name = NULL;
+       enum lttng_domain_type domain;
+       enum lttng_buffer_type buffer_type;
+       enum lttng_map_bitness bitness;
+       enum lttng_map_boundary_policy boundary_policy;
+
+       if (!src_view || !map) {
+               ret = -1;
+               goto end;
+       }
+
+       map_comm = (typeof(map_comm)) src_view->buffer.data;
+       offset += sizeof(*map_comm);
+
+       domain = map_comm->domain;
+       buffer_type = map_comm->buffer_type;
+       bitness = map_comm->bitness;
+       boundary_policy = map_comm->boundary_policy;
+       dimension_count = map_comm->dimension_count;
+       coalesce_hits = map_comm->coalesce_hits;
+
+       if (map_comm->name_length != 0) {
+               struct lttng_payload_view name_view =
+                               lttng_payload_view_from_view(
+                                               src_view, offset,
+                                               map_comm->name_length);
+
+               name = name_view.buffer.data;
+               if (!lttng_buffer_view_contains_string(&name_view.buffer,
+                                       name, map_comm->name_length)){
+                       ret = -1;
+                       goto end;
+               }
+               offset += map_comm->name_length;
+       }
+
+       size_t map_dim_sizes_len = sizeof(*(*map)->dimension_sizes) * dimension_count;
+
+       struct lttng_payload_view dimension_sizes_view =
+                       lttng_payload_view_from_view(src_view, offset,
+                               map_dim_sizes_len);
+
+       dimension_sizes = zmalloc(map_dim_sizes_len);
+       if (!dimension_sizes) {
+               ret = -1;
+               goto end;
+       }
+
+       memcpy(dimension_sizes, dimension_sizes_view.buffer.data,
+                       map_dim_sizes_len);
+
+       offset += map_dim_sizes_len;
+
+       status = lttng_map_create(name, dimension_count,
+                       dimension_sizes, domain, buffer_type, bitness,
+                       boundary_policy, coalesce_hits, map);
+       if (status != LTTNG_MAP_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       lttng_map_set_is_enabled(*map, map_comm->is_enabled);
+
+       ret = offset;
+
+end:
+       free(dimension_sizes);
+       return ret;
+}
+
+LTTNG_HIDDEN
+void lttng_map_set_is_enabled(struct lttng_map *map, bool enabled)
+{
+       assert(map);
+
+       LTTNG_OPTIONAL_SET(&map->is_enabled, enabled);
+}
+
+int lttng_map_get_is_enabled(const struct lttng_map *map)
+{
+       assert(map);
+       return (int) LTTNG_OPTIONAL_GET(map->is_enabled);
+}
+
+LTTNG_HIDDEN
+void lttng_map_get(struct lttng_map *map)
+{
+       urcu_ref_get(&map->ref);
+}
+
+static void map_destroy_ref(struct urcu_ref *ref)
+{
+       struct lttng_map *map = container_of(ref, struct lttng_map, ref);
+
+       free(map->dimension_sizes);
+       free(map->name);
+       free(map);
+
+}
+
+LTTNG_HIDDEN
+void lttng_map_put(struct lttng_map *map)
+{
+       if (!map) {
+               return;
+       }
+
+       urcu_ref_put(&map->ref , map_destroy_ref);
+}
+
+
+void lttng_map_destroy(struct lttng_map *map)
+{
+       lttng_map_put(map);
+}
+
+static void delete_map_array_element(void *ptr)
+{
+       struct lttng_map *map = ptr;
+
+       lttng_map_put(map);
+}
+
+LTTNG_HIDDEN
+struct lttng_map_list *lttng_map_list_create(void)
+{
+       struct lttng_map_list *map_list = NULL;
+
+       map_list = zmalloc(sizeof(*map_list));
+       if (!map_list) {
+               goto end;
+       }
+
+       lttng_dynamic_pointer_array_init(&map_list->array,
+                       delete_map_array_element);
+
+end:
+       return map_list;
+}
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_list_add(struct lttng_map_list *map_list,
+               struct lttng_map *map)
+{
+       enum lttng_map_status status;
+       int ret;
+
+       assert(map_list);
+       assert(map);
+
+       lttng_map_get(map);
+
+       ret = lttng_dynamic_pointer_array_add_pointer(&map_list->array, map);
+       if (ret) {
+               lttng_map_put(map);
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto end;
+       }
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_map_list_create_from_payload(struct lttng_payload_view *src_view,
+               struct lttng_map_list **map_list)
+{
+       unsigned int i;
+       ssize_t ret, offset = 0;
+       const struct lttng_map_list_comm *map_list_comm;
+       struct lttng_map_list *local_map_list = NULL;
+
+       map_list_comm = (typeof(map_list_comm)) src_view->buffer.data;
+       offset += sizeof(*map_list_comm);
+
+       local_map_list = lttng_map_list_create();
+       if (!local_map_list) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < map_list_comm->count; i++) {
+               struct lttng_map *map = NULL;
+               struct lttng_payload_view map_view =
+                               lttng_payload_view_from_view(src_view, offset, -1);
+               ssize_t map_size;
+
+               map_size = lttng_map_create_from_payload(&map_view, &map);
+               if (map_size < 0) {
+                       ret = map_size;
+                       goto end;
+               }
+
+               /* Transfer ownership of the map to the collection. */
+               ret = lttng_map_list_add(local_map_list, map);
+               lttng_map_put(map);
+               if (ret < 0) {
+                       ret = -1;
+                       goto end;
+               }
+
+               offset += map_size;
+       }
+
+       /* Pass ownership to caller. */
+       *map_list = local_map_list;
+       local_map_list = NULL;
+
+       ret = offset;
+end:
+       lttng_map_list_destroy(local_map_list);
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_map_list_serialize(const struct lttng_map_list *map_list,
+               struct lttng_payload *payload)
+{
+       int ret;
+       unsigned int i, count;
+       enum lttng_map_status status;
+       struct lttng_map_list_comm map_list_comm = {};
+
+       status = lttng_map_list_get_count(map_list, &count);
+       if (status != LTTNG_MAP_STATUS_OK) {
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       map_list_comm.count = count;
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &map_list_comm,
+                       sizeof(map_list_comm));
+       if (ret) {
+               goto end;
+       }
+       for (i = 0; i < count; i++) {
+               const struct lttng_map *map =
+                               lttng_map_list_get_at_index(map_list, i);
+
+               assert(map);
+
+               ret = lttng_map_serialize(map, payload);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+const struct lttng_map *lttng_map_list_get_at_index(
+               const struct lttng_map_list *map_list, unsigned int index)
+{
+       struct lttng_map *map = NULL;
+
+       assert(map_list);
+       if (index >= lttng_dynamic_pointer_array_get_count(&map_list->array)) {
+               goto end;
+       }
+
+       map = (struct lttng_map *)
+                       lttng_dynamic_pointer_array_get_pointer(
+                                       &map_list->array, index);
+end:
+       return map;
+}
+
+enum lttng_map_status lttng_map_list_get_count(
+               const struct lttng_map_list *map_list, unsigned int *count)
+{
+       enum lttng_map_status status = LTTNG_MAP_STATUS_OK;
+
+       if (!map_list || !count) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       *count = lttng_dynamic_pointer_array_get_count(&map_list->array);
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+void lttng_map_list_destroy(struct lttng_map_list *map_list)
+{
+       if (!map_list) {
+               return;
+       }
+
+       lttng_dynamic_pointer_array_reset(&map_list->array);
+       free(map_list);
+}
+
+struct lttng_map_key_value_pair *lttng_map_key_value_pair_create(const char *key,
+               int64_t value)
+{
+       struct lttng_map_key_value_pair *key_value;
+
+       key_value = zmalloc(sizeof(struct lttng_map_key_value_pair));
+       if (!key_value) {
+               goto end;
+       }
+
+       key_value->key = strdup(key);
+       if (!key_value->key) {
+               free(key_value);
+               key_value = NULL;
+               goto end;
+       }
+       key_value->value = value;
+
+end:
+       return key_value;
+}
+
+enum lttng_map_status lttng_map_key_value_pair_get_key(
+               const struct lttng_map_key_value_pair *key_value,
+               const char **key)
+{
+       assert(key_value);
+       assert(key_value->key);
+
+       *key = key_value->key;
+       return LTTNG_MAP_STATUS_OK;
+}
+
+enum lttng_map_status lttng_map_key_value_pair_get_value(
+               const struct lttng_map_key_value_pair *key_value,
+               int64_t *value)
+{
+       assert(key_value);
+       *value = key_value->value;
+       return LTTNG_MAP_STATUS_OK;
+}
+
+LTTNG_HIDDEN
+void lttng_map_key_value_pair_set_has_overflowed(
+               struct lttng_map_key_value_pair *key_value)
+{
+       assert(key_value);
+
+       key_value->has_overflowed = true;
+}
+
+LTTNG_HIDDEN
+void lttng_map_key_value_pair_set_has_underflowed(
+               struct lttng_map_key_value_pair *key_value)
+{
+       assert(key_value);
+
+       key_value->has_underflowed = true;
+}
+
+bool lttng_map_key_value_pair_get_has_overflowed(
+               const struct lttng_map_key_value_pair *key_value)
+{
+       assert(key_value);
+
+       return key_value->has_overflowed;
+}
+
+bool lttng_map_key_value_pair_get_has_underflowed(
+               const struct lttng_map_key_value_pair *key_value)
+{
+       assert(key_value);
+
+       return key_value->has_underflowed;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_map_key_value_pair_create_from_payload(
+               struct lttng_payload_view *src_view,
+               struct lttng_map_key_value_pair **key_value)
+{
+       const struct lttng_map_key_value_pair_comm *kv_pair_comm;
+       struct lttng_map_key_value_pair *kv_pair;
+       ssize_t ret, offset = 0;
+       const char *key;
+       int64_t value;
+
+       if (!src_view || !key_value) {
+               ret = -1;
+               goto end;
+       }
+
+       kv_pair_comm = (typeof(kv_pair_comm)) src_view->buffer.data;
+       offset += sizeof(*kv_pair_comm);
+
+       if (kv_pair_comm->key_length == 0) {
+               ret = -1;
+               goto end;
+       }
+
+       value = kv_pair_comm->value;
+
+       struct lttng_payload_view key_view =
+               lttng_payload_view_from_view(src_view, offset,
+                       kv_pair_comm->key_length);
+       key = key_view.buffer.data;
+       if (!lttng_buffer_view_contains_string(&key_view.buffer,
+                       key, kv_pair_comm->key_length)) {
+               ret = -1;
+               goto end;
+       }
+
+       offset += kv_pair_comm->key_length;
+
+       kv_pair = lttng_map_key_value_pair_create(key, value);
+       if (!kv_pair) {
+               ret = -1;
+               goto end;
+       }
+
+       kv_pair->has_overflowed = kv_pair_comm->has_overflowed;
+       kv_pair->has_underflowed = kv_pair_comm->has_underflowed;
+
+       *key_value = kv_pair;
+
+       ret = offset;
+
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_map_key_value_pair_serialize(
+               const struct lttng_map_key_value_pair *key_value,
+               struct lttng_payload *payload)
+{
+       int ret;
+       size_t key_len;
+       struct lttng_map_key_value_pair_comm kv_pair_comm = {0};
+
+       assert(key_value);
+       assert(key_value->key);
+
+       key_len = strlen(key_value->key) + 1;
+
+       kv_pair_comm.key_length = key_len;
+       kv_pair_comm.value = key_value->value;
+       kv_pair_comm.has_overflowed = key_value->has_overflowed;
+       kv_pair_comm.has_underflowed = key_value->has_underflowed;
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &kv_pair_comm,
+                       sizeof(kv_pair_comm));
+       if (ret) {
+               goto end;
+       }
+
+       /* Append key.*/
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, key_value->key, key_len);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+void lttng_map_key_value_pair_destroy(struct lttng_map_key_value_pair *key_value)
+{
+       if (!key_value) {
+               return;
+       }
+
+       free(key_value->key);
+       free(key_value);
+}
+
+static void delete_map_key_value_pair_array_element(void *ptr)
+{
+       struct lttng_map_key_value_pair *key_value = ptr;
+       lttng_map_key_value_pair_destroy(key_value);
+}
+
+LTTNG_HIDDEN
+struct lttng_map_key_value_pair_list *lttng_map_key_value_pair_list_create(
+               enum lttng_map_key_value_pair_list_type type,
+               bool summed_all_cpus)
+{
+       struct lttng_map_key_value_pair_list *map_key_values = NULL;
+
+       map_key_values = zmalloc(sizeof(*map_key_values));
+       if (!map_key_values) {
+               goto end;
+       }
+
+       map_key_values->type = type;
+       map_key_values->summed_all_cpus = summed_all_cpus;
+
+       lttng_dynamic_pointer_array_init(&map_key_values->array,
+                       delete_map_key_value_pair_array_element);
+
+end:
+       return map_key_values;
+}
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_key_value_pair_list_set_identifier(
+               struct lttng_map_key_value_pair_list *kv_pair_list,
+               uint64_t identifier)
+{
+       enum lttng_map_status status;
+       assert(kv_pair_list);
+
+       switch (kv_pair_list->type) {
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID:
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID:
+               kv_pair_list->id = identifier;
+               status = LTTNG_MAP_STATUS_OK;
+               break;
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID_AGGREGATED:
+               ERR("Cannot set an identifier for an UST per-pid aggregation key value pair list");
+               status = LTTNG_MAP_STATUS_INVALID;
+               break;
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_KERNEL:
+               ERR("Cannot set an identifier for a kernel key value pair list");
+               status = LTTNG_MAP_STATUS_INVALID;
+               break;
+       default:
+               ERR("Unknown key value par list type %d", kv_pair_list->type);
+               abort();
+       }
+
+       return status;
+}
+
+LTTNG_HIDDEN
+bool lttng_map_key_value_pair_list_get_summed_all_cpu(
+               const struct lttng_map_key_value_pair_list *kv_pair_list)
+{
+       assert(kv_pair_list);
+
+       return kv_pair_list->summed_all_cpus;
+}
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_key_value_pair_list_set_cpu(
+               struct lttng_map_key_value_pair_list *kv_pair_list,
+               uint64_t cpu)
+{
+       assert(kv_pair_list);
+
+       kv_pair_list->cpu = cpu;
+
+       return LTTNG_MAP_STATUS_OK;
+}
+
+LTTNG_HIDDEN
+uint64_t lttng_map_key_value_pair_list_get_cpu(
+               const struct lttng_map_key_value_pair_list *kv_pair_list)
+{
+       assert(kv_pair_list);
+
+       return kv_pair_list->cpu;
+}
+
+LTTNG_HIDDEN
+enum lttng_map_key_value_pair_list_type lttng_map_key_value_pair_list_get_type(
+               const struct lttng_map_key_value_pair_list *kv_pair_list)
+{
+       assert(kv_pair_list);
+
+       return kv_pair_list->type;
+}
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_key_value_pair_list_append_key_value(
+               struct lttng_map_key_value_pair_list *kv_pair_list,
+               struct lttng_map_key_value_pair *key_value)
+{
+       int ret;
+       enum lttng_map_status status;
+
+       assert(kv_pair_list);
+       assert(key_value);
+
+       ret = lttng_dynamic_pointer_array_add_pointer(&kv_pair_list->array,
+                       key_value);
+       if (ret) {
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_STATUS_OK;
+
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+uint64_t lttng_map_key_value_pair_list_get_identifer(
+               const struct lttng_map_key_value_pair_list *kv_pair_list)
+{
+       assert(kv_pair_list);
+
+       switch (kv_pair_list->type) {
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID:
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID:
+               break;
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID_AGGREGATED:
+               ERR("No identifier for UST per-pid aggregation key value pair lists");
+               abort();
+               break;
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_KERNEL:
+               ERR("No identifier for kernel key value pair lists");
+               abort();
+               break;
+       default:
+               ERR("Unknown key value par list type %d", kv_pair_list->type);
+               abort();
+       }
+
+       return kv_pair_list->id;
+}
+
+const struct lttng_map_key_value_pair *lttng_map_key_value_pair_list_get_at_index(
+               const struct lttng_map_key_value_pair_list *kv_pair_list,
+               unsigned int index)
+{
+       struct lttng_map_key_value_pair *key_value = NULL;
+
+       assert(kv_pair_list);
+       if (index >= lttng_dynamic_pointer_array_get_count(&kv_pair_list->array)) {
+               goto end;
+       }
+
+       key_value = (struct lttng_map_key_value_pair *)
+                       lttng_dynamic_pointer_array_get_pointer(
+                                       &kv_pair_list->array, index);
+end:
+       return key_value;
+}
+
+enum lttng_map_status lttng_map_key_value_pair_list_get_count(
+               const struct lttng_map_key_value_pair_list *kv_pair_list,
+               unsigned int *count)
+{
+       enum lttng_map_status status;
+
+       if (!kv_pair_list || !count) {
+               status = LTTNG_MAP_STATUS_INVALID;;
+               goto end;
+       }
+
+       *count = lttng_dynamic_pointer_array_get_count(&kv_pair_list->array);
+
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+void lttng_map_key_value_pair_list_destroy(struct lttng_map_key_value_pair_list *kv_pair_list)
+{
+       if (!kv_pair_list) {
+               return;
+       }
+
+       lttng_dynamic_pointer_array_reset(&kv_pair_list->array);
+       free(kv_pair_list);
+}
+
+int lttng_map_key_value_pair_list_serialize(
+               const struct lttng_map_key_value_pair_list *kv_pair_list,
+               struct lttng_payload *payload)
+{
+       int ret;
+       unsigned int i, count;
+       enum lttng_map_status status;
+       struct lttng_map_key_value_pair_list_comm kv_pair_list_comm = {};
+
+       kv_pair_list_comm.id = kv_pair_list->id;
+       kv_pair_list_comm.cpu = kv_pair_list->cpu;
+       kv_pair_list_comm.type = (uint8_t) kv_pair_list->type;
+       kv_pair_list_comm.summed_all_cpus = (uint8_t) kv_pair_list->summed_all_cpus;
+
+       status = lttng_map_key_value_pair_list_get_count(kv_pair_list, &count);
+       if (status != LTTNG_MAP_STATUS_OK) {
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       kv_pair_list_comm.count = count;
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &kv_pair_list_comm,
+                       sizeof(kv_pair_list_comm));
+       if (ret) {
+               goto end;
+       }
+       for (i = 0; i < count; i++) {
+               const struct lttng_map_key_value_pair *kv_pair =
+                               lttng_map_key_value_pair_list_get_at_index(kv_pair_list, i);
+
+               assert(kv_pair);
+
+               ret = lttng_map_key_value_pair_serialize(kv_pair, payload);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_map_key_value_pair_list_create_from_payload(
+               struct lttng_payload_view *src_view,
+               struct lttng_map_key_value_pair_list **kv_pair_list)
+{
+       ssize_t ret, offset = 0;
+       unsigned int i;
+       enum lttng_map_status status;
+       const struct lttng_map_key_value_pair_list_comm *kv_pair_list_comm;
+       struct lttng_map_key_value_pair_list *local_key_values = NULL;
+
+       kv_pair_list_comm = (typeof(kv_pair_list_comm)) src_view->buffer.data;
+       offset += sizeof(*kv_pair_list_comm);
+
+       local_key_values = lttng_map_key_value_pair_list_create(
+                       kv_pair_list_comm->type, kv_pair_list_comm->summed_all_cpus);
+       if (!local_key_values) {
+               ret = -1;
+               goto end;
+       }
+
+       local_key_values->cpu = kv_pair_list_comm->cpu;
+
+       switch (lttng_map_key_value_pair_list_get_type(local_key_values)) {
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID:
+       case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID:
+               status = lttng_map_key_value_pair_list_set_identifier(local_key_values,
+                       kv_pair_list_comm->id);
+               if (status != LTTNG_MAP_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       default:
+               break;
+       }
+
+       for (i = 0; i < kv_pair_list_comm->count; i++) {
+               struct lttng_map_key_value_pair *kv_pair = NULL;
+               struct lttng_payload_view kv_view =
+                               lttng_payload_view_from_view(src_view, offset, -1);
+               ssize_t kv_size;
+
+               kv_size = lttng_map_key_value_pair_create_from_payload(
+                               &kv_view, &kv_pair);
+               if (kv_size < 0) {
+                       ret = kv_size;
+                       goto end;
+               }
+
+               /* Transfer ownership of the key-value to the collection. */
+               status = lttng_map_key_value_pair_list_append_key_value(local_key_values,
+                               kv_pair);
+               if (status != LTTNG_MAP_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+
+               offset += kv_size;
+       }
+
+       /* Pass ownership to caller. */
+       *kv_pair_list = local_key_values;
+       local_key_values = NULL;
+
+       ret = offset;
+end:
+       lttng_map_key_value_pair_list_destroy(local_key_values);
+       return ret;
+}
+
+static void delete_map_key_value_pair_list_array_element(void *ptr)
+{
+       struct lttng_map_key_value_pair_list *kv_list = ptr;
+       lttng_map_key_value_pair_list_destroy(kv_list);
+}
+
+LTTNG_HIDDEN
+struct lttng_map_content *lttng_map_content_create(
+               enum lttng_buffer_type type)
+{
+       struct lttng_map_content *map_content = NULL;
+
+       map_content = zmalloc(sizeof(*map_content));
+       if (!map_content) {
+               goto end;
+       }
+
+       map_content->type = type;
+
+       lttng_dynamic_pointer_array_init(&map_content->array,
+                       delete_map_key_value_pair_list_array_element);
+
+end:
+       return map_content;
+}
+
+enum lttng_map_status lttng_map_content_get_count(
+               const struct lttng_map_content *map_content,
+               unsigned int *count)
+{
+       enum lttng_map_status status = LTTNG_MAP_STATUS_OK;
+
+       if (!map_content || !count) {
+               status = LTTNG_MAP_STATUS_INVALID;
+               goto end;
+       }
+
+       *count = lttng_dynamic_pointer_array_get_count(&map_content->array);
+       status = LTTNG_MAP_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_buffer_type lttng_map_content_get_buffer_type(
+                       const struct lttng_map_content *map_content)
+{
+       assert(map_content);
+
+       return map_content->type;
+}
+
+LTTNG_HIDDEN
+enum lttng_map_status lttng_map_content_append_key_value_list(
+               struct lttng_map_content *map_content,
+               struct lttng_map_key_value_pair_list *kv_list)
+{
+       int ret;
+       enum lttng_map_status status;
+
+       assert(map_content);
+       assert(kv_list);
+
+       ret = lttng_dynamic_pointer_array_add_pointer(&map_content->array,
+                       kv_list);
+       if (ret) {
+               status = LTTNG_MAP_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_STATUS_OK;
+
+end:
+       return status;
+}
+
+const struct lttng_map_key_value_pair_list *lttng_map_content_get_at_index(
+               const struct lttng_map_content *map_content,
+               unsigned int index)
+{
+       struct lttng_map_key_value_pair_list *kv_pair_list = NULL;
+
+       assert(map_content);
+       if (index >= lttng_dynamic_pointer_array_get_count(&map_content->array)) {
+               goto end;
+       }
+
+       kv_pair_list = (struct lttng_map_key_value_pair_list *)
+                       lttng_dynamic_pointer_array_get_pointer(
+                                       &map_content->array, index);
+end:
+       return kv_pair_list;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_map_content_create_from_payload(
+               struct lttng_payload_view *src_view,
+               struct lttng_map_content **map_content)
+{
+       ssize_t ret, offset = 0;
+       unsigned int i;
+       struct lttng_map_content_comm *map_content_comm;
+       struct lttng_map_content *local_map_content;
+
+       map_content_comm = (typeof(map_content_comm)) src_view->buffer.data;
+       offset += sizeof(*map_content_comm);
+
+       local_map_content = lttng_map_content_create(map_content_comm->type);
+       if (!local_map_content) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < map_content_comm->count; i++) {
+               struct lttng_map_key_value_pair_list *kv_pair_list = NULL;
+               struct lttng_payload_view kv_list_view =
+                               lttng_payload_view_from_view(src_view, offset, -1);
+               ssize_t kv_list_size;
+
+               kv_list_size = lttng_map_key_value_pair_list_create_from_payload(
+                               &kv_list_view, &kv_pair_list);
+               if (kv_list_size < 0) {
+                       ret = kv_list_size;
+                       goto end;
+               }
+
+               /* Transfer ownership of the key-value to the collection. */
+               ret = lttng_map_content_append_key_value_list(local_map_content,
+                               kv_pair_list);
+               if (ret < 0) {
+                       ret = -1;
+                       goto end;
+               }
+
+               offset += kv_list_size;
+       }
+
+       /* Pass ownership to caller. */
+       *map_content = local_map_content;
+       local_map_content = NULL;
+
+       ret = offset;
+end:
+       lttng_map_content_destroy(local_map_content);
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_map_content_serialize(
+               const struct lttng_map_content *map_content,
+               struct lttng_payload *payload)
+{
+       int ret;
+       unsigned int i, count;
+       enum lttng_map_status status;
+       struct lttng_map_content_comm map_content_comm = {};
+
+       status = lttng_map_content_get_count(map_content, &count);
+       if (status != LTTNG_MAP_STATUS_OK) {
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       map_content_comm.count = count;
+       map_content_comm.type = lttng_map_content_get_buffer_type(map_content);
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &map_content_comm,
+                       sizeof(map_content_comm));
+       if (ret) {
+               goto end;
+       }
+       for (i = 0; i < count; i++) {
+               const struct lttng_map_key_value_pair_list *kv_pair_list =
+                               lttng_map_content_get_at_index(map_content, i);
+
+               assert(kv_pair_list);
+
+               ret = lttng_map_key_value_pair_list_serialize(kv_pair_list, payload);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+void lttng_map_content_destroy(struct lttng_map_content *map_content)
+{
+       if (!map_content) {
+               return;
+       }
+
+       lttng_dynamic_pointer_array_reset(&map_content->array);
+       free(map_content);
+}
index c347b3ceac891b60ffc2ecb6a98df84653b857f5..a4e971bd572c159b4a54d90643965dd1479b937d 100644 (file)
@@ -122,7 +122,7 @@ ssize_t lttng_notification_create_from_payload(
                                                notification_size, -1);
 
                evaluation_size = lttng_evaluation_create_from_payload(
-                               &evaluation_view, &evaluation);
+                               condition, &evaluation_view, &evaluation);
        }
 
        if (evaluation_size < 0) {
index 4c1ba5ccef58fc3ba19f3e5a480da41b27baecf6..e65d358ada81c3bc0d286fe532fbda95273e8e47 100644 (file)
@@ -107,6 +107,11 @@ enum lttcomm_sessiond_command {
        LTTNG_CREATE_SESSION_EXT                        = 49,
        LTTNG_CLEAR_SESSION                             = 50,
        LTTNG_LIST_TRIGGERS                             = 51,
+       LTTNG_ADD_MAP                                   = 52,
+       LTTNG_ENABLE_MAP                                = 53,
+       LTTNG_DISABLE_MAP                               = 54,
+       LTTNG_LIST_MAPS                                 = 55,
+       LTTNG_LIST_MAP_VALUES                           = 56,
 };
 
 static inline
@@ -197,6 +202,16 @@ const char *lttcomm_sessiond_command_str(enum lttcomm_sessiond_command cmd)
                return "LTTNG_CLEAR_SESSION";
        case LTTNG_LIST_TRIGGERS:
                return "LTTNG_LIST_TRIGGERS";
+       case LTTNG_ADD_MAP:
+               return "LTTNG_ADD_MAP";
+       case LTTNG_ENABLE_MAP:
+               return "LTTNG_ENABLE_MAP";
+       case LTTNG_DISABLE_MAP:
+               return "LTTNG_DISABLE_MAP";
+       case LTTNG_LIST_MAPS:
+               return "LTTNG_LIST_MAPS";
+       case LTTNG_LIST_MAP_VALUES:
+               return "LTTNG_LIST_MAP_VALUES";
        default:
                abort();
        }
@@ -413,6 +428,18 @@ struct lttcomm_session_msg {
                        struct lttng_channel chan;
                        struct lttng_channel_extended extended;
                } LTTNG_PACKED channel;
+               /* Add map */
+               struct {
+                       uint32_t length;
+               } LTTNG_PACKED add_map;
+               /* Enable map */
+               struct {
+                       char map_name[LTTNG_SYMBOL_NAME_LEN];
+               } LTTNG_PACKED enable_map;
+               /* Disable map */
+               struct {
+                       char map_name[LTTNG_SYMBOL_NAME_LEN];
+               } LTTNG_PACKED disable_map;
                /* Context */
                struct {
                        char channel_name[LTTNG_SYMBOL_NAME_LEN];
@@ -508,6 +535,10 @@ struct lttcomm_session_msg {
                        uint64_t session_descriptor_size;
                        /* An lttng_session_descriptor follows. */
                } LTTNG_PACKED create_session;
+               struct {
+                       uint32_t map_length;
+                       uint32_t query_length;
+               } LTTNG_PACKED list_map_values;
        } u;
        /* Count of fds sent. */
        uint32_t fd_count;
diff --git a/src/common/shm.c b/src/common/shm.c
new file mode 100644 (file)
index 0000000..737f73e
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <urcu.h>
+
+#include <common/error.h>
+
+#include "shm.h"
+
+/*
+ * Using fork to set umask in the child process (not multi-thread safe). We
+ * deal with the shm_open vs ftruncate race (happening when the sessiond owns
+ * the shm and does not let everybody modify it, to ensure safety against
+ * shm_unlink) by simply letting the mmap fail and retrying after a few
+ * seconds. For global shm, everybody has rw access to it until the sessiond
+ * starts.
+ */
+static int get_wait_shm(char *shm_path, size_t mmap_size, int global)
+{
+       int wait_shm_fd, ret;
+       mode_t mode;
+
+       assert(shm_path);
+
+       /* Default permissions */
+       mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
+
+       /*
+        * Change owner of the shm path.
+        */
+       if (global) {
+               /*
+                * If global session daemon, any application can
+                * register. Make it initially writeable so applications
+                * registering concurrently can do ftruncate() by
+                * themselves.
+                */
+               mode |= S_IROTH | S_IWOTH;
+       }
+
+       /*
+        * We're alone in a child process, so we can modify the process-wide
+        * umask.
+        */
+       umask(~mode);
+
+       /*
+        * Try creating shm (or get rw access). We don't do an exclusive open,
+        * because we allow other processes to create+ftruncate it concurrently.
+        *
+        * A sysctl, fs.protected_regular may prevent the session daemon from
+        * opening a previously created shm when the O_CREAT flag is provided.
+        * Systemd enables this ABI-breaking change by default since v241.
+        *
+        * First, attempt to use the create-or-open semantic that is
+        * desired here. If this fails with EACCES, work around this broken
+        * behaviour and attempt to open the shm without the O_CREAT flag.
+        *
+        * The two attempts are made in this order since applications are
+        * expected to race with the session daemon to create this shm.
+        * Attempting an shm_open() without the O_CREAT flag first could fail
+        * because the file doesn't exist. It could then be created by an
+        * application, which would cause a second try with the O_CREAT flag to
+        * fail with EACCES.
+        *
+        * Note that this introduces a new failure mode where a user could
+        * launch an application (creating the shm) and unlink the shm while
+        * the session daemon is launching, causing the second attempt
+        * to fail. This is not recovered-from as unlinking the shm will
+        * prevent userspace tracing from succeeding anyhow: the sessiond would
+        * use a now-unlinked shm, while the next application would create
+        * a new named shm.
+        */
+       wait_shm_fd = shm_open(shm_path, O_RDWR | O_CREAT, mode);
+       if (wait_shm_fd < 0) {
+               if (errno == EACCES) {
+                       /* Work around sysctl fs.protected_regular. */
+                       DBG("shm_open of %s returned EACCES, this may be caused "
+                                       "by the fs.protected_regular sysctl. "
+                                       "Attempting to open the shm without "
+                                       "creating it.", shm_path);
+                       wait_shm_fd = shm_open(shm_path, O_RDWR, mode);
+               }
+               if (wait_shm_fd < 0) {
+                       PERROR("Failed to open wait shm at %s", shm_path);
+                       goto error;
+               }
+       }
+
+       ret = ftruncate(wait_shm_fd, mmap_size);
+       if (ret < 0) {
+               PERROR("ftruncate wait shm");
+               exit(EXIT_FAILURE);
+       }
+
+       if (global) {
+               ret = fchown(wait_shm_fd, 0, 0);
+               if (ret < 0) {
+                       PERROR("fchown");
+                       exit(EXIT_FAILURE);
+               }
+               /*
+                * If global session daemon, any application can
+                * register so the shm needs to be set in read-only mode
+                * for others.
+                */
+               mode &= ~S_IWOTH;
+               ret = fchmod(wait_shm_fd, mode);
+               if (ret < 0) {
+                       PERROR("fchmod");
+                       exit(EXIT_FAILURE);
+               }
+       } else {
+               ret = fchown(wait_shm_fd, getuid(), getgid());
+               if (ret < 0) {
+                       PERROR("fchown");
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       DBG("Got the wait shm fd %d", wait_shm_fd);
+
+       return wait_shm_fd;
+
+error:
+       DBG("Failing to get the wait shm fd");
+
+       return -1;
+}
+
+/*
+ * Return the wait shm mmap for UST application notification. The global
+ * variable is used to indicate if the the session daemon is global
+ * (root:tracing) or running with an unprivileged user.
+ *
+ * This returned value is used by futex_wait_update() in futex.c to WAKE all
+ * waiters which are UST application waiting for a session daemon.
+ */
+char *shm_ust_get_mmap(char *shm_path, int global)
+{
+       size_t mmap_size;
+       int wait_shm_fd, ret;
+       char *wait_shm_mmap;
+       long sys_page_size;
+
+       assert(shm_path);
+
+       sys_page_size = sysconf(_SC_PAGE_SIZE);
+       if (sys_page_size < 0) {
+               PERROR("sysconf PAGE_SIZE");
+               goto error;
+       }
+       mmap_size = sys_page_size;
+
+       wait_shm_fd = get_wait_shm(shm_path, mmap_size, global);
+       if (wait_shm_fd < 0) {
+               goto error;
+       }
+
+       wait_shm_mmap = mmap(NULL, mmap_size, PROT_WRITE | PROT_READ,
+                       MAP_SHARED, wait_shm_fd, 0);
+
+       /* close shm fd immediately after taking the mmap reference */
+       ret = close(wait_shm_fd);
+       if (ret) {
+               PERROR("Error closing fd");
+       }
+
+       if (wait_shm_mmap == MAP_FAILED) {
+               DBG("mmap error (can be caused by race with ust).");
+               goto error;
+       }
+
+       return wait_shm_mmap;
+
+error:
+       return NULL;
+}
+
+/*
+ * shm_create_anonymous is never called concurrently within a process.
+ */
+int shm_create_anonymous(const char *owner_name)
+{
+       char tmp_name[NAME_MAX];
+       int shmfd, ret;
+
+       ret = snprintf(tmp_name, NAME_MAX, "/shm-%s-%d", owner_name, getpid());
+       if (ret < 0) {
+               PERROR("snprintf");
+               return -1;
+       }
+       /*
+        * Allocate shm, and immediately unlink its shm oject, keeping only the
+        * file descriptor as a reference to the object.
+        */
+       shmfd = shm_open(tmp_name, O_CREAT | O_EXCL | O_RDWR, 0700);
+       if (shmfd < 0) {
+               PERROR("shm_open");
+               goto error_shm_open;
+       }
+       ret = shm_unlink(tmp_name);
+       if (ret < 0 && errno != ENOENT) {
+               PERROR("shm_unlink");
+               goto error_shm_release;
+       }
+       return shmfd;
+
+error_shm_release:
+       ret = close(shmfd);
+       if (ret) {
+               PERROR("close");
+       }
+error_shm_open:
+       return -1;
+}
diff --git a/src/common/shm.h b/src/common/shm.h
new file mode 100644 (file)
index 0000000..d714506
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef _LTT_SHM_H
+#define _LTT_SHM_H
+
+char *shm_ust_get_mmap(char *shm_path, int global);
+
+int shm_create_anonymous(const char *owner_name);
+
+#endif /* _LTT_SHM_H */
index 71162e79bad63154b070b323ef75560ae89a72aa..9e0333be9e44e517f335fedb389e7fdea04958ee 100644 (file)
@@ -7,13 +7,14 @@
 
 #include <lttng/trigger/trigger-internal.h>
 #include <lttng/condition/condition-internal.h>
-#include <lttng/condition/event-rule-internal.h>
-#include <lttng/condition/event-rule.h>
-#include <lttng/condition/event-rule-internal.h>
+#include <lttng/condition/on-event-internal.h>
+#include <lttng/condition/on-event.h>
+#include <lttng/condition/on-event-internal.h>
 #include <lttng/condition/buffer-usage.h>
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/event-expr-internal.h>
 #include <lttng/action/action-internal.h>
+#include <lttng/action/group.h>
 #include <common/credentials.h>
 #include <common/payload.h>
 #include <common/payload-view.h>
@@ -92,7 +93,6 @@ const struct lttng_condition *lttng_trigger_get_const_condition(
        return trigger ? trigger->condition : NULL;
 }
 
-
 /*
  * Note: the lack of reference counting 'get' on the action object is normal.
  * This API was exposed as such in 2.11. The client is not expected to call
@@ -395,8 +395,13 @@ bool lttng_trigger_is_equal(
        }
 
        /*
-        * Name is not taken into account since it is cosmetic only.
+        * FIXME: frdeso: this is a change of behavior.
+        * See internal tracker issue 1028.
         */
+       if (strcmp(a->name, b->name) != 0) {
+               return false;
+       }
+
        if (!lttng_condition_is_equal(a->condition, b->condition)) {
                return false;
        }
@@ -909,9 +914,9 @@ enum lttng_domain_type lttng_trigger_get_underlying_domain_type_restriction(
                /* Apply to any domain. */
                type = LTTNG_DOMAIN_NONE;
                break;
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
                /* Return the domain of the event rule. */
-               c_status = lttng_condition_event_rule_get_rule(
+               c_status = lttng_condition_on_event_get_rule(
                                trigger->condition, &event_rule);
                assert(c_status == LTTNG_CONDITION_STATUS_OK);
                type = lttng_event_rule_get_domain_type(event_rule);
@@ -949,11 +954,11 @@ enum lttng_error_code lttng_trigger_generate_bytecode(
        }
 
        switch (lttng_condition_get_type(condition)) {
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
        {
                struct lttng_event_rule *event_rule;
                const enum lttng_condition_status condition_status =
-                               lttng_condition_event_rule_borrow_rule_mutable(
+                               lttng_condition_on_event_borrow_rule_mutable(
                                        condition, &event_rule);
 
                assert(condition_status == LTTNG_CONDITION_STATUS_OK);
@@ -966,7 +971,7 @@ enum lttng_error_code lttng_trigger_generate_bytecode(
                }
 
                /* Generate the capture bytecode. */
-               ret = lttng_condition_event_rule_generate_capture_descriptor_bytecode(
+               ret = lttng_condition_on_event_generate_capture_descriptor_bytecode(
                                condition);
                if (ret != LTTNG_OK) {
                        goto end;
@@ -1013,3 +1018,88 @@ end:
        lttng_payload_reset(&copy_buffer);
        return copy;
 }
+
+
+static
+bool action_type_needs_tracer_notifier(enum lttng_action_type action_type)
+{
+       switch (action_type) {
+       case LTTNG_ACTION_TYPE_NOTIFY:
+       case LTTNG_ACTION_TYPE_START_SESSION:
+       case LTTNG_ACTION_TYPE_STOP_SESSION:
+       case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
+       case LTTNG_ACTION_TYPE_ROTATE_SESSION:
+               return true;
+       case LTTNG_ACTION_TYPE_INCREMENT_VALUE:
+               return false;
+       case LTTNG_ACTION_TYPE_GROUP:
+       case LTTNG_ACTION_TYPE_UNKNOWN:
+       default:
+               abort();
+       }
+}
+
+static
+bool action_needs_tracer_notifier(const struct lttng_action *action)
+{
+       bool needs_tracer_notifier = false;
+       unsigned int i, count;
+       enum lttng_action_status action_status;
+       enum lttng_action_type action_type;
+
+       assert(action);
+       /* If there is only one action. Check if it needs a tracer notifier. */
+       action_type = lttng_action_get_type(action);
+       if (action_type != LTTNG_ACTION_TYPE_GROUP) {
+               needs_tracer_notifier = action_type_needs_tracer_notifier(
+                               action_type);
+               goto end;
+       }
+
+       /*
+        * Iterate over all the actions of the action group and check if any of
+        * them needs a tracer notifier.
+        */
+       action_status = lttng_action_group_get_count(action, &count);
+       assert(action_status == LTTNG_ACTION_STATUS_OK);
+       for (i = 0; i < count; i++) {
+               const struct lttng_action *inner_action =
+                               lttng_action_group_get_at_index(action, i);
+
+               action_type = lttng_action_get_type(inner_action);
+               if (action_type_needs_tracer_notifier(action_type)) {
+                       needs_tracer_notifier = true;
+                       goto end;
+               }
+       }
+
+end:
+       return needs_tracer_notifier;
+}
+
+LTTNG_HIDDEN
+bool lttng_trigger_needs_tracer_notifier(const struct lttng_trigger *trigger)
+{
+       bool needs_tracer_notifier = false;
+       const struct lttng_condition *condition =
+                       lttng_trigger_get_const_condition(trigger);
+       const struct lttng_action *action =
+                       lttng_trigger_get_const_action(trigger);
+
+       switch (lttng_condition_get_type(condition)) {
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
+               needs_tracer_notifier = action_needs_tracer_notifier(action);
+               goto end;
+       case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+               goto end;
+       case LTTNG_CONDITION_TYPE_UNKNOWN:
+       default:
+               abort();
+       }
+end:
+       return needs_tracer_notifier;
+}
index 6b195c77ddae86a3e2d1ca27d6ce92d821819c3d..017ea5fb8451e7da069521729f2e1dd7501cd126 100644 (file)
@@ -37,6 +37,7 @@
 #include <common/utils.h>
 #include <common/index/index.h>
 #include <common/consumer/consumer.h>
+#include <common/shm.h>
 #include <common/optional.h>
 
 #include "ust-consumer.h"
@@ -352,48 +353,6 @@ error_alloc:
        return ret;
 }
 
-/*
- * create_posix_shm is never called concurrently within a process.
- */
-static
-int create_posix_shm(void)
-{
-       char tmp_name[NAME_MAX];
-       int shmfd, ret;
-
-       ret = snprintf(tmp_name, NAME_MAX, "/ust-shm-consumer-%d", getpid());
-       if (ret < 0) {
-               PERROR("snprintf");
-               return -1;
-       }
-       /*
-        * Allocate shm, and immediately unlink its shm oject, keeping
-        * only the file descriptor as a reference to the object.
-        * We specifically do _not_ use the / at the beginning of the
-        * pathname so that some OS implementations can keep it local to
-        * the process (POSIX leaves this implementation-defined).
-        */
-       shmfd = shm_open(tmp_name, O_CREAT | O_EXCL | O_RDWR, 0700);
-       if (shmfd < 0) {
-               PERROR("shm_open");
-               goto error_shm_open;
-       }
-       ret = shm_unlink(tmp_name);
-       if (ret < 0 && errno != ENOENT) {
-               PERROR("shm_unlink");
-               goto error_shm_release;
-       }
-       return shmfd;
-
-error_shm_release:
-       ret = close(shmfd);
-       if (ret) {
-               PERROR("close");
-       }
-error_shm_open:
-       return -1;
-}
-
 static int open_ust_stream_fd(struct lttng_consumer_channel *channel, int cpu,
                const struct lttng_credentials *session_credentials)
 {
@@ -401,7 +360,7 @@ static int open_ust_stream_fd(struct lttng_consumer_channel *channel, int cpu,
        int ret;
 
        if (!channel->shm_path[0]) {
-               return create_posix_shm();
+               return shm_create_anonymous("ust-consumer");
        }
        ret = get_stream_shm_path(shm_path, channel->shm_path, cpu);
        if (ret) {
index 134d2054fbde1ea74de3a8562c93c13067bfcf53..df409aa4cc6ddde35c81cda88f7b4ef7f6330894 100644 (file)
@@ -1486,6 +1486,16 @@ fopen_error:
        return ret;
 }
 
+LTTNG_HIDDEN
+int utils_get_number_of_possible_cpus(void)
+{
+       /*
+        * Return the number of configured cpus as opposed to number of online
+        * cpus.
+        */
+       return sysconf(_SC_NPROCESSORS_CONF);
+}
+
 /*
  * Returns an estimate of the number of bytes of memory available based on the
  * the information in `/proc/meminfo`. The number returned by this function is
index 570216d53c9709dddcfaf480f68a465bc0a8f294..6fb5b2dfdc8de2f3ee8ac03d79b596a1fc910caf 100644 (file)
@@ -53,6 +53,7 @@ int utils_truncate_stream_file(int fd, off_t length);
 int utils_show_help(int section, const char *page_name, const char *help_msg);
 int utils_get_memory_available(size_t *value);
 int utils_get_memory_total(size_t *value);
+int utils_get_number_of_possible_cpus(void);
 int utils_change_working_directory(const char *path);
 enum lttng_error_code utils_user_id_from_name(
                const char *user_name, uid_t *user_id);
index 6deab78486efe7b69c18645481ccc23b065b600a..8cb1e9b4ed26607ae381a76dd864e1e56493bdc6 100644 (file)
@@ -10,6 +10,7 @@
  *
  */
 
+#include "lttng/domain.h"
 #define _LGPL_SOURCE
 #include <assert.h>
 #include <grp.h>
@@ -38,6 +39,8 @@
 #include <lttng/event-internal.h>
 #include <lttng/health-internal.h>
 #include <lttng/lttng.h>
+#include <lttng/map/map-internal.h>
+#include <lttng/map/map-query-internal.h>
 #include <lttng/session-descriptor-internal.h>
 #include <lttng/session-internal.h>
 #include <lttng/trigger/trigger-internal.h>
@@ -1212,10 +1215,16 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle,
                }
 
                ret = lttng_dynamic_buffer_append(&payload.buffer,
-                               *(exclusion_list + i), LTTNG_SYMBOL_NAME_LEN);
+                               exclusion_list[i], exclusion_len);
                if (ret) {
                        goto mem_error;
                }
+
+               for (int i = 0; i < (LTTNG_SYMBOL_NAME_LEN - exclusion_len); i++) {
+                       char c = 0;
+
+                       lttng_dynamic_buffer_append(&payload.buffer, &c, 1);
+               }
        }
 
        /* Add filter expression next. */
@@ -1636,6 +1645,178 @@ end:
        return ret;
 }
 
+enum lttng_error_code lttng_add_map(struct lttng_handle *handle,
+               struct lttng_map *map)
+{
+
+       int ret;
+       enum lttng_error_code ret_code;
+       struct lttcomm_session_msg lsm = {
+               .cmd_type = LTTNG_ADD_MAP,
+       };
+       struct lttcomm_session_msg *message_lsm;
+       struct lttng_payload message;
+       struct lttng_payload reply;
+
+       lttng_payload_init(&message);
+       lttng_payload_init(&reply);
+
+       if (!map) {
+               ret_code = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       lsm.domain.type = lttng_map_get_domain(map);
+
+       lttng_strncpy(lsm.session.name, handle->session_name,
+                       sizeof(lsm.session.name));
+
+       ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+       if (ret) {
+               ret_code = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
+
+       ret = lttng_map_serialize(map, &message);
+       if (ret < 0) {
+               ret_code = LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       message_lsm->u.add_map.length = (uint32_t) message.buffer.size - sizeof(lsm);
+
+       {
+               struct lttng_payload_view message_view =
+                       lttng_payload_view_from_payload(&message, 0, -1);
+
+               message_lsm->fd_count = lttng_payload_view_get_fd_handle_count(
+                               &message_view);
+
+               ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply);
+               if (ret < 0) {
+                       ret_code = ret;
+                       goto end;
+               }
+       }
+
+       ret_code = LTTNG_OK;
+
+end:
+       lttng_payload_reset(&message);
+       lttng_payload_reset(&reply);
+       return ret_code;
+}
+
+enum lttng_error_code lttng_enable_map(struct lttng_handle *handle,
+               const char *map_name)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       struct lttcomm_session_msg lsm;
+       struct lttng_payload message;
+       struct lttng_payload_view lsm_view =
+                       lttng_payload_view_init_from_buffer(
+                               (const char *) &lsm, 0, sizeof(lsm));
+       struct lttng_payload reply;
+
+       lttng_payload_init(&message);
+       lttng_payload_init(&reply);
+
+       memset(&lsm, 0, sizeof(lsm));
+       lsm.cmd_type = LTTNG_ENABLE_MAP;
+
+       COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
+
+       ret = lttng_strncpy(lsm.session.name, handle->session_name,
+                       sizeof(lsm.session.name));
+       if (ret) {
+               ret_code = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = lttng_strncpy(lsm.u.enable_map.map_name, map_name,
+                       sizeof(lsm.u.enable_map.map_name));
+       if (ret) {
+               ret_code = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+       if (ret) {
+               ret_code = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       ret = lttng_ctl_ask_sessiond_payload(&lsm_view, &reply);
+       if (ret < 0) {
+               ret_code = LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       ret_code = LTTNG_OK;
+
+end:
+       lttng_payload_reset(&message);
+       lttng_payload_reset(&reply);
+       return ret_code;
+}
+
+enum lttng_error_code lttng_disable_map(struct lttng_handle *handle,
+               const char *map_name)
+{
+       int ret;
+       enum lttng_error_code ret_code;
+       struct lttcomm_session_msg lsm;
+       struct lttng_payload message;
+       struct lttng_payload_view lsm_view =
+                       lttng_payload_view_init_from_buffer(
+                               (const char *) &lsm, 0, sizeof(lsm));
+       struct lttng_payload reply;
+
+       lttng_payload_init(&message);
+       lttng_payload_init(&reply);
+
+       memset(&lsm, 0, sizeof(lsm));
+       lsm.cmd_type = LTTNG_DISABLE_MAP;
+
+       COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
+
+       ret = lttng_strncpy(lsm.session.name, handle->session_name,
+                       sizeof(lsm.session.name));
+       if (ret) {
+               ret_code = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = lttng_strncpy(lsm.u.disable_map.map_name, map_name,
+                       sizeof(lsm.u.disable_map.map_name));
+       if (ret) {
+               ret_code = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+       if (ret) {
+               ret_code = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       ret = lttng_ctl_ask_sessiond_payload(&lsm_view, &reply);
+       if (ret < 0) {
+               ret_code = LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       ret_code = LTTNG_OK;
+
+end:
+       lttng_payload_reset(&message);
+       lttng_payload_reset(&reply);
+       return ret_code;
+}
+
 /*
  * All tracing will be stopped for registered events of the channel.
  * Returns size of returned session payload data or a negative error code.
@@ -2276,6 +2457,61 @@ end:
        return ret;
 }
 
+enum lttng_error_code lttng_list_maps(struct lttng_handle *handle,
+               struct lttng_map_list **map_list)
+{
+       int ret;
+       enum lttng_error_code ret_code = LTTNG_OK;
+       struct lttcomm_session_msg lsm = { .cmd_type = LTTNG_LIST_MAPS };
+       struct lttng_map_list *local_map_list = NULL;
+       struct lttng_payload reply;
+       struct lttng_payload_view lsm_view =
+                       lttng_payload_view_init_from_buffer(
+                               (const char *) &lsm, 0, sizeof(lsm));
+
+       lttng_payload_init(&reply);
+
+       if (handle == NULL) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = lttng_strncpy(lsm.session.name, handle->session_name,
+                       sizeof(lsm.session.name));
+       if (ret) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
+
+       ret = lttng_ctl_ask_sessiond_payload(&lsm_view, &reply);
+       if (ret < 0) {
+               ret_code = (enum lttng_error_code) -ret;
+               goto end;
+       }
+
+       {
+               struct lttng_payload_view reply_view =
+                               lttng_payload_view_from_payload(
+                                               &reply, 0, reply.buffer.size);
+
+               ret = lttng_map_list_create_from_payload(
+                               &reply_view, &local_map_list);
+               if (ret < 0) {
+                       ret_code = LTTNG_ERR_FATAL;
+                       goto end;
+               }
+       }
+
+       *map_list = local_map_list;
+       local_map_list = NULL;
+end:
+       lttng_payload_reset(&reply);
+       lttng_map_list_destroy(local_map_list);
+       return ret_code;
+}
+
 /*
  * Ask the session daemon for all available events of a session channel.
  * Sets the contents of the events array.
@@ -3352,6 +3588,101 @@ end:
        return ret_code;
 }
 
+/*
+ * Ask the session daemon for all values for a given map.
+ * On error, returns a negative value.
+ */
+enum lttng_error_code lttng_list_map_content(
+               struct lttng_handle *handle, const struct lttng_map *map,
+               const struct lttng_map_query *map_query,
+               struct lttng_map_content **map_content)
+{
+       struct lttcomm_session_msg lsm = {
+               .cmd_type = LTTNG_LIST_MAP_VALUES,
+       };
+       struct lttcomm_session_msg *message_lsm;
+       struct lttng_payload message;
+       struct lttng_payload reply;
+       enum lttng_error_code ret;
+       struct lttng_map_content *local_map_content = NULL;
+       uint32_t map_length, map_query_length;
+
+       lttng_payload_init(&message);
+       lttng_payload_init(&reply);
+
+       if (!map || !map_query) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       lsm.domain.type = handle->domain.type;
+       ret = lttng_strncpy(lsm.session.name, handle->session_name,
+               sizeof(lsm.session.name));
+       if (ret) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+       if (ret) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       ret = lttng_map_serialize(map, &message);
+       if (ret < 0) {
+               ret = -LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       map_length = (uint32_t) message.buffer.size - sizeof(lsm);
+
+       ret = lttng_map_query_serialize(map_query, &message);
+       if (ret < 0) {
+               ret = -LTTNG_ERR_UNK;
+               goto end;
+       }
+       map_query_length = (uint32_t) message.buffer.size - map_length - sizeof(lsm);
+
+       message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
+       message_lsm->u.list_map_values.map_length = map_length;
+       message_lsm->u.list_map_values.query_length = map_query_length;
+       {
+               struct lttng_payload_view message_view =
+                               lttng_payload_view_from_payload(
+                                               &message, 0, -1);
+
+               ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply);
+               if (ret < 0) {
+                       goto end;
+               }
+       }
+
+
+       {
+               struct lttng_payload_view reply_view =
+                               lttng_payload_view_from_payload(
+                                               &reply, 0, reply.buffer.size);
+               ret = lttng_map_content_create_from_payload(
+                       &reply_view, &local_map_content);
+               if (ret < 0) {
+                       ret = LTTNG_ERR_FATAL;
+                       goto end;
+               }
+       }
+
+       *map_content = local_map_content;
+       local_map_content = NULL;
+
+       ret = LTTNG_OK;
+       goto end;
+end:
+       lttng_payload_reset(&reply);
+       lttng_payload_reset(&message);
+       lttng_map_content_destroy(local_map_content);
+       return ret;
+}
+
 /*
  * lib constructor.
  */
index 817918f68e66c29acd3e0a4c44ad40ec6000f5e0..ec91e3b56da173ed80fe2b65fff52b56b8c30b6c 100644 (file)
@@ -27,13 +27,17 @@ TESTS = tools/filtering/test_invalid_filter \
        tools/crash/test_crash \
        tools/regen-metadata/test_ust \
        tools/regen-statedump/test_ust \
+       tools/map/test_map_kernel \
        tools/notification/test_notification_ust_error \
        tools/notification/test_notification_ust_buffer_usage \
+       tools/notification/test_notification_ust_capture \
        tools/notification/test_notification_ust_event_rule_condition_exclusion \
        tools/notification/test_notification_kernel_error \
        tools/notification/test_notification_kernel_buffer_usage \
+       tools/notification/test_notification_kernel_capture \
        tools/notification/test_notification_kernel_instrumentation \
        tools/notification/test_notification_kernel_syscall \
+       tools/notification/test_notification_notifier_discarded_count \
        tools/notification/test_notification_kernel_userspace_probe \
        tools/notification/test_notification_multi_app \
        tools/rotation/test_ust \
@@ -68,6 +72,7 @@ TESTS += ust/before-after/test_before_after \
        ust/blocking/test_blocking \
        ust/multi-lib/test_multi_lib \
        ust/rotation-destroy-flush/test_rotation_destroy_flush \
+       tools/map/test_map_ust \
        tools/metadata/test_ust \
        tools/relayd-grouping/test_ust
 
index 8547efd675b937e72ba5509b3d7bb89ee26266d8..f06f51528fb75b093238caeacb6589d9af34e7b9 100644 (file)
@@ -1,11 +1,18 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-EXTRA_DIST = test_event_basic test_all_events test_syscall \
-               test_clock_override test_rotation_destroy_flush \
-               test_select_poll_epoll test_lttng_logger \
-               test_userspace_probe test_callstack \
-               test_syscall validate_select_poll_epoll.py \
-               test_ns_contexts test_ns_contexts_change
+EXTRA_DIST = test_all_events test_syscall \
+                                                test_callstack \
+                                                test_clock_override \
+                                                test_event_basic \
+                                                test_kernel_function \
+                                                test_lttng_logger \
+                                                test_ns_contexts \
+                                                test_ns_contexts_change
+                                                test_rotation_destroy_flush \
+                                                test_select_poll_epoll \
+                                                test_syscall \
+                                                test_userspace_probe \
+                                                validate_select_poll_epoll.py
 
 noinst_PROGRAMS = select_poll_epoll
 select_poll_epoll_SOURCES = select_poll_epoll.c
diff --git a/tests/regression/kernel/test_kernel_function b/tests/regression/kernel/test_kernel_function
new file mode 100755 (executable)
index 0000000..47deb92
--- /dev/null
@@ -0,0 +1,62 @@
+#!/bin/bash
+#
+# Copyright (C) 2013 Christian Babeux <christian.babeux@efficios.com>
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+TEST_DESC="Kernel tracer - function event"
+
+CURDIR=$(dirname $0)/
+TESTDIR=$CURDIR/../..
+NUM_TESTS=6
+
+source $TESTDIR/utils/utils.sh
+
+function test_kernel_function_basic()
+{
+       local TRACE_PATH=$(mktemp -d)
+       local SESSION_NAME="kernel_function_basic"
+       local EVENT_NAME="my_event_name"
+       local TARGET_SYMBOL="lttng_test_filter_event_write"
+
+       create_lttng_session_ok $SESSION_NAME $TRACE_PATH
+
+       lttng_enable_kernel_function_event_ok $SESSION_NAME "$TARGET_SYMBOL" "$EVENT_NAME"
+
+       start_lttng_tracing_ok
+
+       echo 1 > /proc/lttng-test-filter-event
+
+       stop_lttng_tracing_ok
+
+       validate_trace "${EVENT_NAME}_entry" $TRACE_PATH
+       validate_trace "${EVENT_NAME}_return" $TRACE_PATH
+
+       destroy_lttng_session_ok $SESSION_NAME
+
+       rm -rf $TRACE_PATH
+}
+
+# MUST set TESTDIR before calling those functions
+plan_tests $NUM_TESTS
+
+print_test_banner "$TEST_DESC"
+
+if [ "$(id -u)" == "0" ]; then
+       isroot=1
+else
+       isroot=0
+fi
+
+skip $isroot "Root access is needed. Skipping all tests." $NUM_TESTS ||
+{
+       start_lttng_sessiond_notap
+       validate_lttng_modules_present
+       modprobe lttng-test
+
+       test_kernel_function_basic
+
+       modprobe --remove lttng-test
+       stop_lttng_sessiond_notap
+}
index d561a647959e6a12d3769379fbdb84a33a523aaa..1aa0b6c6a35ba16bacb34e09d559d6167b72927e 100644 (file)
@@ -2,4 +2,4 @@
 
 SUBDIRS = streaming filtering health tracefile-limits snapshots live exclusion save-load mi \
                wildcard crash regen-metadata regen-statedump notification rotation \
-               base-path metadata working-directory relayd-grouping clear tracker trigger
+               base-path map metadata working-directory relayd-grouping clear tracker trigger
diff --git a/tests/regression/tools/map/Makefile.am b/tests/regression/tools/map/Makefile.am
new file mode 100644 (file)
index 0000000..8fb83c3
--- /dev/null
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+AM_CPPFLAGS += -I$(top_srcdir)/tests -I$(srcdir)
+
+noinst_SCRIPTS = \
+       map_base_test.sh \
+       test_map_kernel
+
+EXTRA_DIST = \
+       map_base_test.sh \
+       test_map_kernel
+
+if HAVE_LIBLTTNG_UST_CTL
+EXTRA_DIST += test_map_ust
+noinst_SCRIPTS += test_map_ust
+endif
+
+all-local:
+       @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
+               for script in $(EXTRA_DIST); do \
+                       cp -f $(srcdir)/$$script $(builddir); \
+               done; \
+       fi
+
+clean-local:
+       @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
+               for script in $(EXTRA_DIST); do \
+                       rm -f $(builddir)/$$script; \
+               done; \
+       fi
diff --git a/tests/regression/tools/map/map_base_test.sh b/tests/regression/tools/map/map_base_test.sh
new file mode 100644 (file)
index 0000000..ae75849
--- /dev/null
@@ -0,0 +1,578 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+
+CURDIR=$(dirname "$0")/
+TESTDIR=$CURDIR/../../..
+
+TMPDIR=$(mktemp -d)
+
+SH_TAP=1
+
+# shellcheck source=../../../utils/utils.sh
+source "$TESTDIR/utils/utils.sh"
+
+FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}"
+
+function view_map_ok() {
+       local map_name="$1"
+       local key="$2"
+       local expected_value="$3"
+       local extracted_value
+       local temp_view_output
+
+       temp_view_output=$(mktemp -t map_view_output.XXXXXX)
+
+       "$FULL_LTTNG_BIN" view-map "$map_name" --key="$key" > "$temp_view_output"
+       ok $? "Map '$map_name' viewed succesfully"
+
+       grep -q " $key " "$temp_view_output"
+       ok $? "Key '$key' found in view-map output"
+
+       # Get value
+       # TODO: this is based on the text output, ideally when mi is availabe we
+       # who should use it to parse the value!
+       # Sample output
+       # | key | 5|
+       # Keep white space surrounding the key so to avoid grepping a substring
+       # in a larger key.
+       extracted_value=$(grep " $key " "$temp_view_output" | tr -d " " | cut -d "|" -f3)
+       # Necessary since the returned value can be non existent
+       extracted_value=${extracted_value:-"-1"}
+
+       is "$extracted_value" "$expected_value" "Key value is $expected_value as expected"
+
+       rm -f "$temp_view_output"
+}
+
+function test_map_view_empty()
+{
+       local domain="$1"
+       local bitness="$2"
+       local buf_option="$3"
+
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+
+       diag "Map view empty: $domain bitness $bitness $buf_option"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       "$FULL_LTTNG_BIN" view-map "$MAP_NAME" > /dev/null
+       ok $? "Map enabled viewed succesfully"
+
+       "$FULL_LTTNG_BIN" disable-map "$domain" "$MAP_NAME" > /dev/null
+       ok $? "Map disabled succesfully"
+
+       "$FULL_LTTNG_BIN" view-map "$MAP_NAME" > /dev/null
+       ok $? "Map disabled viewed succesfully"
+
+       destroy_lttng_session_ok "$SESSION_NAME"
+}
+
+function test_map_formated_keys()
+{
+       local domain="$1"
+       local event_name="$2"
+       local key_format="$3"
+       local expected_key="$4"
+       local test_app="$5"
+
+       local bitness="32"
+       # buf option left empty for use with both UST and kernel domain.
+       local buf_option=""
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+
+       diag "Map with $domain formated key. event-name: \"$event_name\", key format: \"$key_format\", expecting: \"$expected_key\""
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event "$domain" "$event_name" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$key_format"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       $test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$expected_key" "$NR_ITER"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_n_triggers_n_keys()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="$1"
+       local bitness="$2"
+       local event_name="$3"
+       local test_app="$4"
+       local buf_option=""
+
+       local number_of_trigger=5
+
+       diag "Map $domain with $number_of_trigger triggers with all different keys"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       for i in $(seq 1 $number_of_trigger); do
+               cur_trigger_name="${TRIGGER_NAME}${i}"
+               lttng_add_trigger_ok "$cur_trigger_name" \
+                       --condition \
+                               on-event "$domain" "$event_name" \
+                       --action \
+                               incr-value --session "$SESSION_NAME" \
+                               --map "$MAP_NAME" \
+                               --key "${KEY}${i}"
+       done
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       $test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       for i in $(seq 1 $number_of_trigger); do
+               view_map_ok "$MAP_NAME" "$KEY${i}" "$NR_ITER"
+       done
+
+       for i in $(seq 1 $number_of_trigger); do
+               lttng_remove_trigger_ok "$TRIGGER_NAME${i}"
+       done
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_n_triggers_1_key()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="$1"
+       local bitness="$2"
+       local event_name="$3"
+       local test_app="$4"
+       local buf_option=""
+
+       local number_of_trigger=5
+
+       diag "Map $domain with $number_of_trigger triggers all with the same key"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       for i in $(seq 1 $number_of_trigger); do
+               cur_trigger_name="${TRIGGER_NAME}${i}"
+               lttng_add_trigger_ok "$cur_trigger_name" \
+                       --condition \
+                               on-event "$domain" "$event_name" \
+                       --action \
+                               incr-value --session "$SESSION_NAME" \
+                               --map "$MAP_NAME" \
+                               --key "${KEY}"
+       done
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       $test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$((NR_ITER * number_of_trigger))"
+
+       for i in $(seq 1 $number_of_trigger); do
+               lttng_remove_trigger_ok "$TRIGGER_NAME${i}"
+       done
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_n_triggers_1_key_coalesced()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="$1"
+       local bitness="$2"
+       local event_name="$3"
+       local test_app="$4"
+       local buf_option=""
+
+       local number_of_trigger=5
+
+       diag "Map $domain with $number_of_trigger triggers all with the same key"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option" "--coalesce-hits"
+
+       for i in $(seq 1 $number_of_trigger); do
+               cur_trigger_name="${TRIGGER_NAME}${i}"
+               lttng_add_trigger_ok "$cur_trigger_name" \
+                       --condition \
+                               on-event "$domain" "$event_name" \
+                       --action \
+                               incr-value --session "$SESSION_NAME" \
+                               --map "$MAP_NAME" \
+                               --key "${KEY}"
+       done
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       $test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       # With the `coalesce-hits` map option two enablers on the same event
+       # with the same key will only increment the counter once.
+       view_map_ok "$MAP_NAME" "$KEY" "$((NR_ITER))"
+
+       for i in $(seq 1 $number_of_trigger); do
+               lttng_remove_trigger_ok "$TRIGGER_NAME${i}"
+       done
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_disable_enable()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="$1"
+       local bitness="$2"
+       local event_name="$3"
+       local test_app="$4"
+       local buf_option=""
+
+       diag "Map $domain disable-enable --bitness $bitness"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event "$domain" "$event_name" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       $test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$NR_ITER"
+
+       "$FULL_LTTNG_BIN" disable-map "$domain" -s "$SESSION_NAME" "$MAP_NAME" > /dev/null
+       ok $? "Map disabled succesfully"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       $test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       # The values in the map should not have changed since the map is
+       # disabled.
+       view_map_ok "$MAP_NAME" "$KEY" "$NR_ITER"
+
+       "$FULL_LTTNG_BIN" enable-map "$domain" -s "$SESSION_NAME" "$MAP_NAME" > /dev/null
+       ok $? "Map enabled succesfully"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       $test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$((NR_ITER * 2))"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_add_remove_add_trigger()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="$1"
+       local bitness="$2"
+       local event_name="$3"
+       local test_app="$4"
+       local buf_option=""
+
+       diag "Map $domain add-remove-add the same trigger"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event "$domain" "$event_name" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       "$test_app"
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$NR_ITER"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       "$test_app"
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$NR_ITER"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event "$domain" "$event_name" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       "$test_app"
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$((NR_ITER * 2))"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_creation_after_trigger()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="$1"
+       local bitness="$2"
+       local event_name="$3"
+       local test_app="$4"
+       local buf_option=""
+
+       diag "Map $domain creation after trigger creation"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event "$domain" "$event_name" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       "$test_app"
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$NR_ITER"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_remove_trigger_before_stop()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="$1"
+       local bitness="$2"
+       local event_name="$3"
+       local test_app="$4"
+       local buf_option=""
+
+       diag "Map remove trigger before stop"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event "$domain" "$event_name" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       "$test_app"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       view_map_ok "$MAP_NAME" "$KEY" "$NR_ITER"
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       # Confirm that the map content is unchanged after a stop.
+       view_map_ok "$MAP_NAME" "$KEY" "$NR_ITER"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_two_incr_value_two_keys()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY1="romados"
+       local KEY2="pitarifique"
+       local domain="$1"
+       local bitness="$2"
+       local event_name="$3"
+       local test_app="$4"
+       local buf_option=""
+
+       diag "Map remove trigger before stop"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event "$domain" "$event_name" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY1" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY2"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       "$test_app"
+
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY1" "$NR_ITER"
+       view_map_ok "$MAP_NAME" "$KEY2" "$NR_ITER"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_filter()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="$1"
+       local event_name="$2"
+       local filter_field="$3"
+       local test_app="$4"
+       local buf_option=""
+       local bitness="32"
+
+       diag "Map $domain filtering $event_name filter: \"$filter_field == 0\""
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event "$domain" "$event_name" --filter "$filter_field==0"\
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       $test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "1"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_clear()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="$1"
+       local bitness="$2"
+       local event_name="$3"
+       local test_app="$4"
+       local buf_option=""
+       local bitness="32"
+
+       diag "Map $domain clear"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event "$domain" "$event_name" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       $test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$NR_ITER"
+
+       lttng_clear_session_ok "$SESSION_NAME"
+
+       view_map_ok "$MAP_NAME" "$KEY" "0"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
diff --git a/tests/regression/tools/map/test_map_kernel b/tests/regression/tools/map/test_map_kernel
new file mode 100755 (executable)
index 0000000..3317e25
--- /dev/null
@@ -0,0 +1,322 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+
+CURDIR=$(dirname "$0")/
+TESTDIR=$CURDIR/../../..
+NR_ITER=5
+KERNEL_EVENT_NAME="lttng_test_filter_event"
+KERNEL_TEST_FILE_NAME="/proc/lttng-test-filter-event"
+TESTAPP_PATH="$TESTDIR/utils/testapp"
+TESTAPP_SYSCALL_BIN="$TESTAPP_PATH/gen-syscall-events/gen-syscall-events"
+TESTAPP_USERSPACE_BINARY="$TESTAPP_PATH/userspace-probe-elf-binary/.libs/userspace-probe-elf-binary"
+
+KERNEL_NUM_TESTS=421
+NUM_TESTS=$(($KERNEL_NUM_TESTS))
+
+TMPDIR=$(mktemp -d)
+
+SH_TAP=1
+
+# shellcheck source=../../../utils/utils.sh
+source "$TESTDIR/utils/utils.sh"
+source "$CURDIR/map_base_test.sh"
+
+FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}"
+
+plan_tests $NUM_TESTS
+
+function kernel_test_app()
+{
+       /bin/echo -n "$NR_ITER" > "$KERNEL_TEST_FILE_NAME"
+}
+
+function kernel_syscall_test_app()
+{
+       for i in $(seq 1 $NR_ITER)
+       do
+               "$TESTAPP_SYSCALL_BIN" /dev/null /proc/cpuinfo /proc/cmdline
+       done
+}
+
+function kernel_userspace_test_app()
+{
+       for i in $(seq 1 $NR_ITER)
+       do
+               "$TESTAPP_USERSPACE_BINARY"
+       done
+}
+
+function test_map_kernel_create()
+{
+       local MAP_NAME="my_map_name"
+       local MAP_NAME_2="my_map_name2"
+       local MAP_NAME_3="my_map_name3"
+       local MAP_NAME_4="my_map_name4"
+       local SESSION_NAME="my_session_name"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       "$FULL_LTTNG_BIN" add-map --kernel --bitness 32 --session "wrong_session_name" "$MAP_NAME" > /dev/null
+       isnt $? 0 "Map creation failed on wrong session name"
+
+       "$FULL_LTTNG_BIN" add-map --kernel --bitness 42 --session "$SESSION_NAME" "$MAP_NAME" > /dev/null
+       isnt $? 0 "Map creation failed \"--bitness\" wrong value as expected"
+
+       "$FULL_LTTNG_BIN" add-map --kernel --session "SESS_DOESNT_EXIST" "$MAP_NAME" > /dev/null
+       isnt $? 0 "Failed to add map to session that doesn't exist"
+
+       "$FULL_LTTNG_BIN" disable-map --kernel "MAP_DOESNT_EXIST" > /dev/null
+       isnt $? 0 "Failed to disable map that doesn't exist"
+
+       "$FULL_LTTNG_BIN" add-map --kernel --bitness 64 --session "$SESSION_NAME" "$MAP_NAME" > /dev/null
+       ok $? "Map with 64bit bitness created succesfully"
+
+       "$FULL_LTTNG_BIN" disable-map --kernel "$MAP_NAME" > /dev/null
+       ok $? "Map disabled succesfully"
+
+       "$FULL_LTTNG_BIN" add-map --kernel --bitness 32 --session "$SESSION_NAME" "$MAP_NAME_2" > /dev/null
+       ok $? "Map with 32bit bitness created succesfully"
+
+       "$FULL_LTTNG_BIN" add-map --kernel --session "$SESSION_NAME" "$MAP_NAME_2" > /dev/null
+       isnt $? 0 "Duplicated map fails to create as expected"
+
+       "$FULL_LTTNG_BIN" disable-map --kernel "$MAP_NAME_2" > /dev/null
+       ok $? "Map disabled succesfully"
+
+       "$FULL_LTTNG_BIN" add-map --kernel --session "$SESSION_NAME" "$MAP_NAME_3" > /dev/null
+       ok $? "Map with default bitness created succesfully"
+
+       "$FULL_LTTNG_BIN" disable-map --kernel "$MAP_NAME_3" > /dev/null
+       ok $? "Map removed succesfully"
+
+       "$FULL_LTTNG_BIN" add-map --kernel --session "$SESSION_NAME" --max-key-count 212 "$MAP_NAME_4" > /dev/null
+       ok $? "Map with max key count created succesfully"
+
+       "$FULL_LTTNG_BIN" disable-map --kernel "$MAP_NAME_4" > /dev/null
+       ok $? "Map disabled succesfully"
+
+       "$FULL_LTTNG_BIN" enable-map --kernel "$MAP_NAME_4" > /dev/null
+       ok $? "Map enabled succesfully"
+
+       destroy_lttng_session_ok "$SESSION_NAME"
+}
+
+function test_map_kernel_probe()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME_1="my_trigger_name_1"
+       local TRIGGER_NAME_2="my_trigger_name_2"
+       local TARGET_SYMBOL="lttng_test_filter_event_write"
+       local event_name_1="my_probe1"
+       local event_name_2="my_probe2"
+       local KEY="foo"
+
+       diag "Test map kernel probe"
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "--kernel" "32" ""
+
+       lttng_add_trigger_ok "$TRIGGER_NAME_1" \
+               --condition \
+                       on-event --kernel --probe="$TARGET_SYMBOL" "$event_name_1" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME_2" \
+               --condition \
+                       on-event --kernel --probe="$TARGET_SYMBOL" "$event_name_2" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "\${EVENT_NAME}"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       kernel_test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "1"
+       view_map_ok "$MAP_NAME" "$event_name_2" "1"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME_1"
+       lttng_remove_trigger_ok "$TRIGGER_NAME_2"
+
+       destroy_lttng_session_ok "$SESSION_NAME"
+}
+
+function test_map_kernel_function()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name_1"
+       local TARGET_SYMBOL="lttng_test_filter_event_write"
+       local event_name="my_probe1"
+       local KEY="foo"
+
+       diag "Test map kernel function"
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "--kernel" "32" ""
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event --kernel --function="$TARGET_SYMBOL" "$event_name" \
+               --action incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY" \
+               --action incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "\${EVENT_NAME}"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       kernel_test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "${KEY}" "2"
+       view_map_ok "$MAP_NAME" "${event_name}_entry" "1"
+       view_map_ok "$MAP_NAME" "${event_name}_return" "1"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok "$SESSION_NAME"
+}
+
+function test_map_kernel_syscall()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME_1="my_trigger_name_1"
+       local TRIGGER_NAME_2="my_trigger_name_2"
+       local FILE_1="/proc/cmdline"
+       local FILE_2="/proc/cpuinfo"
+       local TARGET_SYSCALL=openat
+       local KEY="foo"
+
+       diag "Test map kernel syscall"
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "--kernel" "32" ""
+
+       lttng_add_trigger_ok "$TRIGGER_NAME_1" \
+               --condition \
+                       on-event --kernel --syscall "$TARGET_SYSCALL" --filter "filename == \"$FILE_1\"" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME_2" \
+               --condition \
+                       on-event --kernel --syscall "$TARGET_SYSCALL" --filter "filename == \"$FILE_2\"" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "\${EVENT_NAME}"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       kernel_syscall_test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       # When using filtering on filename we only get hits on the entry event
+       # as it's the one having the filename argument.
+       view_map_ok "$MAP_NAME" "${KEY}" "$NR_ITER"
+       view_map_ok "$MAP_NAME" "syscall_entry_$TARGET_SYSCALL" "$NR_ITER"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME_1"
+       lttng_remove_trigger_ok "$TRIGGER_NAME_2"
+
+       destroy_lttng_session_ok "$SESSION_NAME"
+}
+
+function test_map_kernel_userspace_probe()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME_1="my_trigger_name_1"
+       local TEST_FUNCTION="test_function"
+       local KEY="foo"
+
+       diag "Test map kernel userspace probe"
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "--kernel" "32" ""
+
+       lttng_add_trigger_ok "$TRIGGER_NAME_1" \
+               --condition \
+                       on-event --kernel --userspace-probe="elf:$TESTAPP_USERSPACE_BINARY:$TEST_FUNCTION" event_name \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       kernel_userspace_test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$NR_ITER"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME_1"
+
+       destroy_lttng_session_ok "$SESSION_NAME"
+}
+
+if [ "$(id -u)" == "0" ]; then
+
+       start_lttng_sessiond_notap
+
+       validate_lttng_modules_present
+
+       modprobe lttng-test
+
+       test_map_kernel_create
+
+       test_map_formated_keys "--kernel" "$KERNEL_EVENT_NAME" "\${EVENT_NAME}" "$KERNEL_EVENT_NAME" kernel_test_app
+       test_map_formated_keys "--kernel" "$KERNEL_EVENT_NAME" "pitarifique-\${EVENT_NAME}" "pitarifique-$KERNEL_EVENT_NAME" kernel_test_app
+
+       test_map_view_empty "--kernel" "64" ""
+       test_map_view_empty "--kernel" "32" ""
+
+       test_map_n_triggers_n_keys "--kernel" "32" "$KERNEL_EVENT_NAME" kernel_test_app
+       test_map_n_triggers_n_keys "--kernel" "64" "$KERNEL_EVENT_NAME" kernel_test_app
+
+       test_map_n_triggers_1_key "--kernel" "32" "$KERNEL_EVENT_NAME" kernel_test_app
+       test_map_n_triggers_1_key "--kernel" "64" "$KERNEL_EVENT_NAME" kernel_test_app
+
+       test_map_n_triggers_1_key_coalesced "--kernel" "32" "$KERNEL_EVENT_NAME" kernel_test_app
+       test_map_n_triggers_1_key_coalesced "--kernel" "64" "$KERNEL_EVENT_NAME" kernel_test_app
+
+       test_map_disable_enable "--kernel" "32" "$KERNEL_EVENT_NAME" kernel_test_app
+       test_map_disable_enable "--kernel" "64" "$KERNEL_EVENT_NAME" kernel_test_app
+
+       test_map_add_remove_add_trigger "--kernel" "32" "$KERNEL_EVENT_NAME" kernel_test_app
+       test_map_add_remove_add_trigger "--kernel" "64" "$KERNEL_EVENT_NAME" kernel_test_app
+
+       test_map_creation_after_trigger "--kernel" "32" "$KERNEL_EVENT_NAME" kernel_test_app
+       test_map_creation_after_trigger "--kernel" "64" "$KERNEL_EVENT_NAME" kernel_test_app
+
+       test_map_remove_trigger_before_stop "--kernel" "32" "$KERNEL_EVENT_NAME" kernel_test_app
+       test_map_remove_trigger_before_stop "--kernel" "64" "$KERNEL_EVENT_NAME" kernel_test_app
+
+       test_map_two_incr_value_two_keys "--kernel" "64" "$KERNEL_EVENT_NAME" kernel_test_app
+
+       test_map_clear "--kernel" 32 "$KERNEL_EVENT_NAME" kernel_test_app
+       test_map_clear "--kernel" 64 "$KERNEL_EVENT_NAME" kernel_test_app
+
+       test_map_kernel_probe
+       test_map_kernel_function
+
+       test_map_kernel_syscall
+
+       test_map_kernel_userspace_probe
+
+       test_map_filter "--kernel" "$KERNEL_EVENT_NAME" "intfield" kernel_test_app
+
+       modprobe --remove lttng-test
+
+       stop_lttng_sessiond_notap
+else
+       # Kernel tests are skipped.
+       skip 0 "Root access is needed. Skipping all kernel notification tests." $KERNEL_NUM_TESTS
+fi
+
+
+rm -rf "$TMPDIR"
diff --git a/tests/regression/tools/map/test_map_query.c b/tests/regression/tools/map/test_map_query.c
new file mode 100644 (file)
index 0000000..04e8689
--- /dev/null
@@ -0,0 +1,125 @@
+#include <stdio.h>
+#include <stdint.h>
+
+#include <lttng/lttng.h>
+#include <lttng/handle.h>
+#include <lttng/map.h>
+#include <lttng/map-query.h>
+
+int main() {
+       int ret;
+       enum lttng_map_query_status query_status;
+       enum lttng_error_code ret_code;
+       unsigned int map_count, list_count;
+       enum lttng_map_status map_status;
+       struct lttng_map_content *map_content = NULL;
+       struct lttng_map_list *map_list = NULL;
+       const struct lttng_map *map = NULL;
+       struct lttng_domain *domains = NULL;
+       const struct lttng_map_key_value_pair_list *kv_list;
+       const struct lttng_map_key_value_pair *kv_pair;
+       const char *key;
+       int64_t value;
+       int nb_domains;
+
+
+       nb_domains = lttng_list_domains("mysession", &domains);
+
+       struct lttng_handle *handle = lttng_create_handle("mysession", &domains[0]);
+
+       struct lttng_map_query *map_query = lttng_map_query_create(
+                       LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET,
+                       LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_ALL,
+                       LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_ALL);
+
+       if (!map_query) {
+               printf("Error creating the map query\n");
+               ret = -1;
+               goto end;
+       }
+
+       query_status = lttng_map_query_add_cpu(map_query, 0);
+       if (query_status != LTTNG_MAP_QUERY_STATUS_OK) {
+               printf("Error setting the targeted cpu\n");
+               ret = -1;
+               goto end;
+       }
+
+       query_status = lttng_map_query_add_key_filter(map_query,
+                       "total number of hits");
+       if (query_status != LTTNG_MAP_QUERY_STATUS_OK) {
+               printf("Error setting the targeted key\n");
+               ret = -1;
+               goto end;
+       }
+
+       ret_code = lttng_list_maps(handle, &map_list);
+       if (ret_code != LTTNG_OK) {
+               printf("Error getting list of all maps\n");
+               ret = -1;
+               goto end;
+       }
+
+       map_status = lttng_map_list_get_count(map_list, &map_count);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               printf("Error getting the number of maps\n");
+               ret = -1;
+               goto end;
+       }
+
+       if (map_count < 1) {
+               printf("Error: expecting at least 1 map.\n");
+               ret = -1;
+               goto end;
+       }
+
+       map = lttng_map_list_get_at_index(map_list, 0);
+       if (!map) {
+               printf("Error getting map at index 0\n");
+               ret = -1;
+               goto end;
+       }
+
+       ret_code = lttng_list_map_content(handle, map, map_query, &map_content);
+       if (ret_code != LTTNG_OK) {
+               printf("Error executing the query on map\n");
+               ret = -1;
+               goto end;
+       }
+
+       map_status = lttng_map_content_get_count(map_content, &list_count);
+       if (map_status != LTTNG_MAP_STATUS_OK) {
+               printf("Error getting the number of key value pair list\n");
+               ret = -1;
+               goto end;
+       }
+
+       if (list_count < 1) {
+               printf("Error: expecting at least 1 list.\n");
+               ret = -1;
+               goto end;
+       }
+
+       kv_list = lttng_map_content_get_at_index(map_content, 0);
+       if (!kv_list) {
+               printf("Error getting key value pair list at index 0\n");
+               ret = -1;
+               goto end;
+       }
+
+       kv_pair = lttng_map_key_value_pair_list_get_at_index(kv_list, 0);
+       if (!kv_pair) {
+               printf("Error getting key value pair at index 0\n");
+               ret = -1;
+               goto end;
+       }
+
+       lttng_map_key_value_pair_get_key(kv_pair, &key);
+       lttng_map_key_value_pair_get_value(kv_pair, &value);
+
+       printf("Key: \"%s\", value: %"PRId64"\n", key, value);
+
+       ret = 0;
+end:
+       return ret;
+}
diff --git a/tests/regression/tools/map/test_map_ust b/tests/regression/tools/map/test_map_ust
new file mode 100755 (executable)
index 0000000..b6c21c2
--- /dev/null
@@ -0,0 +1,416 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+
+CURDIR=$(dirname "$0")/
+TESTDIR=$CURDIR/../../..
+NR_ITER=5
+NR_USEC_WAIT=1
+TESTAPP_PATH="$TESTDIR/utils/testapp"
+TESTAPP_NAME="gen-ust-events"
+TESTAPP_BIN="$TESTAPP_PATH/$TESTAPP_NAME/$TESTAPP_NAME"
+
+GEN_UST_NEVENTS_BIN="$TESTAPP_PATH/gen-ust-nevents/gen-ust-nevents"
+
+UST_EVENT_NAME="tp:tptest"
+
+UST_NUM_TESTS=474
+NUM_TESTS=$(($UST_NUM_TESTS))
+
+TMPDIR=$(mktemp -d)
+
+SH_TAP=1
+
+# shellcheck source=../../../utils/utils.sh
+source "$TESTDIR/utils/utils.sh"
+source "$CURDIR/map_base_test.sh"
+
+FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}"
+
+if [ ! -x "$TESTAPP_BIN" ]; then
+       BAIL_OUT "No UST events binary detected."
+fi
+
+plan_tests $NUM_TESTS
+
+
+function ust_test_app()
+{
+       $TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT
+}
+
+function test_map_ust_per_uid_create()
+{
+       local MAP_NAME="my_map_name"
+       local MAP_NAME_2="my_map_name2"
+       local MAP_NAME_3="my_map_name3"
+       local SESSION_NAME="my_session_name"
+
+       diag "Map creation"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       "$FULL_LTTNG_BIN" add-map --userspace --bitness 32 --session "wrong_session_name" "$MAP_NAME" > /dev/null
+       isnt $? 0 "Map creation failed on wrong session name"
+
+       "$FULL_LTTNG_BIN" add-map --userspace --bitness 42 --session "$SESSION_NAME" "$MAP_NAME" > /dev/null
+       isnt $? 0 "Map creation failed \"--bitness\" wrong value as expected"
+
+       "$FULL_LTTNG_BIN" add-map --userspace --session "SESS_DOESNT_EXIST" "$MAP_NAME" > /dev/null
+       isnt $? 0 "Failed to add map to session that doesn't exist"
+
+       "$FULL_LTTNG_BIN" disable-map --userspace --session "$SESSION_NAME" "MAP_DOESNT_EXIST" > /dev/null
+       isnt $? 0 "Failed to disable map that doesn't exist"
+
+       "$FULL_LTTNG_BIN" add-map --userspace --bitness 64 --session "$SESSION_NAME" "$MAP_NAME" > /dev/null
+       ok $? "Map with 64bit bitness created succesfully"
+
+       "$FULL_LTTNG_BIN" disable-map --userspace "$MAP_NAME" > /dev/null
+       ok $? "Map disabled succesfully"
+
+       destroy_lttng_session_ok "$SESSION_NAME"
+}
+
+function test_map_ust_per_pid_create()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+
+       diag "Map per-pid creation"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" --userspace 64 --per-pid
+
+       "$FULL_LTTNG_BIN" disable-map --userspace "$MAP_NAME" > /dev/null
+       ok $? "Map disabled succesfully"
+
+       "$FULL_LTTNG_BIN" enable-map --userspace "$MAP_NAME" > /dev/null
+       ok $? "Map enabled succesfully"
+
+       destroy_lttng_session_ok "$SESSION_NAME"
+}
+
+function test_map_base_scenario()
+{
+       local domain="$1"
+       local bitness="$2"
+       local buf_option="$3"
+       local event_name="$4"
+
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+
+       diag "Map base tracing scenario: $domain bitness $bitness $buf_option"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event "$domain" "$event_name" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       ust_test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$NR_ITER"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_ust_two_apps()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="--userspace"
+       local bitness="64"
+       local buf_option="--per-uid"
+
+       diag "Map with two apps"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event --userspace "$UST_EVENT_NAME" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       ust_test_app
+       ust_test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$((NR_ITER * 2))"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_ust_with_events()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="--userspace"
+       local bitness="64"
+       local buf_option="--per-uid"
+
+       diag "Map with regular events"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       enable_ust_lttng_event_ok "$SESSION_NAME" "*"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event --userspace "$UST_EVENT_NAME" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       ust_test_app
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "$NR_ITER"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+function test_map_ust_per_pid_dead_app_aggregation()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME1="my_trigger_name1"
+       local TRIGGER_NAME2="my_trigger_name2"
+       local KEY1="foo"
+       local KEY2="ashton"
+       local domain="--userspace"
+       local bitness="64"
+       local buf_option="--per-pid"
+
+       local file_sync_before_exit=$(mktemp -u)
+       local file_sync_before_exit_touch=$(mktemp -u)
+
+       # In per-pid, test that running apps and dead apps aggrgated values are
+       # listed in their own map.
+
+       diag "Map per-pid user with dead app aggregation"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME1" \
+               --condition \
+                       on-event --userspace "tp:tptest1" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY1"
+
+       lttng_add_trigger_ok "$TRIGGER_NAME2" \
+               --condition \
+                       on-event --userspace "$UST_EVENT_NAME" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY2"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       # Two apps will have run completely when we call view-map.
+       $GEN_UST_NEVENTS_BIN -i $NR_ITER -w $NR_USEC_WAIT
+       $GEN_UST_NEVENTS_BIN -i $NR_ITER -w $NR_USEC_WAIT
+
+       # One app will be done generating events but is still running when we
+       # call view-map.
+
+       $TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT \
+                       --sync-before-exit-touch $file_sync_before_exit_touch \
+                       --sync-before-exit $file_sync_before_exit &
+
+       # Wait for the before exit sync point. This ensure that we went over the
+       # last tracepoint.
+       while [ ! -f "${file_sync_before_exit_touch}" ]; do
+               sleep 0.1
+       done
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       # After the apps are dead, we should see map key value pairs in the
+       # dead map aggregation listing. Two apps ran and exited, so we should
+       # have NR_ITER * 2 hits.
+       view_map_ok "$MAP_NAME" "$KEY1" "$(( $NR_ITER * 2 ))"
+
+       # One app is still running and is done generating events, we should see
+       # NR_ITER hits.
+       view_map_ok "$MAP_NAME" "$KEY2" "$NR_ITER"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME1"
+       lttng_remove_trigger_ok "$TRIGGER_NAME2"
+
+       touch "$file_sync_before_exit"
+       wait
+
+       destroy_lttng_session_ok $SESSION_NAME
+
+       rm -f ${file_sync_before_exit}
+       rm -f ${file_sync_before_exit_touch}
+}
+
+function test_map_ust_exclusion()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="--userspace"
+       local bitness="64"
+       local buf_option="--per-uid"
+       local exclusion="tp:tptest1,tp:tptest2,tp:tptest3,tp:tptest4"
+
+       diag "Map per-pid user with dead app aggregation"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event --userspace "tp:tptest*" --exclude="$exclusion" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       "$GEN_UST_NEVENTS_BIN" -i "$NR_ITER" -w 1
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       # After the map is dead, we should still see map key value pairs in the
+       # dead map aggregation listing.
+       view_map_ok "$MAP_NAME" "$KEY" "5"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+
+function test_map_ust_clear_per_pid()
+{
+       local MAP_NAME="my_map_name"
+       local SESSION_NAME="my_session_name"
+       local TRIGGER_NAME="my_trigger_name"
+       local KEY="foo"
+       local domain="--userspace"
+       local bitness="64"
+       local buf_option="--per-pid"
+
+       diag "Map UST per-pid clear"
+
+       create_lttng_session_ok "$SESSION_NAME"
+
+       lttng_add_map_ok "$MAP_NAME" "$SESSION_NAME" "$domain" "$bitness" "$buf_option"
+       lttng_add_trigger_ok "$TRIGGER_NAME" \
+               --condition \
+                       on-event --userspace "tp:tptest1" \
+               --action \
+                       incr-value --session "$SESSION_NAME" --map "$MAP_NAME" --key "$KEY"
+
+       start_lttng_tracing_ok $SESSION_NAME
+
+       "$GEN_UST_NEVENTS_BIN" -i "$NR_ITER" -w 1
+
+       stop_lttng_tracing_ok $SESSION_NAME
+
+       # After the map is dead, we should still see map key value pairs in the
+       # dead map aggregation listing.
+       view_map_ok "$MAP_NAME" "$KEY" "5"
+
+       lttng_clear_session_ok $SESSION_NAME
+
+       view_map_ok "$MAP_NAME" "$KEY" "0"
+
+       lttng_remove_trigger_ok "$TRIGGER_NAME"
+
+       destroy_lttng_session_ok $SESSION_NAME
+}
+
+start_lttng_sessiond_notap
+
+test_map_ust_per_pid_dead_app_aggregation
+test_map_n_triggers_n_keys "--userspace" "64" "$UST_EVENT_NAME" ust_test_app
+test_map_n_triggers_n_keys "--userspace" "32" "$UST_EVENT_NAME" ust_test_app
+
+test_map_n_triggers_1_key "--userspace" "64" "$UST_EVENT_NAME" ust_test_app
+test_map_n_triggers_1_key "--userspace" "32" "$UST_EVENT_NAME" ust_test_app
+
+test_map_n_triggers_1_key_coalesced "--userspace" "32" "$UST_EVENT_NAME" ust_test_app
+test_map_n_triggers_1_key_coalesced "--userspace" "64" "$UST_EVENT_NAME" ust_test_app
+
+test_map_ust_per_uid_create
+test_map_ust_per_pid_create
+
+test_map_view_empty "--userspace" "64" "--per-uid"
+test_map_view_empty "--userspace" "64" "--per-pid"
+test_map_view_empty "--userspace" "32" "--per-uid"
+test_map_view_empty "--userspace" "32" "--per-pid"
+
+test_map_base_scenario "--userspace" "64" "--per-uid" "$UST_EVENT_NAME"
+test_map_base_scenario "--userspace" "32" "--per-uid" "$UST_EVENT_NAME"
+test_map_base_scenario "--userspace" "64" "--per-pid" "$UST_EVENT_NAME"
+test_map_base_scenario "--userspace" "32" "--per-pid" "$UST_EVENT_NAME"
+
+test_map_formated_keys "--userspace" "$UST_EVENT_NAME" "\${PROVIDER_NAME}:\${EVENT_NAME}" "$UST_EVENT_NAME" ust_test_app
+test_map_formated_keys "--userspace" "$UST_EVENT_NAME" "pitarifique-\${EVENT_NAME}" "pitarifique-tptest" ust_test_app
+
+test_map_disable_enable "--userspace" "32" "$UST_EVENT_NAME" ust_test_app
+test_map_disable_enable "--userspace" "64" "$UST_EVENT_NAME" ust_test_app
+
+test_map_add_remove_add_trigger "--userspace" "32" "$UST_EVENT_NAME" ust_test_app
+test_map_add_remove_add_trigger "--userspace" "64" "$UST_EVENT_NAME" ust_test_app
+
+test_map_creation_after_trigger "--userspace" "32" "$UST_EVENT_NAME" ust_test_app
+test_map_creation_after_trigger "--userspace" "64" "$UST_EVENT_NAME" ust_test_app
+
+test_map_remove_trigger_before_stop "--userspace" "32" "$UST_EVENT_NAME" ust_test_app
+test_map_remove_trigger_before_stop "--userspace" "64" "$UST_EVENT_NAME" ust_test_app
+
+test_map_ust_two_apps
+test_map_ust_with_events
+test_map_two_incr_value_two_keys "--userspace" "64" "$UST_EVENT_NAME" ust_test_app
+
+test_map_clear "--userspace" 32 "$UST_EVENT_NAME" ust_test_app
+test_map_clear "--userspace" 64 "$UST_EVENT_NAME" ust_test_app
+test_map_ust_clear_per_pid
+
+test_map_ust_exclusion
+
+test_map_filter "--userspace" "$UST_EVENT_NAME" "intfield" ust_test_app
+
+stop_lttng_sessiond_notap
+
+rm -rf "$TMPDIR"
index 3aca442f2235db9adb9f90f4e46e0aa4048eeba3..0dceea5721fbe149874a9b511a72cb8c9e3f6cdd 100644 (file)
@@ -9,18 +9,22 @@ noinst_PROGRAMS = base_client notification rotation
 
 if NO_SHARED
 
-CLEANFILES = libpause_consumer.so libpause_consumer.so.debug
+CLEANFILES = libpause_consumer.so libpause_consumer.so.debug libpause_sessiond.so libpause_sessiond.so.debug
 EXTRA_DIST = \
             base_client.c \
             consumer_testpoints.c \
+            sessiond_testpoints.c \
             notification.c \
             test_notification_kernel_buffer_usage \
+            test_notification_kernel_capture \
             test_notification_kernel_error \
             test_notification_kernel_instrumentation \
             test_notification_kernel_syscall \
             test_notification_kernel_userspace_probe \
             test_notification_multi_app \
+            test_notification_notifier_discarded_count \
             test_notification_ust_buffer_usage \
+            test_notification_ust_capture \
             test_notification_ust_error \
             test_notification_ust_event_rule_condition_exclusion \
             util_event_generator.sh
@@ -38,7 +42,14 @@ libpause_consumer_la_LIBADD = \
        $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la \
        $(DL_LIBS)
 libpause_consumer_la_LDFLAGS = $(FORCE_SHARED_LIB_OPTIONS)
-noinst_LTLIBRARIES = libpause_consumer.la
+
+libpause_sessiond_la_SOURCES = sessiond_testpoints.c
+libpause_sessiond_la_LIBADD = \
+       $(top_builddir)/src/common/libcommon.la \
+       $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la \
+       $(DL_LIBS)
+libpause_sessiond_la_LDFLAGS = $(FORCE_SHARED_LIB_OPTIONS)
+noinst_LTLIBRARIES = libpause_sessiond.la libpause_consumer.la
 
 base_client_SOURCES = base_client.c
 base_client_LDADD = $(LIB_LTTNG_CTL)
@@ -56,6 +67,7 @@ noinst_SCRIPTS = \
        test_notification_kernel_syscall \
        test_notification_kernel_userspace_probe \
        test_notification_multi_app \
+       test_notification_notifier_discarded_count \
        test_notification_ust_buffer_usage \
        test_notification_ust_error \
        test_notification_ust_event_rule_condition_exclusion \
@@ -64,12 +76,15 @@ noinst_SCRIPTS = \
 
 EXTRA_DIST = \
        test_notification_kernel_buffer_usage \
+       test_notification_kernel_capture \
        test_notification_kernel_error \
        test_notification_kernel_instrumentation \
        test_notification_kernel_syscall \
        test_notification_kernel_userspace_probe \
        test_notification_multi_app \
+       test_notification_notifier_discarded_count \
        test_notification_ust_buffer_usage \
+       test_notification_ust_capture \
        test_notification_ust_error \
        test_notification_ust_event_rule_condition_exclusion \
        test_rotation \
index 70ad763abe51aa1645bfd9c6b2678a75dd6e8b51..c215b5cf47c8b0518c82fb4f0aa3f731c9006ff7 100644 (file)
@@ -17,6 +17,7 @@
 #include <assert.h>
 
 #include <lttng/action/action.h>
+#include <lttng/action/group.h>
 #include <lttng/action/notify.h>
 #include <lttng/condition/buffer-usage.h>
 #include <lttng/condition/condition.h>
@@ -35,6 +36,7 @@ static const char *channel_name = NULL;
 static double threshold_ratio = 0.0;
 static uint64_t threshold_bytes = 0;
 static bool is_threshold_ratio = false;
+static bool use_action_group = false;
 static enum lttng_condition_type buffer_usage_type = LTTNG_CONDITION_TYPE_UNKNOWN;
 static enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
 
@@ -50,6 +52,7 @@ int parse_arguments(char **argv)
        const char *buffer_usage_threshold_type = NULL;
        const char *buffer_usage_threshold_value = NULL;
        const char *nr_expected_notifications_string = NULL;
+       const char *use_action_group_value = NULL;
 
        session_name = argv[1];
        channel_name = argv[2];
@@ -58,6 +61,7 @@ int parse_arguments(char **argv)
        buffer_usage_threshold_type = argv[5];
        buffer_usage_threshold_value = argv[6];
        nr_expected_notifications_string = argv[7];
+       use_action_group_value = argv[8];
 
        /* Parse arguments */
        /* Domain type */
@@ -98,6 +102,11 @@ int parse_arguments(char **argv)
        /* Number of notification to expect */
        sscanf(nr_expected_notifications_string, "%d", &nr_expected_notifications);
 
+       /* Put notify action in a group. */
+       if (!strcasecmp("1", use_action_group_value)) {
+               use_action_group = true;
+       }
+
        return 0;
 error:
        return 1;
@@ -107,6 +116,7 @@ int main(int argc, char **argv)
 {
        int ret = 0;
        enum lttng_condition_status condition_status;
+       enum lttng_action_status action_status;
        enum lttng_notification_channel_status nc_status;
        struct lttng_notification_channel *notification_channel = NULL;
        struct lttng_condition *condition = NULL;
@@ -120,7 +130,7 @@ int main(int argc, char **argv)
         */
        setbuf(stdout, NULL);
 
-       if (argc < 8) {
+       if (argc < 9) {
                printf("error: Missing arguments for tests\n");
                ret = 1;
                goto end;
@@ -196,11 +206,39 @@ int main(int argc, char **argv)
                goto end;
        }
 
-       action = lttng_action_notify_create();
-       if (!action) {
-               printf("error: Could not create action notify\n");
-               ret = 1;
-               goto end;
+       if (use_action_group) {
+               struct lttng_action *notify, *group;
+
+               group = lttng_action_group_create();
+               if (!group) {
+                       printf("error: Could not create action group\n");
+                       ret = 1;
+                       goto end;
+               }
+               notify = lttng_action_notify_create();
+               if (!notify) {
+                       lttng_action_destroy(group);
+                       printf("error: Could not create action notify\n");
+                       ret = 1;
+                       goto end;
+               }
+               action_status = lttng_action_group_add_action(group, notify);
+               if (action_status != LTTNG_ACTION_STATUS_OK) {
+                       printf("error: Could not add action notify to action group\n");
+                       lttng_action_destroy(group);
+                       lttng_action_destroy(notify);
+                       ret = 1;
+                       goto end;
+               }
+
+               action = group;
+       } else {
+               action = lttng_action_notify_create();
+               if (!action) {
+                       printf("error: Could not create action notify\n");
+                       ret = 1;
+                       goto end;
+               }
        }
 
        trigger = lttng_trigger_create(condition, action);
@@ -265,7 +303,7 @@ int main(int argc, char **argv)
                        goto end;
                default:
                        /* Unhandled conditions / errors. */
-                       printf("error: Unknown notification channel status\n");
+                       printf("error: Unknown notification channel status (%d) \n", status);
                        ret = 1;
                        goto end;
                }
index 73415c51ecc51d3fc58675fd1fd2d764f96d5998..28c8e58ceb0f43ea21dcff5959417954c84c634a 100644 (file)
 
 #include <tap/tap.h>
 
+/* A callback to populate the condition capture descriptor */
+typedef int (*condition_capture_desc_cb)(struct lttng_condition *condition);
+
+/* A callback for captured field validation */
+typedef int (*validate_cb)(const struct lttng_event_field_value *event_field, unsigned iteration);
+
 int nb_args = 0;
 int named_pipe_args_start = 0;
 pid_t app_pid = 0;
 const char *app_state_file = NULL;
 
+enum field_type {
+       FIELD_TYPE_PAYLOAD,
+       FIELD_TYPE_CONTEXT,
+       FIELD_TYPE_APP_CONTEXT,
+       FIELD_TYPE_ARRAY_FIELD,
+};
+
+struct capture_base_field_tuple {
+       char* field_name;
+       enum field_type field_type;
+       bool expected_ust; // Do we expect a capture?
+       bool expected_kernel; // Do we expect a capture?
+       validate_cb validate_ust;
+       validate_cb validate_kernel;
+};
+
+static
+const char *field_value_type_to_str(enum lttng_event_field_value_type type)
+{
+       switch (type) {
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
+               return "UNKNOWN";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
+               return "INVALID";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
+               return "UNSIGNED INT";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
+               return "SIGNED INT";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
+               return "UNSIGNED ENUM";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
+               return "SIGNED ENUM";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
+               return "REAL";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
+               return "STRING";
+       case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
+               return "ARRAY";
+       default:
+               abort();
+       }
+}
+
+static int validate_type(
+               const struct lttng_event_field_value *event_field,
+               enum lttng_event_field_value_type expect)
+{
+       int ret;
+       enum lttng_event_field_value_type value;
+
+       value = lttng_event_field_value_get_type(event_field);
+       if (value == LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID) {
+               ret = 1;
+               goto end;
+       }
+
+       ret = (expect == value);
+       ok(ret, "Expected field type: %s got %s",
+                       field_value_type_to_str(expect),
+                       field_value_type_to_str(value));
+
+       ret = !ret;
+
+end:
+       return ret;
+}
+
+/*
+ * Validate unsigned captured field against the iteration number.
+ * The iteration number is always unsigned and will always be compared to value
+ * under MAX_UINT.
+ */
+static int validate_unsigned_int_field(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       uint64_t value;
+       enum lttng_event_field_value_status status;
+
+       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_unsigned_int_get_value(
+               event_field , &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_unsigned_int_get_value");
+               ret = 1;
+               goto end;
+       }
+
+       ret = (value == (uint64_t) iteration);
+       ok (ret, "Expected unsigned int of value: %u got %" PRIu64, iteration, value);
+
+       ret = !ret;
+
+end:
+
+       return ret;
+}
+
+/*
+ * Validate signed captured field.
+ * Value should be -1.
+ */
+static int validate_signed_int_field(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       int64_t expected = -1;
+       int64_t value;
+       enum lttng_event_field_value_status status;
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_signed_int_get_value(
+               event_field , &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_signed_int_get_value");
+               ret = 1;
+               goto end;
+       }
+
+       ret = (value == expected);
+       ok(ret, "Expected signed int of value: %" PRId64 " got %" PRId64, expected, value);
+
+       ret = !ret;
+
+end:
+
+       return ret;
+}
+
+/*
+ * Validate array of unsigned int.
+ */
+static int validate_array_unsigned_int_field(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       enum lttng_event_field_value_status status;
+       unsigned int expected = 3;
+       unsigned int count;
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_array_get_length(event_field, &count);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_array_get_length");
+               ret = 1;
+               goto end;
+       }
+
+       ret = (count == expected);
+       ok(ret, "Expected %d subelements got %d", expected, count);
+       if (!ret) {
+               ret = 1;
+               goto end;
+       }
+
+       for (unsigned int i = 1; i < count + 1; i++) {
+               const struct lttng_event_field_value *value;
+               status = lttng_event_field_value_array_get_element_at_index(
+                               event_field, i - 1, &value);
+               if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       fail("lttng_event_field_value_array_get_element_at_index");
+                       ret = 1;
+                       goto end;
+               }
+               ret = validate_unsigned_int_field(value, i);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = 0;
+end:
+
+       return ret;
+}
+static int validate_array_unsigned_int_field_at_index(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       uint64_t expected_value = 2;
+       enum lttng_event_field_value_status status;
+       uint64_t value;
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_unsigned_int_get_value(
+               event_field , &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_unsigned_int_get_value");
+               ret = 1;
+               goto end;
+       }
+
+       ret = (value == expected_value);
+       ok (ret, "Expected unsigned int of value: %u got %" PRIu64,
+                       expected_value, value);
+
+       ret = 0;
+end:
+       return ret;
+}
+
+/*
+ * Validate sequence for a string (seqfield1):
+ *
+ * Value: "test" in utf8  [116, 101, 115, 116]
+ */
+static int validate_seqfield1(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       enum lttng_event_field_value_status status;
+       unsigned int count;
+       unsigned int expect[4] = {116, 101, 115, 116};
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_array_get_length(event_field, &count);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_array_get_length");
+               ret = 1;
+               goto end;
+       }
+
+       ret = (count == 4);
+       ok(ret, "Expected 4 subelement got %d", count);
+       if (!ret) {
+               ret = 1;
+               goto end;
+       }
+
+       for (unsigned int i = 0; i < count ; i++) {
+               const struct lttng_event_field_value *value;
+               status = lttng_event_field_value_array_get_element_at_index(
+                               event_field, i, &value);
+               if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       fail("lttng_event_field_value_array_get_element_at_index");
+                       ret = 1;
+                       goto end;
+               }
+               ret = validate_unsigned_int_field(value, expect[i]);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = 0;
+end:
+
+       return ret;
+}
+
+static int validate_string(
+               const struct lttng_event_field_value *event_field,
+               const char *expect)
+{
+       int ret;
+       const char *value = NULL;
+
+       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_STRING);
+       if (ret) {
+               goto end;
+       }
+
+       value = lttng_event_field_value_string_get_value(event_field);
+       if (!value) {
+               fail("lttng_event_field_value_array_get_length");
+               ret = 1;
+               goto end;
+       }
+
+       ok(!strcmp(value, expect), "Expected string: \"%s\" got \"%s\"", expect, value);
+
+       ret = 0;
+end:
+
+       return ret;
+}
+
+/*
+ * Validate string. Expected value is "test".
+ */
+static int validate_string_test(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       const char *expect = "test";
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_string(event_field, expect);
+       return ret;
+}
+
+/*
+ * Validate escaped string. Expected value is "\*".
+ */
+static int validate_string_escaped(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       const char *expect = "\\*";
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_string(event_field, expect);
+       return ret;
+}
+
+/*
+ * Validate real field.
+ */
+static int validate_real(
+               const struct lttng_event_field_value *event_field,
+               double expect)
+{
+       int ret;
+       double value;
+       enum lttng_event_field_value_status status;
+
+       ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_REAL);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_real_get_value(event_field, &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_real_get_value");
+               ret = 1;
+               goto end;
+       }
+
+       ret = (value == expect);
+       ok(ret, "Real expected: %f got: %f", expect, value);
+
+       ret = !ret;
+end:
+       return ret;
+}
+
+/*
+ * Validate floatfield.
+ */
+static int validate_floatfield(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       double expect = 2222.0;
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_real(event_field, expect);
+       return ret;
+}
+
+/*
+ * Validate doublefield.
+ */
+static int validate_doublefield(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       double expect = 2.0;
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_real(event_field, expect);
+       return ret;
+}
+
+/*
+ * Validate enum0:  enum0 = ( "AUTO: EXPECT 0" : container = 0 )
+ */
+static int validate_enum0(const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       enum lttng_event_field_value_status status;
+       uint64_t value;
+       uint64_t expected_value = 0;
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_type(event_field,
+                       LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_unsigned_int_get_value(
+                       event_field, &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_unsigned_int_get_value");
+               ret = 1;
+               goto end;
+       }
+
+       ok(value == expected_value,
+                       "Enum value expected: %" PRIu64 " got %" PRIu64,
+                       expected_value, value);
+
+end:
+       return ret;
+}
+
+/*
+ * Validate enumnegative:  enumnegative = ( "AUTO: EXPECT 0" : container = 0 )
+ *
+ * We expect 2 labels here.
+ */
+static int validate_enumnegative(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+       enum lttng_event_field_value_status status;
+       int64_t value;
+       int64_t expected_value = -1;
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_type(
+                       event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM);
+       if (ret) {
+               goto end;
+       }
+
+       status = lttng_event_field_value_signed_int_get_value(
+                       event_field, &value);
+       if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               fail("lttng_event_field_value_unsigned_int_get_value");
+               ret = 1;
+               goto end;
+       }
+
+       ok(value == expected_value,
+                       "Enum value expected: %" PRId64 " got %" PRId64,
+                       expected_value, value);
+
+end:
+       return ret;
+}
+
+static int validate_context_procname_ust(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_string(event_field, "gen-ust-events");
+       return ret;
+}
+
+static int validate_context_procname_kernel(
+               const struct lttng_event_field_value *event_field,
+               unsigned int iteration)
+{
+       int ret;
+
+       /* Unused */
+       (void) iteration;
+
+       ret = validate_string(event_field, "echo");
+       return ret;
+}
+
+struct capture_base_field_tuple test_capture_base_fields[] = {
+               {"DOESNOTEXIST", FIELD_TYPE_PAYLOAD, false, false, NULL, NULL},
+               {"intfield", FIELD_TYPE_PAYLOAD, true, true, validate_unsigned_int_field, validate_unsigned_int_field},
+               {"longfield", FIELD_TYPE_PAYLOAD, true, true, validate_unsigned_int_field, validate_unsigned_int_field},
+               {"signedfield", FIELD_TYPE_PAYLOAD, true, true, validate_signed_int_field, validate_signed_int_field},
+               {"arrfield1", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field},
+               {"arrfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test},
+               {"arrfield3", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field},
+               {"seqfield1", FIELD_TYPE_PAYLOAD, true, true, validate_seqfield1, validate_seqfield1},
+               {"seqfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test},
+               {"seqfield3", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field},
+               {"seqfield4", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field},
+               {"arrfield1[1]", FIELD_TYPE_ARRAY_FIELD, true, true, validate_array_unsigned_int_field_at_index, validate_array_unsigned_int_field_at_index},
+               {"stringfield", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test},
+               {"stringfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_escaped, validate_string_escaped},
+               {"floatfield", FIELD_TYPE_PAYLOAD, true, false, validate_floatfield, validate_floatfield},
+               {"doublefield", FIELD_TYPE_PAYLOAD, true, false, validate_doublefield, validate_doublefield},
+               {"enum0", FIELD_TYPE_PAYLOAD, true, true, validate_enum0, validate_enum0},
+               {"enumnegative", FIELD_TYPE_PAYLOAD, true, true, validate_enumnegative, validate_enumnegative},
+               {"$ctx.procname", FIELD_TYPE_CONTEXT, true, true, validate_context_procname_ust, validate_context_procname_kernel},
+};
+
 static const char *get_notification_trigger_name(
                struct lttng_notification *notification)
 {
@@ -46,7 +588,7 @@ static const char *get_notification_trigger_name(
        }
 
        switch (lttng_evaluation_get_type(evaluation)) {
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
        {
                status = lttng_evaluation_event_rule_get_trigger_name(
                                evaluation, &name);
@@ -904,6 +1446,7 @@ static void create_tracepoint_event_rule_trigger(const char *event_pattern,
                unsigned int exclusion_count,
                const char * const *exclusions,
                enum lttng_domain_type domain_type,
+               condition_capture_desc_cb capture_desc_cb,
                struct lttng_condition **condition,
                struct lttng_trigger **trigger)
 {
@@ -960,9 +1503,16 @@ static void create_tracepoint_event_rule_trigger(const char *event_pattern,
                ok(success, "Setting tracepoint event rule exclusions");
        }
 
-       tmp_condition = lttng_condition_event_rule_create(event_rule);
+       tmp_condition = lttng_condition_on_event_create(event_rule);
        ok(tmp_condition, "Condition event rule object creation");
 
+       if (capture_desc_cb) {
+               ret = capture_desc_cb(tmp_condition);
+               if (ret) {
+                       assert("Generating the condition capture descriptor");
+               }
+       }
+
        tmp_action = lttng_action_notify_create();
        ok(tmp_action, "Action event rule object creation");
 
@@ -1033,7 +1583,7 @@ static void test_tracepoint_event_rule_notification(
        }
 
        create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
-                       NULL, domain_type, &condition, &trigger);
+                       NULL, domain_type, NULL, &condition, &trigger);
 
        notification_channel = lttng_notification_channel_create(
                        lttng_session_daemon_notification_endpoint);
@@ -1101,7 +1651,7 @@ static void test_tracepoint_event_rule_notification_filter(
        ok(notification_channel, "Notification channel object creation");
 
        create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
-                       0, NULL, domain_type, &ctrl_condition, &ctrl_trigger);
+                       0, NULL, domain_type, NULL, &ctrl_condition, &ctrl_trigger);
 
        nc_status = lttng_notification_channel_subscribe(
                        notification_channel, ctrl_condition);
@@ -1113,7 +1663,7 @@ static void test_tracepoint_event_rule_notification_filter(
         * `intfield` is even.
         */
        create_tracepoint_event_rule_trigger(pattern, trigger_name,
-                       "(intfield & 1) == 0", 0, NULL, domain_type, &condition,
+                       "(intfield & 1) == 0", 0, NULL, domain_type, NULL, &condition,
                        &trigger);
 
        nc_status = lttng_notification_channel_subscribe(
@@ -1201,7 +1751,8 @@ static void test_tracepoint_event_rule_notification_exclusion(
        ok(notification_channel, "Notification channel object creation");
 
        create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
-                       0, NULL, domain_type, &ctrl_condition, &ctrl_trigger);
+                       0, NULL, domain_type, NULL, &ctrl_condition,
+                       &ctrl_trigger);
 
        nc_status = lttng_notification_channel_subscribe(
                        notification_channel, ctrl_condition);
@@ -1209,7 +1760,8 @@ static void test_tracepoint_event_rule_notification_exclusion(
                        "Subscribe to tracepoint event rule condition");
 
        create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 4,
-                       exclusions, domain_type, &condition, &trigger);
+                       exclusions, domain_type, NULL, &condition,
+                       &trigger);
 
        nc_status = lttng_notification_channel_subscribe(
                        notification_channel, condition);
@@ -1310,20 +1862,15 @@ static void test_kprobe_event_rule_notification(
                        lttng_session_daemon_notification_endpoint);
        ok(notification_channel, "Notification channel object creation");
 
-       event_rule = lttng_event_rule_kprobe_create();
+       event_rule = lttng_event_rule_kernel_probe_create(location);
        ok(event_rule, "kprobe event rule object creation");
 
-       event_rule_status = lttng_event_rule_kprobe_set_location(
-                       event_rule, location);
-       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting kprobe event rule location: '%s'", symbol_name);
-
-       event_rule_status = lttng_event_rule_kprobe_set_name(
+       event_rule_status = lttng_event_rule_kernel_probe_set_event_name(
                        event_rule, trigger_name);
        ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
                        "Setting kprobe event rule name: '%s'", trigger_name);
 
-       condition = lttng_condition_event_rule_create(event_rule);
+       condition = lttng_condition_on_event_create(event_rule);
        ok(condition, "Condition event rule object creation");
 
        /* Register the trigger for condition. */
@@ -1424,20 +1971,15 @@ static void test_uprobe_event_rule_notification(
                        lttng_session_daemon_notification_endpoint);
        ok(notification_channel, "Notification channel object creation");
 
-       event_rule = lttng_event_rule_uprobe_create();
+       event_rule = lttng_event_rule_userspace_probe_create(probe_location);
        ok(event_rule, "kprobe event rule object creation");
 
-       event_rule_status = lttng_event_rule_uprobe_set_location(
-                       event_rule, probe_location);
-       ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting uprobe event rule location");
-
-       event_rule_status = lttng_event_rule_uprobe_set_name(
+       event_rule_status = lttng_event_rule_userspace_probe_set_event_name(
                        event_rule, trigger_name);
        ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
                        "Setting uprobe event rule name: '%s'", trigger_name);
 
-       condition = lttng_condition_event_rule_create(event_rule);
+       condition = lttng_condition_on_event_create(event_rule);
        ok(condition, "Condition event rule object creation");
 
        /* Register the trigger for condition. */
@@ -1529,7 +2071,7 @@ static void test_syscall_event_rule_notification(
        ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
                        "Setting syscall event rule pattern: '%s'", syscall_name);
 
-       condition = lttng_condition_event_rule_create(event_rule);
+       condition = lttng_condition_on_event_create(event_rule);
        ok(condition, "Condition syscall event rule object creation");
 
        /* Register the trigger for condition. */
@@ -1624,7 +2166,7 @@ static void test_syscall_event_rule_notification_filter(
        ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
                        "Setting filter: '%s'", filter_pattern);
 
-       condition = lttng_condition_event_rule_create(event_rule);
+       condition = lttng_condition_on_event_create(event_rule);
        ok(condition, "Condition event rule object creation");
 
        /* Register the triggers for condition */
@@ -1681,6 +2223,241 @@ end:
        return;
 }
 
+static int generate_capture_descr(struct lttng_condition *condition)
+{
+       int ret;
+       struct lttng_event_expr *expr = NULL;
+       unsigned int basic_field_size;
+       enum lttng_condition_status cond_status;
+
+       basic_field_size = sizeof(test_capture_base_fields) / sizeof(*test_capture_base_fields);
+       for (int i = 0; i < basic_field_size; i++) {
+
+               diag("Adding capture descriptor \"%s\"", test_capture_base_fields[i].field_name);
+
+               switch (test_capture_base_fields[i].field_type) {
+               case FIELD_TYPE_PAYLOAD:
+                       expr = lttng_event_expr_event_payload_field_create(
+                                       test_capture_base_fields[i].field_name);
+                       break;
+               case FIELD_TYPE_CONTEXT:
+                       expr = lttng_event_expr_channel_context_field_create(
+                                       test_capture_base_fields[i].field_name);
+                       break;
+               case FIELD_TYPE_ARRAY_FIELD:
+               {
+                       int nb_matches;
+                       unsigned int index;
+                       char field_name[256];
+                       struct lttng_event_expr *array_expr = NULL;
+                       nb_matches = sscanf(test_capture_base_fields[i].field_name,
+                                       "%[^[][%u]", field_name, &index);
+                       if (nb_matches != 2) {
+                               ret = 1;
+                               goto end;
+                       }
+                       array_expr = lttng_event_expr_event_payload_field_create(
+                               field_name);
+
+                       expr = lttng_event_expr_array_field_element_create(
+                               array_expr, index);
+                       break;
+               }
+               case FIELD_TYPE_APP_CONTEXT:
+                       fail("Application context not tested yet.");
+               default:
+                       ret = 1;
+                       goto end;
+               }
+               if (expr == NULL) {
+                       fail("Creating capture expression");
+                       ret = -1;
+                       goto end;
+               }
+               cond_status = lttng_condition_on_event_append_capture_descriptor(
+                               condition, expr);
+               if (cond_status != LTTNG_CONDITION_STATUS_OK) {
+                       fail("Appending capture_descriptor");
+                       ret = -1;
+                       lttng_event_expr_destroy(expr);
+                       goto end;
+               }
+       }
+
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static int validator_notification_trigger_capture(
+               enum lttng_domain_type domain,
+               struct lttng_notification *notification,
+               const int iteration)
+{
+       int ret;
+       unsigned int capture_count, i;
+       enum lttng_evaluation_status evaluation_status;
+       enum lttng_event_field_value_status event_field_value_status;
+       const struct lttng_evaluation *evaluation;
+       const struct lttng_event_field_value *captured_fields;
+       bool at_least_one_error = false;
+
+       evaluation = lttng_notification_get_evaluation(notification);
+       if (evaluation == NULL) {
+               fail("lttng_notification_get_evaluation");
+               ret = 1;
+               goto end;
+       }
+
+       /* TODO: it seems weird that lttng_evaluation_get_captured_values return
+        * INVALID if no capture were present. might be better to return
+        * something with more meaning. Another question is how we link the
+        * notion of capture and the descriptor from the perspective of a
+        * client. Is it really invalid to ask for captured value when there might
+        * not be any?
+        */
+       evaluation_status = lttng_evaluation_get_captured_values(evaluation, &captured_fields);
+       if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) {
+               diag("lttng_evaluation_get_captured_values");
+               ret = 1;
+               goto end;
+       }
+
+       event_field_value_status =
+               lttng_event_field_value_array_get_length(captured_fields,
+                               &capture_count);
+       if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+               assert(0 && "get count of captured field");
+       }
+
+       for (i = 0; i < capture_count; i++) {
+               const struct lttng_event_field_value *captured_field = NULL;
+               validate_cb validate;
+               bool expected;
+
+               diag("Validating capture \"%s\"", test_capture_base_fields[i].field_name);
+               event_field_value_status = lttng_event_field_value_array_get_element_at_index(captured_fields, i, &captured_field);
+
+               switch(domain) {
+               case LTTNG_DOMAIN_UST:
+                       expected = test_capture_base_fields[i].expected_ust;
+                       break;
+               case LTTNG_DOMAIN_KERNEL:
+                       expected = test_capture_base_fields[i].expected_kernel;
+                       break;
+               default:
+                       assert(0 && "Domain invalid for this test");
+               }
+
+               if (!expected) {
+                       ok(event_field_value_status == LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE, "No payload captured");
+                       continue;
+               }
+
+               if (domain == LTTNG_DOMAIN_UST) {
+                       validate = test_capture_base_fields[i].validate_ust;
+               } else {
+                       validate = test_capture_base_fields[i].validate_kernel;
+               }
+
+               if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+                       const char *reason;
+                       if (event_field_value_status ==
+                                       LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
+                               reason = "Expected a capture but it is unavailable";
+                       } else {
+                               reason = "lttng_event_field_value_array_get_element_at_index";
+                       }
+                       fail(reason);
+                       ret = 1;
+                       goto end;
+               }
+               diag("Captured field of type %s",
+                               field_value_type_to_str(
+                                       lttng_event_field_value_get_type(captured_field)));
+
+               assert(validate);
+               ret = validate(captured_field, iteration);
+               if (ret) {
+                       at_least_one_error = true;
+               }
+       }
+
+       ret = at_least_one_error;
+
+end:
+       return ret;
+}
+
+static void test_tracepoint_event_rule_notification_capture(
+               enum lttng_domain_type domain_type)
+{
+       enum lttng_notification_channel_status nc_status;
+
+       int i, ret;
+       struct lttng_condition *condition = NULL;
+       struct lttng_notification_channel *notification_channel = NULL;
+       struct lttng_trigger *trigger = NULL;
+       const char *trigger_name = "my_precious";
+       const char *pattern;
+
+       if (domain_type == LTTNG_DOMAIN_UST) {
+               pattern = "tp:tptest";
+       } else {
+               pattern = "lttng_test_filter_event";
+       }
+
+       create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
+                       NULL, domain_type, generate_capture_descr, &condition,
+                       &trigger);
+
+       notification_channel = lttng_notification_channel_create(
+                       lttng_session_daemon_notification_endpoint);
+       ok(notification_channel, "Notification channel object creation");
+
+       nc_status = lttng_notification_channel_subscribe(
+                       notification_channel, condition);
+       ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+                       "Subscribe to tracepoint event rule condition");
+
+       resume_application();
+
+       /* Get 3 notifications */
+       for (i = 0; i < 3; i++) {
+               struct lttng_notification *notification = get_next_notification(
+                               notification_channel);
+               ok(notification, "Received notification");
+
+               /* Error */
+               if (notification == NULL) {
+                       goto end;
+               }
+
+               ret = validator_notification_trigger_name(notification, trigger_name);
+               if (ret) {
+                       lttng_notification_destroy(notification);
+                       goto end;
+               }
+
+               ret = validator_notification_trigger_capture(domain_type, notification, i);
+               if (ret) {
+                       lttng_notification_destroy(notification);
+                       goto end;
+               }
+
+               lttng_notification_destroy(notification);
+       }
+
+end:
+       suspend_application();
+       lttng_notification_channel_destroy(notification_channel);
+       lttng_unregister_trigger(trigger);
+       lttng_trigger_destroy(trigger);
+       lttng_condition_destroy(condition);
+       return;
+}
+
 int main(int argc, const char *argv[])
 {
        int test_scenario;
@@ -1798,7 +2575,7 @@ int main(int argc, const char *argv[])
        }
        case 4:
        {
-               plan_tests(13);
+               plan_tests(12);
                /* Test cases that need the kernel tracer. */
                assert(domain_type == LTTNG_DOMAIN_KERNEL);
 
@@ -1831,7 +2608,7 @@ int main(int argc, const char *argv[])
        {
                const char *testapp_path, *test_symbol_name;
 
-               plan_tests(13);
+               plan_tests(12);
 
                if (argc < 7) {
                        fail("Missing parameter for tests to run %d", argc);
@@ -1851,6 +2628,26 @@ int main(int argc, const char *argv[])
 
                break;
        }
+       case 7:
+       {
+               switch(domain_type) {
+               case LTTNG_DOMAIN_UST:
+                       plan_tests(222);
+                       break;
+               case LTTNG_DOMAIN_KERNEL:
+                       plan_tests(216);
+                       break;
+               default:
+                       assert(0);
+               }
+
+               diag("Test tracepoint event rule notification captures for domain %s",
+                               domain_type_string);
+               test_tracepoint_event_rule_notification_capture(domain_type);
+
+               break;
+       }
+
        default:
                abort();
        }
diff --git a/tests/regression/tools/notification/sessiond_testpoints.c b/tests/regression/tools/notification/sessiond_testpoints.c
new file mode 100644 (file)
index 0000000..0f6e208
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <common/compat/getenv.h>
+#include <common/consumer/consumer.h>
+#include <common/pipe.h>
+#include <common/error.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <lttng/constant.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <assert.h>
+#include <stdio.h>
+
+static char *pause_pipe_path;
+static struct lttng_pipe *pause_pipe;
+static int *notifier_notif_consumption_state;;
+
+int lttng_opt_verbose;
+int lttng_opt_mi;
+int lttng_opt_quiet;
+
+static
+void __attribute__((destructor)) pause_pipe_fini(void)
+{
+       int ret;
+
+       if (pause_pipe_path) {
+               ret = unlink(pause_pipe_path);
+               if (ret) {
+                       PERROR("unlink pause pipe");
+               }
+       }
+
+       free(pause_pipe_path);
+       lttng_pipe_destroy(pause_pipe);
+}
+
+/*
+ */
+int __testpoint_sessiond_thread_notification(void);
+int __testpoint_sessiond_thread_notification(void)
+{
+       int ret = 0;
+       const char *pause_pipe_path_prefix;
+
+       pause_pipe_path_prefix = lttng_secure_getenv(
+                       "NOTIFIER_PAUSE_PIPE_PATH");
+       if (!pause_pipe_path_prefix) {
+               ret = -1;
+               goto end;
+       }
+
+       notifier_notif_consumption_state = dlsym(NULL, "notifier_consumption_paused");
+       assert(notifier_notif_consumption_state);
+
+       ret = asprintf(&pause_pipe_path, "%s", pause_pipe_path_prefix);
+       if (ret < 1) {
+               ERR("Failed to allocate pause pipe path");
+               goto end;
+       }
+
+       DBG("Creating pause pipe at %s", pause_pipe_path);
+       pause_pipe = lttng_pipe_named_open(pause_pipe_path,
+                       S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, O_NONBLOCK);
+       if (!pause_pipe) {
+               ERR("Failed to create pause pipe at %s", pause_pipe_path);
+               ret = -1;
+               goto end;
+       }
+
+       /* Only the read end of the pipe is useful to us. */
+       ret = lttng_pipe_write_close(pause_pipe);
+end:
+       return ret;
+}
+
+int __testpoint_sessiond_handle_notifier_event_pipe(void);
+int __testpoint_sessiond_handle_notifier_event_pipe(void)
+{
+       int ret = 0;
+       uint8_t value;
+       bool value_read = false;
+
+       if (!pause_pipe) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Purge pipe and only consider the freshest value. */
+       do {
+               ret = lttng_pipe_read(pause_pipe, &value, sizeof(value));
+               if (ret == sizeof(value)) {
+                       value_read = true;
+               }
+       } while (ret == sizeof(value));
+
+       ret = (errno == EAGAIN) ? 0 : -errno;
+
+       if (value_read) {
+               *notifier_notif_consumption_state = !!value;
+               DBG("Message received on pause pipe: %s data consumption",
+                               *notifier_notif_consumption_state ? "paused" : "resumed");
+       }
+end:
+       return ret;
+}
diff --git a/tests/regression/tools/notification/test_notification_kernel_capture b/tests/regression/tools/notification/test_notification_kernel_capture
new file mode 100755 (executable)
index 0000000..9b6e7ac
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+
+CURDIR=$(dirname "$0")/
+TESTDIR=$CURDIR/../../../
+
+TMPDIR=$(mktemp -d)
+
+TESTAPP_PATH="$TESTDIR/utils/testapp"
+TESTAPP_STATE_PATH=$(mktemp -u "$TMPDIR/application_state.XXXXXXXXXX")
+
+NUM_TESTS=104
+
+# shellcheck source=../../../utils/utils.sh
+source "$TESTDIR/utils/utils.sh"
+# shellcheck source=./util_event_generator.sh
+source "$CURDIR/util_event_generator.sh"
+
+function test_basic_error_path
+{
+       kernel_event_generator_run_once_per_transition generate_filter_events \
+               "$TESTAPP_STATE_PATH" 10 &
+       APP_PID=$!
+
+       "$CURDIR/notification" 7 LTTNG_DOMAIN_KERNEL $APP_PID \
+               "$TESTAPP_STATE_PATH"
+
+       kill -SIGUSR2 $APP_PID
+       wait $APP_PID 2> /dev/null
+}
+
+
+if [ "$(id -u)" == "0" ]; then
+       validate_lttng_modules_present
+
+       modprobe lttng-test
+
+       start_lttng_sessiond_notap
+
+       test_basic_error_path
+
+       stop_lttng_sessiond_notap
+       rmmod lttng-test
+
+else
+       # Kernel tests are skipped.
+       plan_tests $NUM_TESTS
+       skip 0 "Root access is needed. Skipping all kernel notification tests." $NUM_TESTS
+fi
+
+# Just in case cleanup
+rm -rf "$TMPDIR"
index afac94d1042ad16e4ec68c7a31ff6ec2a2b52d18..5d5427c9d03759eee3797cc326f8131c0457edec 100755 (executable)
@@ -54,8 +54,9 @@ function start_client {
        local buffer_usage_threshold_type=$6
        local buffer_usage_threshold_value=$7
        local nr_expected_notification=$8
+       local use_action_group=$9
 
-       ${CURDIR}/base_client ${session_name} ${channel_name} ${domain_type} ${buffer_usage_type} ${buffer_usage_threshold_type} ${buffer_usage_threshold_value} ${nr_expected_notification} > ${output_file} &
+       ${CURDIR}/base_client ${session_name} ${channel_name} ${domain_type} ${buffer_usage_type} ${buffer_usage_threshold_type} ${buffer_usage_threshold_value} ${nr_expected_notification} ${use_action_group} > ${output_file} &
        pid=$!
 
        app_pids+=("$pid")
@@ -177,8 +178,8 @@ function test_multi_app ()
        for (( i = 0; i < $nr_client_app; i++ )); do
                low_app_output_file=$output_dir/${low_output_file_pattern}${i}
                high_app_output_file=$output_dir/${high_output_file_pattern}${i}
-               start_client $low_app_output_file $SESSION_NAME $CHANNEL_NAME $domain_string LOW RATIO 0.0 $nr_notification_expected
-               start_client $high_app_output_file $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 $nr_notification_expected
+               start_client $low_app_output_file $SESSION_NAME $CHANNEL_NAME $domain_string LOW RATIO 0.0 $nr_notification_expected $(( $i % 2))
+               start_client $high_app_output_file $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 $nr_notification_expected $(( $i % 2))
        done
 
        wait_for_message $output_dir "${low_output_file_pattern}" "sync: ready"
@@ -362,7 +363,7 @@ function test_on_register_evaluation ()
 
        high_app_output_file=${high_output_file_pattern}.first_receiver
        high_app_output_path=$output_dir/${high_app_output_file}
-       start_client $high_app_output_path $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 1
+       start_client $high_app_output_path $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 1 0
 
        wait_for_message $output_dir "${high_app_output_file}" "sync: ready"
 
@@ -379,7 +380,7 @@ function test_on_register_evaluation ()
        # notification on subscription
        high_app_output_file=${high_output_file_pattern}.second_receiver
        high_app_output_path=$output_dir/${high_app_output_file}
-       start_client $high_app_output_path $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 1
+       start_client $high_app_output_path $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 1 0
        wait_for_message $output_dir "${high_app_output_file}" "sync: ready"
        wait_for_message $output_dir "${high_app_output_file}" "notification: high 0"
 
diff --git a/tests/regression/tools/notification/test_notification_notifier_discarded_count b/tests/regression/tools/notification/test_notification_notifier_discarded_count
new file mode 100755 (executable)
index 0000000..620a8a8
--- /dev/null
@@ -0,0 +1,254 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+
+CURDIR=$(dirname "$0")/
+TESTDIR=$CURDIR/../../../
+
+TMPDIR=$(mktemp -d)
+
+TESTAPP_PATH="$TESTDIR/utils/testapp"
+TESTAPP_NAME="gen-ust-events"
+TESTAPP_BIN="$TESTAPP_PATH/$TESTAPP_NAME/$TESTAPP_NAME"
+
+TESTPOINT_BASE_PATH=$(readlink -f "$TMPDIR/lttng.t_p_n")
+TESTPOINT_PIPE_PATH=$(mktemp -u "${TESTPOINT_BASE_PATH}.XXXXXX")
+TESTPOINT=$(readlink -f "${CURDIR}/.libs/libpause_sessiond.so")
+
+SH_TAP=1
+
+# shellcheck source=../../../utils/utils.sh
+source "$TESTDIR/utils/utils.sh"
+# shellcheck source=./util_event_generator.sh
+source "$CURDIR/util_event_generator.sh"
+
+FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}"
+FULL_LTTNG_SESSIOND_BIN="${TESTDIR}/../src/bin/lttng-sessiond/lttng-sessiond"
+
+UST_NUM_TESTS=16
+KERNEL_NUM_TESTS=15
+NUM_TESTS=$(($UST_NUM_TESTS + $KERNEL_NUM_TESTS))
+
+plan_tests $NUM_TESTS
+
+function test_kernel_notifier_discarded_count
+{
+       local sessiond_pipe=()
+       local trigger_name="my_trigger"
+       local list_triggers_stdout=$(mktemp -t list_triggers_stdout.XXXXXX)
+
+       # Used on sessiond launch.
+       LTTNG_SESSIOND_ENV_VARS="LTTNG_TESTPOINT_ENABLE=1 \
+               NOTIFIER_PAUSE_PIPE_PATH=${TESTPOINT_PIPE_PATH} \
+               LD_PRELOAD=${TESTPOINT}"
+
+       diag "Kernel event notifer error counter"
+
+       start_lttng_sessiond_notap
+
+       # This is needed since the testpoint create a pipe with the sessiond
+       # type suffixed.
+       for f in "$TESTPOINT_BASE_PATH"*; do
+               sessiond_pipe+=("$f")
+       done
+
+       lttng_add_trigger_ok "$trigger_name" \
+               --condition on-event --kernel lttng_test_filter_event \
+               --action notify
+
+       "$FULL_LTTNG_BIN" list-triggers > "$list_triggers_stdout"
+
+       # Confirm that the discarded notification line is present.
+       cat "$list_triggers_stdout" | grep --quiet "tracer notifications discarded: 0"
+       ok $? "No discarded tracer notification"
+
+       # Stop consumption of notifier tracer notifications.
+       echo -n 1 > $sessiond_pipe
+
+       # The notifier ring buffer configuration is currently made of 16 4096
+       # bytes subbuffers. Each kernel notification is at least 42 bytes long.
+       # To fill it, we need to generate (16 * 4096)/42 = 1561 notifications.
+       # That number is a bit larger than what we need since some of the space
+       # is lost in subbuffer boundaries.
+       echo -n "200000" > /proc/lttng-test-filter-event
+
+       "$FULL_LTTNG_BIN" list-triggers > "$list_triggers_stdout"
+
+       # Confirm that the discarded notification line is present. To avoid
+       # false positive.
+       cat "$list_triggers_stdout" | grep --quiet "tracer notifications discarded"
+       ok $? "Tracer notification discarded line printed"
+
+       # Confirm that the number of tracer notifications discarded is not zero.
+       cat "$list_triggers_stdout" | grep --quiet "tracer notifications discarded: 0"
+       isnt $? 0 "Discarded tracer notification number non-zero as expected"
+
+       lttng_remove_trigger_ok "$trigger_name"
+
+       # Confirm that no notifier is enabled.
+       list_triggers_line_count=$("$FULL_LTTNG_BIN" list-triggers | wc -l)
+       is "$list_triggers_line_count" "0" "No \`on-event\` kernel notifier enabled as expected"
+
+       # Enable another notifier and list it to confirm the counter was cleared.
+       lttng_add_trigger_ok "$trigger_name" \
+               --condition on-event --kernel lttng_test_filter_event \
+               --action notify
+
+       # Confirm that the discarded notification line is present.
+       "$FULL_LTTNG_BIN" list-triggers > "$list_triggers_stdout"
+       cat "$list_triggers_stdout" | grep --quiet "tracer notifications discarded: 0"
+       ok $? "No discarded tracer notification"
+
+       lttng_remove_trigger_ok "$trigger_name"
+
+       stop_lttng_sessiond_notap
+
+       unset LTTNG_SESSIOND_ENV_VARS
+
+       rm -f "$list_triggers_stdout"
+}
+
+function test_kernel_notifier_discarded_count_max_bucket
+{
+       start_lttng_sessiond "" "--event-notifier-error-number-of-bucket=3"
+
+       diag "Kernel event notifer error counter bucket limit"
+       for i in $(seq 3); do
+               lttng_add_trigger_ok "$i" \
+                       --condition on-event --kernel my_event_that_doesnt_need_to_really_exist_$i \
+                       --action notify
+       done
+
+       for i in $(seq 4 5); do
+               lttng_add_trigger_fail "$i" \
+                       --condition on-event --kernel my_event_that_doesnt_need_to_really_exist_$i \
+                       --action notify
+       done
+
+       stop_lttng_sessiond_notap
+}
+
+function test_ust_notifier_discarded_count
+{
+       local sessiond_pipe=()
+       local trigger_name="my_trigger"
+       local list_triggers_stdout=$(mktemp -t list_triggers_stdout.XXXXXX)
+       local NR_ITER=2000
+       local NR_USEC_WAIT=0
+
+
+       diag "UST event notifer error counter"
+       # Used on sessiond launch.
+       LTTNG_SESSIOND_ENV_VARS="LTTNG_TESTPOINT_ENABLE=1 \
+               NOTIFIER_PAUSE_PIPE_PATH=${TESTPOINT_PIPE_PATH} \
+               LD_PRELOAD=${TESTPOINT}"
+
+       start_lttng_sessiond_notap
+
+       # This is needed since the testpoint create a pipe with the sessiond
+       # type suffixed.
+       for f in "$TESTPOINT_BASE_PATH"*; do
+               sessiond_pipe+=("$f")
+       done
+
+       lttng_add_trigger_ok "$trigger_name" \
+               --condition on-event --userspace tp:tptest \
+               --action notify
+
+       "$FULL_LTTNG_BIN" list-triggers > "$list_triggers_stdout"
+
+       # Confirm that the discarded notification line is present.
+       cat "$list_triggers_stdout" | grep --quiet "tracer notifications discarded: 0"
+       ok $? "No discarded tracer notification"
+
+       # Stop consumption of notifier tracer notifications.
+       echo -n 1 > $sessiond_pipe
+
+       # The notifier ring buffer configuration is currently made of 16 4096
+       # bytes subbuffers. Each userspace notification is at least 42 bytes long.
+       # To fill it, we need to generate (16 * 4096)/42 = 1561 notifications.
+       # That number is a bit larger than what we need since some of the space
+       # is lost in subbuffer boundaries.
+       $TESTAPP_BIN -i $NR_ITER -w $NR_USEC_WAIT
+       ok $? "Generating $NR_ITER tracer notifications"
+
+       "$FULL_LTTNG_BIN" list-triggers > "$list_triggers_stdout"
+
+       # Confirm that the discarded notification line is present. To avoid
+       # false positive.
+       cat "$list_triggers_stdout" | grep --quiet "tracer notifications discarded"
+       ok $? "Tracer notification discarded line printed"
+
+       # Confirm that the number of tracer notifications discarded is not zero.
+       cat "$list_triggers_stdout" | grep --quiet "tracer notifications discarded: 0"
+       isnt $? 0 "Discarded tracer notification number non-zero as expected"
+
+       # Remove the notifier.
+       lttng_remove_trigger_ok "$trigger_name"
+
+       # Confirm that no notifier is enabled.
+       list_triggers_line_count=$("$FULL_LTTNG_BIN" list-triggers | wc -l)
+       is "$list_triggers_line_count" "0" "No \`on-event\` userspace notifier enabled as expected"
+
+       # Enable another notifier and list it to confirm the counter was cleared.
+       lttng_add_trigger_ok "$trigger_name" \
+               --condition on-event --userspace tp:tptest \
+               --action notify
+
+       # Confirm that the discarded notification line is present.
+       "$FULL_LTTNG_BIN" list-triggers > "$list_triggers_stdout"
+       cat "$list_triggers_stdout" | grep --quiet "tracer notifications discarded: 0"
+       ok $? "No discarded tracer notification"
+
+       lttng_remove_trigger_ok "$trigger_name"
+
+       stop_lttng_sessiond_notap
+
+       unset LTTNG_SESSIOND_ENV_VARS
+
+       rm -f "$list_triggers_stdout"
+}
+function test_ust_notifier_discarded_count_max_bucket
+{
+       start_lttng_sessiond "" "--event-notifier-error-number-of-bucket=3"
+
+       diag "UST event notifer error counter bucket limit"
+       for i in $(seq 3); do
+               lttng_add_trigger_ok "$i" \
+                       --condition on-event --userspace my_event_that_doesnt_need_to_really_exist_$i \
+                       --action notify
+       done
+
+       for i in $(seq 4 5); do
+               lttng_add_trigger_fail "$i" \
+                       --condition on-event --userspace my_event_that_doesnt_need_to_really_exist_$i \
+                       --action notify
+       done
+
+       stop_lttng_sessiond_notap
+}
+
+test_ust_notifier_discarded_count
+test_ust_notifier_discarded_count_max_bucket
+
+if [ "$(id -u)" == "0" ]; then
+
+       validate_lttng_modules_present
+
+       modprobe lttng-test
+
+       test_kernel_notifier_discarded_count
+
+       test_kernel_notifier_discarded_count_max_bucket
+
+       modprobe --remove lttng-test
+
+       rm -rf "${sessiond_pipe[@]}" 2> /dev/null
+else
+       # Kernel tests are skipped.
+       skip 0 "Root access is needed. Skipping all kernel notification tests." $KERNEL_NUM_TESTS
+fi
+
+rm -rf "$TMPDIR"
diff --git a/tests/regression/tools/notification/test_notification_ust_capture b/tests/regression/tools/notification/test_notification_ust_capture
new file mode 100755 (executable)
index 0000000..5003c28
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 Jonathan Rajotte-Julien <jonathan.rajotte-julien@efficios.com>
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+
+CURDIR=$(dirname "$0")/
+TESTDIR=$CURDIR/../../../
+
+TMPDIR=$(mktemp -d)
+
+TESTAPP_PATH="$TESTDIR/utils/testapp"
+
+GEN_UST_EVENTS_TESTAPP_NAME="gen-ust-events"
+GEN_UST_EVENTS_TESTAPP_BIN="$TESTAPP_PATH/$GEN_UST_EVENTS_TESTAPP_NAME/$GEN_UST_EVENTS_TESTAPP_NAME"
+
+TESTAPP_STATE_PATH=$(mktemp -u "$TMPDIR/application_state.XXXXXXXXXX")
+
+# shellcheck source=../../../utils/utils.sh
+source "$TESTDIR/utils/utils.sh"
+# shellcheck source=./util_event_generator.sh
+source "$CURDIR/util_event_generator.sh"
+
+function test_basic_error_path
+{
+       ust_event_generator_run_once_per_transition \
+               "$GEN_UST_EVENTS_TESTAPP_BIN" "$TESTAPP_STATE_PATH" 3 10 &
+       APP_PID=$!
+
+       "$CURDIR/notification" 7 LTTNG_DOMAIN_UST $APP_PID "$TESTAPP_STATE_PATH"
+
+       kill -SIGUSR2 $APP_PID
+       wait $APP_PID 2> /dev/null
+}
+
+start_lttng_sessiond_notap
+
+test_basic_error_path
+
+stop_lttng_sessiond_notap
index 3361744e9c85a878a7d34d351471267aeb3ea61c..469102f8eed088c40cabcd5f3c9e8128d1fa56de 100644 (file)
@@ -3,7 +3,8 @@
 noinst_SCRIPTS = test_save test_load test_autoload
 EXTRA_DIST = $(noinst_SCRIPTS) load-42.lttng load-42-complex.lttng \
        load-42-trackers.lttng tracker_legacy_none.lttng \
-       tracker_legacy_all.lttng tracker_legacy_selective.lttng
+       tracker_legacy_all.lttng tracker_legacy_selective.lttng \
+       load-42-maps.lttng
 
 SUBDIRS = configuration
 
diff --git a/tests/regression/tools/save-load/load-42-maps.lttng b/tests/regression/tools/save-load/load-42-maps.lttng
new file mode 100644 (file)
index 0000000..82aaecd
--- /dev/null
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sessions>
+       <session>
+               <name>load-42-maps</name>
+               <domains>
+                       <domain>
+                               <type>UST</type>
+                               <buffer_type>PER_UID</buffer_type>
+                               <channels/>
+                               <maps>
+                                       <map>
+                                               <name>ze-map-32</name>
+                                               <enabled>true</enabled>
+                                               <bitness>32</bitness>
+                                               <boundary_policy>OVERFLOW</boundary_policy>
+                                               <coalesce_hits>false</coalesce_hits>
+                                               <dimensions>
+                                                       <dimension>
+                                                               <size>4096</size>
+                                                       </dimension>
+                                               </dimensions>
+                                       </map>
+                                       <map>
+                                               <name>ze-map-64</name>
+                                               <enabled>true</enabled>
+                                               <bitness>64</bitness>
+                                               <boundary_policy>OVERFLOW</boundary_policy>
+                                               <coalesce_hits>false</coalesce_hits>
+                                               <dimensions>
+                                                       <dimension>
+                                                               <size>4096</size>
+                                                       </dimension>
+                                               </dimensions>
+                                       </map>
+                               </maps>
+                               <process_attr_trackers/>
+                       </domain>
+                       <domain>
+                               <type>JUL</type>
+                               <buffer_type>PER_UID</buffer_type>
+                               <channels/>
+                               <maps/>
+                       </domain>
+                       <domain>
+                               <type>LOG4J</type>
+                               <buffer_type>PER_UID</buffer_type>
+                               <channels/>
+                               <maps/>
+                       </domain>
+                       <domain>
+                               <type>PYTHON</type>
+                               <buffer_type>PER_UID</buffer_type>
+                               <channels/>
+                               <maps/>
+                       </domain>
+               </domains>
+               <started>false</started>
+               <output>
+                       <consumer_output>
+                               <enabled>true</enabled>
+                               <destination>
+                                       <path>/tmp/lttng/load-42-maps</path>
+                               </destination>
+                       </consumer_output>
+               </output>
+       </session>
+</sessions>
index 4f18dec2d8a052342dd3e45619bac2178b0df84f..1870bf0b4292cb3cdbc6d1744e1294fc9342088d 100755 (executable)
@@ -16,7 +16,7 @@ EVENT_NAME="tp:tptest"
 
 DIR=$(readlink -f $TESTDIR)
 
-NUM_TESTS=75
+NUM_TESTS=78
 
 source $TESTDIR/utils/utils.sh
 
@@ -101,6 +101,7 @@ function test_all_load()
        destroy_lttng_session_ok $SESSION_NAME
        destroy_lttng_session_ok "$SESSION_NAME-complex"
        destroy_lttng_session_ok "$SESSION_NAME-trackers"
+       destroy_lttng_session_ok "$SESSION_NAME-maps"
        destroy_lttng_session_ok "tracker_legacy_all"
        destroy_lttng_session_ok "tracker_legacy_none"
        destroy_lttng_session_ok "tracker_legacy_selective"
@@ -164,6 +165,25 @@ function test_trackers()
        rm -f ${mi_output_file}
 }
 
+function test_maps()
+{
+       diag "Test maps loading"
+
+       lttng_load_ok "-i $CURDIR/$SESSION_NAME-maps.lttng"
+
+       local mi_output_file=$(mktemp)
+       if [ $? -ne 0 ]; then
+               break;
+       fi
+
+       $TESTDIR/../src/bin/lttng/$LTTNG_BIN --mi XML list "$SESSION_NAME-maps" > $mi_output_file
+
+       # TODO: once map information is in the MI, do some mad testing with sick xpath expressions.
+
+       destroy_lttng_session_ok "$SESSION_NAME-maps"
+       rm -f ${mi_output_file}
+}
+
 function test_override_url_normal()
 {
        local local_url_override="file:///tmp/override/to/here"
@@ -354,6 +374,7 @@ TESTS=(
        test_all_load
        test_overwrite
        test_trackers
+       test_maps
        test_override_session_name
        test_override_url_normal
        test_override_url_snapshot
index 0f3e596a0aa5501db90c3b0e17620dc039bbf6e9..c4bc515e3b0a5479d134947c756691b4f9477e63 100755 (executable)
@@ -12,13 +12,17 @@ TESTDIR=$CURDIR/../../../
 SESSION_NAME="save-42"
 CHANNEL_NAME="chan-save"
 EVENT_NAME="tp:tptest"
+MAP_32_NAME="ze-map-32"
+MAP_64_NAME="ze-map-64"
 
 DIR=$(readlink -f $TESTDIR)
 
-NUM_TESTS=41
+NUM_TESTS=46
 
 source $TESTDIR/utils/utils.sh
 
+FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}"
+
 # MUST set TESTDIR before calling those functions
 plan_tests $NUM_TESTS
 
@@ -54,12 +58,25 @@ function test_basic_save()
        create_lttng_session_ok $SESSION_NAME $TRACE_PATH
        enable_ust_lttng_channel_ok $SESSION_NAME $CHANNEL_NAME
        enable_ust_lttng_event_ok $SESSION_NAME $EVENT_NAME $CHANNEL_NAME
+       lttng_add_map_ok $MAP_32_NAME $SESSION_NAME -u 32 "" ""
+       lttng_add_map_ok $MAP_64_NAME $SESSION_NAME -u 64 "" ""
        lttng_track_ok "-p 666 -u -s $SESSION_NAME"
 
        lttng_save $SESSION_NAME "-o $TRACE_PATH"
 
        is_session_saved $TRACE_PATH $SESSION_NAME
 
+       local session_file="$TRACE_PATH/$SESSION_NAME.lttng"
+
+       local map_count=$(xmllint --xpath 'count(/sessions/session[1]/domains/domain[./type = "UST"]/maps/map)' "$session_file")
+       is "$map_count" 2
+
+       local bitness_32=$(xmllint --xpath '/sessions/session[1]/domains/domain[./type = "UST"]/maps/map[./name = "ze-map-32"]/bitness/text()' "$session_file")
+       is "$bitness_32" 32
+
+       local bitness_64=$(xmllint --xpath '/sessions/session[1]/domains/domain[./type = "UST"]/maps/map[./name = "ze-map-64"]/bitness/text()' "$session_file")
+       is "$bitness_64" 64
+
        destroy_lttng_session_ok $SESSION_NAME
 }
 
index cecea3b19e07f193120c4b59e96b6da8fd7adf67..a6fc7bd028e3f3ff2e818d4a1cbb5c816f74413d 100755 (executable)
@@ -22,47 +22,6 @@ NUM_TESTS=18
 NR_ITER=5
 NR_USEC_WAIT=5
 
-function lttng_add_trigger_ust()
-{
-       local expected_to_fail="$1"
-       local trigger_name="$2"
-       shift 2
-
-       "$FULL_LTTNG_BIN" add-trigger --id "$trigger_name" "$@" 1> /dev/null 2> /dev/null
-       ret=$?
-       if [[ $expected_to_fail -eq "1" ]]; then
-               test "$ret" -ne "0"
-               ok $? "Add trigger $trigger_name failed as expected"
-       else
-               ok $ret "Add trigger $trigger_name"
-       fi
-}
-
-function lttng_remove_trigger_ust()
-{
-       local expected_to_fail="$1"
-       local trigger_name="$2"
-
-       "$FULL_LTTNG_BIN" remove-trigger "$trigger_name" 1> /dev/null 2> /dev/null
-       ret=$?
-       if [[ $expected_to_fail -eq "1" ]]; then
-               test "$ret" -ne "0"
-               ok $? "Remove trigger $trigger_name failed as expected"
-       else
-               ok $ret "Remove trigger $trigger_name"
-       fi
-}
-
-function lttng_add_trigger_ust_ok()
-{
-       lttng_add_trigger_ust 0 "$@"
-}
-
-function lttng_remove_trigger_ust_ok()
-{
-       lttng_remove_trigger_ust 0 "$@"
-}
-
 function lttng_session_is_active()
 {
        local SESSION_NAME="$1"
@@ -96,7 +55,7 @@ function test_start_session_action()
 
        # Add `start-session` action to an event-rule condition _followed_ by
        # a `notify` action.
-       lttng_add_trigger_ust_ok \
+       lttng_add_trigger_ok \
                $TRIGGER_NAME \
                --condition on-event -u "tp:tptest" \
                --action start-session $SESSION_NAME \
@@ -124,7 +83,7 @@ function test_start_session_action()
        lttng_session_is_active $SESSION_NAME
 
        # Tearing down.
-       lttng_remove_trigger_ust_ok $TRIGGER_NAME
+       lttng_remove_trigger_ok $TRIGGER_NAME
        stop_lttng_tracing_ok $SESSION_NAME
        destroy_lttng_session_ok $SESSION_NAME
 
@@ -150,7 +109,7 @@ function test_stop_session_action()
 
        # Add `stop-session` action to an event-rule condition _followed_ by
        # a `notify` action.
-       lttng_add_trigger_ust_ok \
+       lttng_add_trigger_ok \
                $TRIGGER_NAME \
                --condition on-event -u "tp:tptest" \
                --action stop-session $SESSION_NAME \
@@ -178,7 +137,7 @@ function test_stop_session_action()
        lttng_session_is_inactive $SESSION_NAME
 
        # Tearing down.
-       lttng_remove_trigger_ust_ok $TRIGGER_NAME
+       lttng_remove_trigger_ok $TRIGGER_NAME
        destroy_lttng_session_ok $SESSION_NAME
 
        rm -f "$SYNC_AFTER_NOTIF_REGISTER_PATH"
index db325a90d61884225eab325f1de7c9a211c500c4..b3a51dd47104552ed7ee1b9ec4679c5ec54d3e3f 100755 (executable)
@@ -101,20 +101,20 @@ test_success "--fire-every" \
 
 skip $ist_root "non-root user: skipping kprobe tests" 9 || {
        test_success "--condition on-event probe by symbol" \
-               --condition on-event -k --probe=lttng_channel_enable my_channel_enable \
+               --condition on-event -k --probe=lttng_event_container_enable my_channel_enable \
                --action notify
 
-       channel_enable_addr=$(grep ' t lttng_channel_enable\s\[lttng_tracer\]$' /proc/kallsyms | cut -f 1 -d ' ')
-       channel_disable_addr=$(grep ' t lttng_channel_disable\s\[lttng_tracer\]$' /proc/kallsyms | cut -f 1 -d ' ')
+       channel_enable_addr=$(grep 'lttng_event_container_enable' /proc/kallsyms | cut -f 1 -d ' ')
+       channel_disable_addr=$(grep 'lttng_event_container_disable' /proc/kallsyms | cut -f 1 -d ' ')
 
        # We need to find a valid offset.
        base_symbol=""
        offset=0
        if [[ 0x$channel_enable_addr -lt 0x$channel_disable_addr ]]; then
-               base_symbol="lttng_channel_enable"
+               base_symbol="lttng_event_container_enable"
                offset=$(( 0x$channel_disable_addr - 0x$channel_enable_addr ))
        else
-               base_symbol="lttng_channel_disable"
+               base_symbol="lttng_event_container_disable"
                offset=$(( 0x$channel_enable_addr - 0x$channel_disable_addr ))
        fi
 
index e09d7cdc6894763dc50697abd2b0f716e268d5a2..88b2e87f374aa4c6c7e8e020bdfeee856123202f 100755 (executable)
@@ -23,7 +23,7 @@ TESTDIR="$CURDIR/../../.."
 # shellcheck source=../../../utils/utils.sh
 source "$TESTDIR/utils/utils.sh"
 
-plan_tests 40
+plan_tests 54
 
 FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}"
 
@@ -41,12 +41,6 @@ else
        ist_root=0
 fi
 
-function add_trigger ()
-{
-       "${FULL_LTTNG_BIN}" add-trigger "$@"
-       ok $? "add trigger \`$*\`: exit code is 0"
-}
-
 function list_triggers ()
 {
        local test_name="$1"
@@ -68,9 +62,9 @@ test_top_level_options ()
        start_lttng_sessiond_notap
 
 
-       add_trigger --id hello --condition on-event -u test-id --action notify
-       add_trigger --fire-once-after 123 --condition on-event -u test-fire-once-after --action notify
-       add_trigger --fire-every 124 --condition on-event -u test-fire-every --action notify
+       lttng_add_trigger_ok "hello" --condition on-event -u test-id --action notify
+       lttng_add_trigger_ok "T0" --fire-once-after 123 --condition on-event -u test-fire-once-after --action notify
+       lttng_add_trigger_ok "T1" --fire-every 124 --condition on-event -u test-fire-every --action notify
 
        cat > "${tmp_expected_stdout}" <<- EOF
        - id: T0
@@ -78,6 +72,7 @@ test_top_level_options ()
          firing policy: once after 123 occurences
          condition: event rule hit
            rule: test-fire-once-after (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            notify
        - id: T1
@@ -85,12 +80,14 @@ test_top_level_options ()
          firing policy: after every 124 occurences
          condition: event rule hit
            rule: test-fire-every (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            notify
        - id: hello
          user id: ${uid}
          condition: event rule hit
            rule: test-id (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            notify
        EOF
@@ -105,41 +102,88 @@ test_on_event_tracepoint ()
        # shellcheck disable=SC2119
        start_lttng_sessiond_notap
 
-       add_trigger --condition on-event -u -a --action notify
-       add_trigger --id ABC --condition on-event aaa -u --filter 'p == 2' --action notify
-       add_trigger --condition on-event 'hello*' -u -x 'hello2,hello3,hello4' --action notify
-       add_trigger --id BCD --condition on-event -u gerboise --loglevel INFO --action notify
-       add_trigger --condition on-event -u lemming --loglevel-only WARNING --action notify
+       lttng_add_trigger_ok "C" --condition on-event -u -a --action notify
+       lttng_add_trigger_ok "A" --condition on-event aaa -u --filter 'p == 2' --action notify
+       lttng_add_trigger_ok "D" --condition on-event 'hello*' -u -x 'hello2,hello3,hello4' --action notify
+       lttng_add_trigger_ok "B" --condition on-event -u gerboise --loglevel INFO --action notify
+       lttng_add_trigger_ok "E" --condition on-event -u lemming --loglevel-only WARNING --action notify
+       lttng_add_trigger_ok "F" --condition on-event -u capture-payload-field --capture a --action notify
+       lttng_add_trigger_ok "G" --condition on-event -u capture-array --capture 'a[2]' --capture '$ctx.tourlou[18]' --action notify
+       lttng_add_trigger_ok "H" --condition on-event -u capture-chan-ctx --capture '$ctx.vpid' --action notify
+       lttng_add_trigger_ok "I" --condition on-event -u capture-app-ctx --capture '$app.iga:active_clients' --action notify
+
 
        cat > "${tmp_expected_stdout}" <<- EOF
-       - id: ABC
+       - id: A
          user id: ${uid}
          condition: event rule hit
            rule: aaa (type: tracepoint, domain: ust, filter: p == 2)
+           tracer notifications discarded: 0
          actions:
            notify
-       - id: BCD
+       - id: B
          user id: ${uid}
          condition: event rule hit
            rule: gerboise (type: tracepoint, domain: ust, log level <= TRACE_INFO)
+           tracer notifications discarded: 0
          actions:
            notify
-       - id: T0
+       - id: C
          user id: ${uid}
          condition: event rule hit
            rule: * (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            notify
-       - id: T1
+       - id: D
          user id: ${uid}
          condition: event rule hit
            rule: hello* (type: tracepoint, domain: ust, exclusions: hello2,hello3,hello4)
+           tracer notifications discarded: 0
          actions:
            notify
-       - id: T2
+       - id: E
          user id: ${uid}
          condition: event rule hit
            rule: lemming (type: tracepoint, domain: ust, log level == TRACE_WARNING)
+           tracer notifications discarded: 0
+         actions:
+           notify
+       - id: F
+         user id: ${uid}
+         condition: event rule hit
+           rule: capture-payload-field (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
+           captures:
+             - a
+         actions:
+           notify
+       - id: G
+         user id: ${uid}
+         condition: event rule hit
+           rule: capture-array (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
+           captures:
+             - a[2]
+             - \$ctx.tourlou[18]
+         actions:
+           notify
+       - id: H
+         user id: ${uid}
+         condition: event rule hit
+           rule: capture-chan-ctx (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
+           captures:
+             - \$ctx.vpid
+         actions:
+           notify
+       - id: I
+         user id: ${uid}
+         condition: event rule hit
+           rule: capture-app-ctx (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
+           captures:
+             - \$app.iga:active_clients
          actions:
            notify
        EOF
@@ -157,43 +201,46 @@ test_on_event_probe ()
        # shellcheck disable=SC2119
        start_lttng_sessiond_notap
 
-       channel_enable_addr=$(grep ' t lttng_channel_enable\s\[lttng_tracer\]$' /proc/kallsyms | cut -f 1 -d ' ')
-       channel_disable_addr=$(grep ' t lttng_channel_disable\s\[lttng_tracer\]$' /proc/kallsyms | cut -f 1 -d ' ')
+       channel_enable_addr=$(grep 'lttng_event_container_enable' /proc/kallsyms | cut -f 1 -d ' ')
+       channel_disable_addr=$(grep 'lttng_event_container_disable' /proc/kallsyms | cut -f 1 -d ' ')
 
        # We need to find a valid offset.
        base_symbol=""
        offset=0
        if [[ 0x$channel_enable_addr -lt 0x$channel_disable_addr ]]; then
-               base_symbol="lttng_channel_enable"
+               base_symbol="lttng_event_container_enable"
                offset=$(( 0x$channel_disable_addr - 0x$channel_enable_addr ))
        else
-               base_symbol="lttng_channel_disable"
+               base_symbol="lttng_event_container_disable"
                offset=$(( 0x$channel_enable_addr - 0x$channel_disable_addr ))
        fi
 
        offset_hex="0x$(printf '%x' $offset)"
 
-       add_trigger --condition on-event -k --probe=lttng_channel_enable my_channel_enable --action notify
-       add_trigger --condition on-event -k --probe="${base_symbol}+${offset_hex}" my_channel_enable --action notify
-       add_trigger --condition on-event -k --probe="0x${channel_enable_addr}" my_channel_enable --action notify
+       lttng_add_trigger_ok "T0" --condition on-event -k --probe=lttng_event_container_enable my_channel_enable --action notify
+       lttng_add_trigger_ok "T1" --condition on-event -k --probe="${base_symbol}+${offset_hex}" my_channel_enable --action notify
+       lttng_add_trigger_ok "T2" --condition on-event -k --probe="0x${channel_enable_addr}" my_channel_enable --action notify
 
        cat > "${tmp_expected_stdout}" <<- EOF
        - id: T0
          user id: ${uid}
          condition: event rule hit
-           rule: my_channel_enable (type: probe, location: lttng_channel_enable)
+           rule: my_channel_enable (type: probe, location: lttng_event_container_enable)
+           tracer notifications discarded: 0
          actions:
            notify
        - id: T1
          user id: ${uid}
          condition: event rule hit
            rule: my_channel_enable (type: probe, location: ${base_symbol}+${offset_hex})
+           tracer notifications discarded: 0
          actions:
            notify
        - id: T2
          user id: ${uid}
          condition: event rule hit
            rule: my_channel_enable (type: probe, location: 0x${channel_enable_addr})
+           tracer notifications discarded: 0
          actions:
            notify
        EOF
@@ -208,13 +255,14 @@ test_on_event_userspace_probe ()
        # shellcheck disable=SC2119
        start_lttng_sessiond_notap
 
-       add_trigger --condition on-event -k --userspace-probe=${uprobe_elf_binary}:test_function ma-probe --action notify
+       lttng_add_trigger_ok "T0" --condition on-event -k --userspace-probe=${uprobe_elf_binary}:test_function ma-probe --action notify
 
        cat > "${tmp_expected_stdout}" <<- EOF
        - id: T0
          user id: ${uid}
          condition: event rule hit
            rule: ma-probe (type: userspace probe, location: ${uprobe_elf_binary}:test_function)
+           tracer notifications discarded: 0
          actions:
            notify
        EOF
@@ -229,20 +277,22 @@ test_on_event_syscall ()
        # shellcheck disable=SC2119
        start_lttng_sessiond_notap
 
-       add_trigger --condition on-event -k --syscall open --action notify
-       add_trigger --condition on-event -k --syscall ptrace --filter 'a > 2' --action notify
+       lttng_add_trigger_ok "T0" --condition on-event -k --syscall open --action notify
+       lttng_add_trigger_ok "T1" --condition on-event -k --syscall ptrace --filter 'a > 2' --action notify
 
        cat > "${tmp_expected_stdout}" <<- EOF
        - id: T0
          user id: ${uid}
          condition: event rule hit
            rule: open (type: syscall)
+           tracer notifications discarded: 0
          actions:
            notify
        - id: T1
          user id: ${uid}
          condition: event rule hit
            rule: ptrace (type: syscall, filter: a > 2)
+           tracer notifications discarded: 0
          actions:
            notify
        EOF
@@ -256,14 +306,14 @@ test_snapshot_action ()
 {
        start_lttng_sessiond_notap
 
-       add_trigger --condition on-event -u some-event --action snapshot-session ze-session
-       add_trigger --condition on-event -u some-event --action snapshot-session ze-session --path /some/path
-       add_trigger --condition on-event -u some-event --action snapshot-session ze-session --url file:///some/other/path
-       add_trigger --condition on-event -u some-event --action snapshot-session ze-session --url net://1.2.3.4
-       add_trigger --condition on-event -u some-event --action snapshot-session ze-session --url net://1.2.3.4:1234:1235
-       add_trigger --condition on-event -u some-event --action snapshot-session ze-session --ctrl-url=tcp://1.2.3.4:1111 --data-url=tcp://1.2.3.4:1112
-       add_trigger --condition on-event -u some-event --action snapshot-session ze-session --path /some/path --max-size=1234
-       add_trigger --condition on-event -u some-event --action snapshot-session ze-session --path /some/path --name=meh
+       lttng_add_trigger_ok "T0" --condition on-event -u some-event --action snapshot-session ze-session
+       lttng_add_trigger_ok "T1" --condition on-event -u some-event --action snapshot-session ze-session --path /some/path
+       lttng_add_trigger_ok "T2" --condition on-event -u some-event --action snapshot-session ze-session --url file:///some/other/path
+       lttng_add_trigger_ok "T3" --condition on-event -u some-event --action snapshot-session ze-session --url net://1.2.3.4
+       lttng_add_trigger_ok "T4" --condition on-event -u some-event --action snapshot-session ze-session --url net://1.2.3.4:1234:1235
+       lttng_add_trigger_ok "T5" --condition on-event -u some-event --action snapshot-session ze-session --ctrl-url=tcp://1.2.3.4:1111 --data-url=tcp://1.2.3.4:1112
+       lttng_add_trigger_ok "T6" --condition on-event -u some-event --action snapshot-session ze-session --path /some/path --max-size=1234
+       lttng_add_trigger_ok "T7" --condition on-event -u some-event --action snapshot-session ze-session --path /some/path --name=meh
 
 
        cat > "${tmp_expected_stdout}" <<- EOF
@@ -271,48 +321,56 @@ test_snapshot_action ()
          user id: ${uid}
          condition: event rule hit
            rule: some-event (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            snapshot session \`ze-session\`
        - id: T1
          user id: ${uid}
          condition: event rule hit
            rule: some-event (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            snapshot session \`ze-session\`, path: /some/path
        - id: T2
          user id: ${uid}
          condition: event rule hit
            rule: some-event (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            snapshot session \`ze-session\`, path: /some/other/path
        - id: T3
          user id: ${uid}
          condition: event rule hit
            rule: some-event (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            snapshot session \`ze-session\`, url: net://1.2.3.4
        - id: T4
          user id: ${uid}
          condition: event rule hit
            rule: some-event (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            snapshot session \`ze-session\`, url: net://1.2.3.4:1234:1235
        - id: T5
          user id: ${uid}
          condition: event rule hit
            rule: some-event (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            snapshot session \`ze-session\`, control url: tcp://1.2.3.4:1111, data url: tcp://1.2.3.4:1112
        - id: T6
          user id: ${uid}
          condition: event rule hit
            rule: some-event (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            snapshot session \`ze-session\`, path: /some/path, max size: 1234
        - id: T7
          user id: ${uid}
          condition: event rule hit
            rule: some-event (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
          actions:
            snapshot session \`ze-session\`, path: /some/path, name: meh
        EOF
@@ -322,12 +380,90 @@ test_snapshot_action ()
        stop_lttng_sessiond_notap
 }
 
+test_on_event_kernel_incr_value ()
+{
+       local session="session_doesnt_need_to_exist"
+       local map="map_doesnt_need_to_exist"
+       # shellcheck disable=SC2119
+       start_lttng_sessiond_notap
+
+       lttng_add_trigger_ok "T0" --condition on-event -k some-event --action incr-value -s $session -m $map --key string
+       lttng_add_trigger_ok "T1" --condition on-event -k some-event2 --action incr-value -s $session -m $map --key prefix_$\{EVENT_NAME\}
+
+       cat > "${tmp_expected_stdout}" <<- EOF
+       - id: T0
+         user id: ${uid}
+         condition: event rule hit
+           rule: some-event (type: tracepoint, domain: kernel)
+           tracer notifications discarded: 0
+         actions:
+           increment value:
+              session: \`${session}\`
+              map: \`${map}\`
+              key: \`string\`
+       - id: T1
+         user id: ${uid}
+         condition: event rule hit
+           rule: some-event2 (type: tracepoint, domain: kernel)
+           tracer notifications discarded: 0
+         actions:
+           increment value:
+              session: \`${session}\`
+              map: \`${map}\`
+              key: \`prefix_\${EVENT_NAME}\`
+       EOF
+
+       list_triggers "on-event kernel incr-value" "${tmp_expected_stdout}"
+
+       stop_lttng_sessiond_notap
+}
+
+test_on_event_ust_incr_value ()
+{
+       local session="session_doesnt_need_to_exist"
+       local map="map_doesnt_need_to_exist"
+       # shellcheck disable=SC2119
+       start_lttng_sessiond_notap
+
+       lttng_add_trigger_ok "T0" --condition on-event -u some-event --action incr-value -s $session -m $map --key string
+       lttng_add_trigger_ok "T1" --condition on-event -u some-event2 --action incr-value -s $session -m $map --key prefix_$\{EVENT_NAME\}
+
+       cat > "${tmp_expected_stdout}" <<- EOF
+       - id: T0
+         user id: ${uid}
+         condition: event rule hit
+           rule: some-event (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
+         actions:
+           increment value:
+              session: \`${session}\`
+              map: \`${map}\`
+              key: \`string\`
+       - id: T1
+         user id: ${uid}
+         condition: event rule hit
+           rule: some-event2 (type: tracepoint, domain: ust)
+           tracer notifications discarded: 0
+         actions:
+           increment value:
+              session: \`${session}\`
+              map: \`${map}\`
+              key: \`prefix_\${EVENT_NAME}\`
+       EOF
+
+       list_triggers "on-event UST incr-value" "${tmp_expected_stdout}"
+
+       stop_lttng_sessiond_notap
+}
+
 test_top_level_options
 test_on_event_tracepoint
 skip $ist_root "non-root user: skipping kprobe tests" 6 || test_on_event_probe
 skip $ist_root "non-root user: skipping uprobe tests" 4 || test_on_event_userspace_probe
 skip $ist_root "non-root user: skipping syscall tests" 5 || test_on_event_syscall
 test_snapshot_action
+skip $ist_root "non-root user: skipping incr-value tests" 5 || test_on_event_kernel_incr_value
+test_on_event_ust_incr_value
 
 # Cleanup
 rm -f "${tmp_stdout}"
index 168227a4ab84d404205ca6414e336119380d787c..582cce7ef3fe4958aef349d455b145354601d4ae 100755 (executable)
@@ -34,12 +34,6 @@ tmp_expected_stdout=$(mktemp -t test_list_triggers_cli_expected_stdout.XXXXXX)
 uid=$(id --user)
 gid=$(id --group)
 
-function add_trigger ()
-{
-       "${FULL_LTTNG_BIN}" add-trigger "$@"
-       ok $? "add trigger \`$*\`: exit code is 0"
-}
-
 function list_triggers ()
 {
        local test_name="$1"
@@ -74,20 +68,22 @@ function remove_trigger ()
 start_lttng_sessiond_notap
 
 # Add a few triggers
-add_trigger --condition on-event -u -a --action notify
-add_trigger --id ABC --condition on-event aaa -u --filter 'p == 2' --action notify
+lttng_add_trigger_ok "ABC" --condition on-event aaa -u --filter 'p == 2' --action notify
+lttng_add_trigger_ok "DEF" --condition on-event -u -a --action notify
 
 cat > "${tmp_expected_stdout}" <<- EOF
 - id: ABC
   user id: ${uid}
   condition: event rule hit
     rule: aaa (type: tracepoint, domain: ust, filter: p == 2)
+    tracer notifications discarded: 0
   actions:
     notify
-- id: T0
+- id: DEF
   user id: ${uid}
   condition: event rule hit
     rule: * (type: tracepoint, domain: ust)
+    tracer notifications discarded: 0
   actions:
     notify
 EOF
@@ -96,16 +92,17 @@ list_triggers "two triggers left" "${tmp_expected_stdout}"
 remove_trigger "ABC"
 
 cat > "${tmp_expected_stdout}" <<- EOF
-- id: T0
+- id: DEF
   user id: ${uid}
   condition: event rule hit
     rule: * (type: tracepoint, domain: ust)
+    tracer notifications discarded: 0
   actions:
     notify
 EOF
 list_triggers "one trigger left" "${tmp_expected_stdout}"
 
-remove_trigger "T0"
+remove_trigger "DEF"
 
 list_triggers "no triggers left" "/dev/null"
 
index aecc478bd3fcc63e02ac79eb9e28c46978c458a7..47f1d67aa92930d91a67608d16d32e50fb876854 100644 (file)
@@ -14,7 +14,7 @@
 #include <sys/time.h>
 #include <time.h>
 
-#include <lttng/condition/event-rule.h>
+#include <lttng/condition/on-event.h>
 #include <lttng/lttng.h>
 
 #include "utils.h"
@@ -69,7 +69,7 @@ static bool is_expected_trigger_name(const char *expected_trigger_name,
        case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
        case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
                break;
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+       case LTTNG_CONDITION_TYPE_ON_EVENT:
        {
                const char *trigger_name;
                enum lttng_evaluation_status evaluation_status;
index 01b2981524bdebb271c9a867d03946c087e85b06..a88fe0b6cf7c3d56eb303fb0842fce4d314760a3 100644 (file)
@@ -8,27 +8,33 @@ LOG_DRIVER_FLAGS='--merge'
 LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
        $(top_srcdir)/config/tap-driver.sh
 
-TESTS = test_kernel_data \
-       test_session \
-       test_uri \
-       test_utils_parse_size_suffix \
-       test_utils_parse_time_suffix \
-       test_utils_expand_path \
-       test_utils_compat_poll \
-       test_utils_compat_pthread \
-       test_string_utils \
-       test_notification \
-       test_event_rule \
-       test_directory_handle \
-       test_relayd_backward_compat_group_by_session \
+TESTS = \
        ini_config/test_ini_config \
-       test_fd_tracker \
-       test_uuid \
+       test_action \
        test_buffer_view \
+       test_directory_handle \
        test_event_expr_to_bytecode \
+       test_event_rule \
+       test_fd_tracker \
+       test_kernel_data \
+       test_kernel_probe \
+       test_log_level_rule \
+       test_map \
+       test_map_key \
+       test_map_query \
+       test_notification \
        test_payload \
+       test_relayd_backward_compat_group_by_session \
+       test_session \
+       test_string_utils \
        test_unix_socket \
-       test_kernel_probe
+       test_uri \
+       test_utils_compat_poll \
+       test_utils_compat_pthread \
+       test_utils_expand_path \
+       test_utils_parse_size_suffix \
+       test_utils_parse_time_suffix \
+       test_uuid
 
 LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la
 
@@ -41,19 +47,33 @@ LIBRELAYD=$(top_builddir)/src/common/relayd/librelayd.la
 LIBLTTNG_CTL=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
 
 # Define test programs
-noinst_PROGRAMS = test_uri test_session test_kernel_data \
-                  test_utils_parse_size_suffix test_utils_parse_time_suffix \
-                  test_utils_expand_path test_utils_compat_poll test_utils_compat_pthread \
-                  test_string_utils test_notification test_directory_handle \
-                  test_relayd_backward_compat_group_by_session \
-                  test_fd_tracker test_uuid \
-                  test_buffer_view \
-                  test_payload \
-                  test_unix_socket \
-                  test_kernel_probe \
-                  test_condition \
-                 test_event_expr_to_bytecode \
-                  test_event_rule 
+noinst_PROGRAMS = \
+       test_action \
+       test_buffer_view \
+       test_condition \
+       test_directory_handle \
+       test_event_expr_to_bytecode \
+       test_event_rule \
+       test_fd_tracker \
+       test_kernel_data \
+       test_kernel_probe \
+       test_log_level_rule \
+       test_map \
+       test_map_key \
+       test_map_query \
+       test_notification \
+       test_payload \
+       test_relayd_backward_compat_group_by_session \
+       test_session \
+       test_string_utils \
+       test_unix_socket \
+       test_uri \
+       test_utils_compat_poll \
+       test_utils_compat_pthread \
+       test_utils_expand_path \
+       test_utils_parse_size_suffix \
+       test_utils_parse_time_suffix \
+       test_uuid
 
 if HAVE_LIBLTTNG_UST_CTL
 noinst_PROGRAMS += test_ust_data
@@ -70,7 +90,6 @@ SESSIOND_OBJS = $(top_builddir)/src/bin/lttng-sessiond/buffer-registry.$(OBJEXT)
         $(top_builddir)/src/bin/lttng-sessiond/condition-internal.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/save.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/notification-thread-commands.$(OBJEXT) \
-        $(top_builddir)/src/bin/lttng-sessiond/shm.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/kernel.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/ht-cleanup.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/notification-thread.$(OBJEXT) \
@@ -79,6 +98,7 @@ SESSIOND_OBJS = $(top_builddir)/src/bin/lttng-sessiond/buffer-registry.$(OBJEXT)
         $(top_builddir)/src/bin/lttng-sessiond/channel.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/agent.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/kernel-consumer.$(OBJEXT) \
+        $(top_builddir)/src/bin/lttng-sessiond/map.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/trace-kernel.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/rotation-thread.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/context.$(OBJEXT) \
@@ -87,6 +107,7 @@ SESSIOND_OBJS = $(top_builddir)/src/bin/lttng-sessiond/buffer-registry.$(OBJEXT)
         $(top_builddir)/src/bin/lttng-sessiond/fd-limit.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/notification-thread-events.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/event.$(OBJEXT) \
+        $(top_builddir)/src/bin/lttng-sessiond/event-notifier-error-accounting.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/timer.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/snapshot.$(OBJEXT) \
         $(top_builddir)/src/bin/lttng-sessiond/sessiond-config.$(OBJEXT) \
@@ -200,6 +221,18 @@ test_directory_handle_LDADD = $(LIBTAP) $(LIBHASHTABLE) $(LIBCOMMON) $(DL_LIBS)
 test_string_utils_SOURCES = test_string_utils.c
 test_string_utils_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBSTRINGUTILS) $(DL_LIBS)
 
+# Map api
+test_map_SOURCES = test_map.c
+test_map_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
+
+# Map key api
+test_map_key_SOURCES = test_map_key.c
+test_map_key_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
+
+# Map query api
+test_map_query_SOURCES = test_map_query.c
+test_map_query_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
+
 # Notification api
 test_notification_SOURCES = test_notification.c
 test_notification_LDADD = $(LIBTAP) $(LIBLTTNG_CTL) $(DL_LIBS)
@@ -208,6 +241,10 @@ test_notification_LDADD = $(LIBTAP) $(LIBLTTNG_CTL) $(DL_LIBS)
 test_event_rule_SOURCES = test_event_rule.c
 test_event_rule_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
 
+# Action api
+test_action_SOURCES = test_action.c
+test_action_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
+#
 # Condition api
 test_condition_SOURCES = test_condition.c
 test_condition_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
@@ -244,3 +281,7 @@ test_kernel_probe_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
 # Event expression to bytecode test
 test_event_expr_to_bytecode_SOURCES = test_event_expr_to_bytecode.c
 test_event_expr_to_bytecode_LDADD = $(LIBTAP) $(LIBLTTNG_CTL) $(LIBCOMMON)
+
+# Log level rule api
+test_log_level_rule_SOURCES = test_log_level_rule.c
+test_log_level_rule_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
diff --git a/tests/unit/test_action.c b/tests/unit/test_action.c
new file mode 100644 (file)
index 0000000..6e526c5
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * test_action.c
+ *
+ * Unit tests for the action API.
+ *
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <lttng/action/action.h>
+#include <lttng/action/action-internal.h>
+#include <lttng/action/incr-value.h>
+#include <lttng/action/incr-value-internal.h>
+
+#include <lttng/map-key-internal.h>
+
+#include <common/dynamic-buffer.h>
+#include <common/buffer-view.h>
+#include <common/payload.h>
+
+/* For error.h */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+#define NUM_TESTS 14
+
+static
+void test_action_incr_value(void)
+{
+       int ret;
+       struct lttng_action *action = NULL;
+       struct lttng_action *action_from_buffer = NULL;
+       const char *map_name = "my_map_name";
+       const char *session_name = "my_session_name";
+       const char *first_part_key = "first_part_🥇_";
+       const char *second_part_key = "_🥈_second_part";
+       struct lttng_map_key *key = NULL;
+       enum lttng_action_status action_status;
+       enum lttng_map_key_status key_status;
+       struct lttng_payload buffer;
+       const struct lttng_map_key *key_from_buffer;
+       const struct lttng_map_key_token *token;
+
+       lttng_payload_init(&buffer);
+
+       /* Test key creation */
+       key = lttng_map_key_create();
+       ok(key, "Key created");
+
+       key_status = lttng_map_key_append_token_string(key, first_part_key);
+       ok(key_status == LTTNG_MAP_KEY_STATUS_OK, "Key append first string");
+
+       key_status = lttng_map_key_append_token_variable(key, LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME);
+       ok(key_status == LTTNG_MAP_KEY_STATUS_OK, "Key append event name variable");
+
+       key_status = lttng_map_key_append_token_string(key, second_part_key);
+       ok(key_status == LTTNG_MAP_KEY_STATUS_OK, "Key append second string");
+
+       /*Test incr value action creation */
+       action = lttng_action_incr_value_create();
+       ok(action, "Incr-value action created");
+
+       action_status = lttng_action_incr_value_set_session_name(action, session_name);
+       ok(action_status == LTTNG_ACTION_STATUS_OK, "incr-value set session name");
+
+       action_status = lttng_action_incr_value_set_map_name(action, map_name);
+       ok(action_status == LTTNG_ACTION_STATUS_OK, "incr-value set map name");
+
+       action_status = lttng_action_incr_value_set_key(action, key);
+       ok(action_status == LTTNG_ACTION_STATUS_OK, "incr-value set key");
+
+       /* Test incr value action serialization */
+       ret = lttng_action_serialize(action, &buffer);
+       ok(ret == 0, "Incr value action serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(&buffer, 0, -1);
+
+               (void) lttng_action_create_from_payload(
+                               &view, &action_from_buffer);
+       }
+       ok(action_from_buffer, "Incr value action created from payload is non-null");
+
+       action_status = lttng_action_incr_value_get_key(action, &key_from_buffer);
+       ok(key_from_buffer, "Retrived key from incr value action");
+
+       token = lttng_map_key_get_token_at_index(key_from_buffer, 0);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING, "First key token is a string");
+
+       token = lttng_map_key_get_token_at_index(key_from_buffer, 1);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE, "Second key token is a variable");
+
+       token = lttng_map_key_get_token_at_index(key_from_buffer, 2);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING, "Third key token is a string");
+
+       lttng_payload_reset(&buffer);
+
+       lttng_action_destroy(action);
+       lttng_action_destroy(action_from_buffer);
+       lttng_map_key_destroy(key);
+}
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+       test_action_incr_value();
+       return exit_status();
+}
index 3b0144a0aae9994c4e212758b75290f7b04afbcf..539e0b0b663300737a617c577470fc179c446c37 100644 (file)
 #include <lttng/event.h>
 #include <lttng/event-rule/tracepoint.h>
 #include <lttng/condition/condition-internal.h>
-#include <lttng/condition/event-rule.h>
+#include <lttng/condition/on-event.h>
+#include <lttng/condition/on-event-internal.h>
 #include <lttng/domain.h>
+#include <lttng/log-level-rule.h>
 #include <common/dynamic-buffer.h>
 #include <common/buffer-view.h>
 
@@ -30,7 +32,7 @@ int lttng_opt_quiet = 1;
 int lttng_opt_verbose;
 int lttng_opt_mi;
 
-#define NUM_TESTS 13
+#define NUM_TESTS 15
 
 static
 void test_condition_event_rule(void)
@@ -45,10 +47,16 @@ void test_condition_event_rule(void)
        const char *pattern="my_event_*";
        const char *filter="msg_id == 23 && size >= 2048";
        const char *exclusions[] = { "my_event_test1", "my_event_test2", "my_event_test3" };
+       uint64_t _error_count = 420, _error_counter_index = 9999, error_count, error_counter_index;
+       struct lttng_log_level_rule *log_level_rule_at_least_as_severe = NULL;
        struct lttng_payload buffer;
 
        lttng_payload_init(&buffer);
 
+       /* Create log level rule */
+       log_level_rule_at_least_as_severe = lttng_log_level_rule_at_least_as_severe_as_create(LTTNG_LOGLEVEL_WARNING);
+       assert(log_level_rule_at_least_as_severe);
+
        tracepoint = lttng_event_rule_tracepoint_create(LTTNG_DOMAIN_UST);
        ok(tracepoint, "tracepoint UST_DOMAIN");
 
@@ -58,8 +66,7 @@ void test_condition_event_rule(void)
        status = lttng_event_rule_tracepoint_set_filter(tracepoint, filter);
        ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Setting filter");
 
-       status = lttng_event_rule_tracepoint_set_log_level_range_lower_bound(
-                       tracepoint, LTTNG_LOGLEVEL_WARNING);
+       status = lttng_event_rule_tracepoint_set_log_level_rule(tracepoint, log_level_rule_at_least_as_severe);
        ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Setting log level range");
 
        for (i = 0; i < 3; i++) {
@@ -69,10 +76,14 @@ void test_condition_event_rule(void)
                                "Setting exclusion pattern");
        }
 
-       condition = lttng_condition_event_rule_create(tracepoint);
+       condition = lttng_condition_on_event_create(tracepoint);
        ok(condition, "Created condition");
 
-       condition_status = lttng_condition_event_rule_get_rule(
+       /* Set the error count information */
+       lttng_condition_on_event_set_error_count(condition, _error_count);
+       lttng_condition_on_event_set_error_counter_index(condition, _error_counter_index);
+
+       condition_status = lttng_condition_on_event_get_rule(
                        condition, &tracepoint_tmp);
        ok(condition_status == LTTNG_CONDITION_STATUS_OK,
                        "Getting event rule from event rule condition");
@@ -94,10 +105,17 @@ void test_condition_event_rule(void)
        ok(lttng_condition_is_equal(condition, condition_from_buffer),
                        "Serialized and de-serialized conditions are equal");
 
+       /* Error count info is not considered in is_equal so test it separately */
+       error_count = lttng_condition_on_event_get_error_count(condition_from_buffer);
+       error_counter_index = lttng_condition_on_event_get_error_counter_index(condition_from_buffer);
+       ok(error_count == _error_count, "Error count is the same. Got %" PRIu64 " Expected %" PRIu64, error_count, _error_count);
+       ok(error_counter_index == _error_counter_index, "Error count index is the same. Got %" PRIu64 " Expected %" PRIu64, error_count, _error_count);
+
        lttng_payload_reset(&buffer);
        lttng_event_rule_destroy(tracepoint);
        lttng_condition_destroy(condition);
        lttng_condition_destroy(condition_from_buffer);
+       lttng_log_level_rule_destroy(log_level_rule_at_least_as_severe);
 }
 
 int main(int argc, const char *argv[])
index 53f16dbbddbca3a6b3e5d3e71a79e6502ddd8d47..050b9d119d53fdefee413d36e131310fe4bcf7fe 100644 (file)
 #include <common/payload-view.h>
 #include <common/payload.h>
 #include <lttng/domain.h>
-#include <lttng/event-rule/kprobe-internal.h>
-#include <lttng/event-rule/kprobe.h>
+#include <lttng/event-rule/kernel-probe-internal.h>
+#include <lttng/event-rule/kernel-probe.h>
 #include <lttng/event-rule/syscall-internal.h>
 #include <lttng/event-rule/syscall.h>
 #include <lttng/event-rule/tracepoint-internal.h>
 #include <lttng/event-rule/tracepoint.h>
-#include <lttng/event-rule/uprobe-internal.h>
-#include <lttng/event-rule/uprobe.h>
+#include <lttng/event-rule/userspace-probe-internal.h>
+#include <lttng/event-rule/userspace-probe.h>
 #include <lttng/event.h>
 #include <lttng/kernel-probe-internal.h>
 #include <lttng/kernel-probe.h>
@@ -37,7 +37,7 @@ int lttng_opt_quiet = 1;
 int lttng_opt_verbose;
 int lttng_opt_mi;
 
-#define NUM_TESTS 187
+#define NUM_TESTS 144
 
 struct tracepoint_test {
        enum lttng_domain_type type;
@@ -47,17 +47,17 @@ struct tracepoint_test {
 static
 void test_event_rule_tracepoint_by_domain(const struct tracepoint_test *test)
 {
-       int ret;
        unsigned int count;
        struct lttng_event_rule *tracepoint = NULL;
        struct lttng_event_rule *tracepoint_from_buffer = NULL;
        enum lttng_event_rule_status status;
        enum lttng_domain_type domain_type, type;
-       enum lttng_loglevel_type log_level_type;
        const char *pattern="my_event_*";
        const char *filter="msg_id == 23 && size >= 2048";
        const char *tmp;
        const char *exclusions[] = {"my_event_test1", "my_event_test2" ,"my_event_test3"};
+       struct lttng_log_level_rule *log_level_rule = NULL;
+       const struct lttng_log_level_rule *log_level_rule_return = NULL;
        struct lttng_payload payload;
 
        type = test->type;
@@ -65,6 +65,9 @@ void test_event_rule_tracepoint_by_domain(const struct tracepoint_test *test)
 
        lttng_payload_init(&payload);
 
+       log_level_rule = lttng_log_level_rule_exactly_create(LTTNG_LOGLEVEL_INFO);
+       assert(log_level_rule);
+
        tracepoint = lttng_event_rule_tracepoint_create(type);
        ok(tracepoint, "tracepoint object.");
 
@@ -84,28 +87,13 @@ void test_event_rule_tracepoint_by_domain(const struct tracepoint_test *test)
        ok(status == LTTNG_EVENT_RULE_STATUS_OK, "getting filter.");
        ok(!strncmp(filter, tmp, strlen(filter)), "filter is equal.");
 
-       status = lttng_event_rule_tracepoint_set_log_level_all(tracepoint);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting all log level.");
-       status = lttng_event_rule_tracepoint_get_log_level_type(tracepoint, &log_level_type);
-       ok(log_level_type == LTTNG_EVENT_LOGLEVEL_ALL, "getting loglevel type all.");
-       status = lttng_event_rule_tracepoint_get_log_level(tracepoint, &ret);
-       ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset loglevel value.");
-
-       status = lttng_event_rule_tracepoint_set_log_level(tracepoint, LTTNG_LOGLEVEL_INFO);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting single loglevel.");
-       status = lttng_event_rule_tracepoint_get_log_level_type(tracepoint, &log_level_type);
-       ok(log_level_type == LTTNG_EVENT_LOGLEVEL_SINGLE, "getting loglevel type single.");
-       status = lttng_event_rule_tracepoint_get_log_level(tracepoint, &ret);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get loglevel value.");
-       ok(ret == LTTNG_LOGLEVEL_INFO, "loglevel value is equal.");
-
-       status = lttng_event_rule_tracepoint_set_log_level_range_lower_bound(tracepoint, LTTNG_LOGLEVEL_WARNING);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting range loglevel.");
-       status = lttng_event_rule_tracepoint_get_log_level_type(tracepoint, &log_level_type);
-       ok(log_level_type == LTTNG_EVENT_LOGLEVEL_RANGE, "getting loglevel type range.");
-       status = lttng_event_rule_tracepoint_get_log_level(tracepoint, &ret);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get loglevel value.");
-       ok(ret == LTTNG_LOGLEVEL_WARNING, "loglevel valuei is equal.");
+       status = lttng_event_rule_tracepoint_get_log_level_rule(tracepoint, &log_level_rule_return);
+       ok(status == LTTNG_EVENT_RULE_STATUS_UNSET, "get unset log level rule.");
+
+       status = lttng_event_rule_tracepoint_set_log_level_rule(tracepoint, log_level_rule);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "setting log level rule.");
+       status = lttng_event_rule_tracepoint_get_log_level_rule(tracepoint, &log_level_rule_return);
+       ok(status == LTTNG_EVENT_RULE_STATUS_OK, "get log level rule.");
 
        if (test->support_exclusion) {
                int i;
@@ -154,6 +142,7 @@ void test_event_rule_tracepoint_by_domain(const struct tracepoint_test *test)
        lttng_payload_reset(&payload);
        lttng_event_rule_destroy(tracepoint);
        lttng_event_rule_destroy(tracepoint_from_buffer);
+       lttng_log_level_rule_destroy(log_level_rule);
 }
 
 static
@@ -225,7 +214,7 @@ static void test_event_rule_syscall(void)
        lttng_event_rule_destroy(syscall_from_buffer);
 }
 
-static void test_event_rule_uprobe(void)
+static void test_event_rule_userspace_probe(void)
 {
        struct lttng_event_rule *uprobe = NULL;
        struct lttng_event_rule *uprobe_from_buffer = NULL;
@@ -261,14 +250,10 @@ static void test_event_rule_uprobe(void)
 
        lttng_payload_init(&payload);
 
-       uprobe = lttng_event_rule_uprobe_create();
+       uprobe = lttng_event_rule_userspace_probe_create(probe_location);
        ok(uprobe, "uprobe event rule object creation.");
 
-       status = lttng_event_rule_uprobe_set_location(uprobe, probe_location);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting uprobe event rule location.");
-
-       status = lttng_event_rule_uprobe_get_location(
+       status = lttng_event_rule_userspace_probe_get_location(
                        uprobe, &probe_location_tmp);
        ok(status == LTTNG_EVENT_RULE_STATUS_OK,
                        "Getting uprobe event rule location.");
@@ -276,10 +261,10 @@ static void test_event_rule_uprobe(void)
                           probe_location, probe_location_tmp),
                        "Location is equal.");
 
-       status = lttng_event_rule_uprobe_set_name(uprobe, probe_name);
+       status = lttng_event_rule_userspace_probe_set_event_name(uprobe, probe_name);
        ok(status == LTTNG_EVENT_RULE_STATUS_OK,
                        "Setting uprobe event rule name: %s.", probe_name);
-       status = lttng_event_rule_uprobe_get_name(uprobe, &tmp);
+       status = lttng_event_rule_userspace_probe_get_event_name(uprobe, &tmp);
        ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Getting uprobe name.");
        ok(!strcmp(probe_name, tmp), "Uprobe name are equal.");
 
@@ -306,7 +291,7 @@ end:
        lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
 }
 
-static void test_event_rule_kprobe_by_location(
+static void test_event_rule_kernel_probe_by_location(
                const struct lttng_kernel_probe_location *location)
 {
        struct lttng_event_rule *kprobe = NULL;
@@ -323,21 +308,18 @@ static void test_event_rule_kprobe_by_location(
 
        lttng_payload_init(&payload);
 
-       kprobe = lttng_event_rule_kprobe_create();
+       kprobe = lttng_event_rule_kernel_probe_create(location);
        ok(kprobe, "kprobe event rule object creation.");
 
-       status = lttng_event_rule_kprobe_set_location(kprobe, location);
-       ok(status == LTTNG_EVENT_RULE_STATUS_OK,
-                       "Setting kprobe event rule location.");
-       status = lttng_event_rule_kprobe_get_location(kprobe, &_location);
+       status = lttng_event_rule_kernel_probe_get_location(kprobe, &_location);
        ok(status == LTTNG_EVENT_RULE_STATUS_OK,
                        "Getting kprobe event rule location.");
        ok(lttng_kernel_probe_location_is_equal(location, _location), "Locations are equal.");
 
-       status = lttng_event_rule_kprobe_set_name(kprobe, probe_name);
+       status = lttng_event_rule_kernel_probe_set_event_name(kprobe, probe_name);
        ok(status == LTTNG_EVENT_RULE_STATUS_OK,
                        "Setting kprobe event rule name: %s.", probe_name);
-       status = lttng_event_rule_kprobe_get_name(kprobe, &tmp);
+       status = lttng_event_rule_kernel_probe_get_event_name(kprobe, &tmp);
        ok(status == LTTNG_EVENT_RULE_STATUS_OK, "Getting kprobe name.");
        ok(!strcmp(probe_name, tmp), "kprobe name are equal.");
 
@@ -361,7 +343,7 @@ static void test_event_rule_kprobe_by_location(
        lttng_event_rule_destroy(kprobe_from_buffer);
 }
 
-static void test_event_rule_kprobe(void)
+static void test_event_rule_kernel_probe(void)
 {
        struct lttng_kernel_probe_location *address_location = NULL;
        struct lttng_kernel_probe_location *symbol_location = NULL;
@@ -371,8 +353,8 @@ static void test_event_rule_kprobe(void)
        assert(address_location);
        assert(symbol_location);
 
-       test_event_rule_kprobe_by_location(address_location);
-       test_event_rule_kprobe_by_location(symbol_location);
+       test_event_rule_kernel_probe_by_location(address_location);
+       test_event_rule_kernel_probe_by_location(symbol_location);
 
        lttng_kernel_probe_location_destroy(address_location);
        lttng_kernel_probe_location_destroy(symbol_location);
@@ -383,7 +365,7 @@ int main(int argc, const char *argv[])
        plan_tests(NUM_TESTS);
        test_event_rule_tracepoint();
        test_event_rule_syscall();
-       test_event_rule_uprobe();
-       test_event_rule_kprobe();
+       test_event_rule_userspace_probe();
+       test_event_rule_kernel_probe();
        return exit_status();
 }
diff --git a/tests/unit/test_log_level_rule.c b/tests/unit/test_log_level_rule.c
new file mode 100644 (file)
index 0000000..9eccc79
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Unit tests for the log level rule API.
+ *
+ * Copyright (C) 2020 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <common/payload-view.h>
+#include <common/payload.h>
+#include <lttng/log-level-rule-internal.h>
+#include <lttng/log-level-rule.h>
+
+/* For error.h. */
+int lttng_opt_quiet = 1;
+int lttng_opt_verbose;
+int lttng_opt_mi;
+
+#define NUM_TESTS 29
+
+static void test_log_level_rule_error(void)
+{
+       int level = 9000;
+       struct lttng_log_level_rule *exactly =
+                       lttng_log_level_rule_exactly_create(level);
+       struct lttng_log_level_rule *at_least_as_severe =
+                       lttng_log_level_rule_at_least_as_severe_as_create(
+                                       level);
+
+       ok(lttng_log_level_rule_get_type(NULL) == LTTNG_LOG_LEVEL_RULE_TYPE_UNKNOWN, "Get type on invalid pointer");
+
+       ok(lttng_log_level_rule_exactly_get_level(NULL, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (NULL, NULL) returns invalid");
+       ok(lttng_log_level_rule_exactly_get_level(exactly, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (valid, NULL) returns invalid");
+       ok(lttng_log_level_rule_exactly_get_level(NULL, &level) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_exactly_get_level (NULL, valid) returns invalid");
+
+       ok(lttng_log_level_rule_at_least_as_severe_as_get_level(NULL, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (NULL, NULL) returns invalid");
+       ok(lttng_log_level_rule_at_least_as_severe_as_get_level(exactly, NULL) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (valid, NULL) returns invalid");
+       ok(lttng_log_level_rule_at_least_as_severe_as_get_level(NULL, &level) == LTTNG_LOG_LEVEL_RULE_STATUS_INVALID, "lttng_log_level_rule_at_least_as_severe_as_get_level (NULL, valid) returns invalid");
+
+       lttng_log_level_rule_destroy(exactly);
+       lttng_log_level_rule_destroy(at_least_as_severe);
+}
+
+static
+void test_log_level_rule_serialize_deserialize(const struct lttng_log_level_rule *rule)
+{
+       struct lttng_log_level_rule *log_level_rule_from_buffer = NULL;
+       struct lttng_payload payload;
+
+       lttng_payload_init(&payload);
+
+       ok(lttng_log_level_rule_serialize(rule, &payload) == 0, "Serializing.");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &payload, 0, -1);
+
+               ok(lttng_log_level_rule_create_from_payload(
+                               &view, &log_level_rule_from_buffer) > 0,
+                               "Deserializing.");
+       }
+
+       ok(lttng_log_level_rule_is_equal(rule, log_level_rule_from_buffer), "Serialized and from buffer are equal");
+
+       lttng_log_level_rule_destroy(log_level_rule_from_buffer);
+}
+
+static
+void test_log_level_rule_is_equal_exactly(void)
+{
+       int level = 9000, no_eq_level = 420;
+       struct lttng_log_level_rule *a, *b, *different_level, *different_type;
+
+       /* Identical log level rules. */
+       a = lttng_log_level_rule_exactly_create(level);
+       b = lttng_log_level_rule_exactly_create(level);
+
+       /* Different level, same type. */
+       different_level = lttng_log_level_rule_exactly_create(no_eq_level);
+
+       /* Different type */
+       different_type = lttng_log_level_rule_at_least_as_severe_as_create(level);
+
+       assert(a && b && different_level && different_type);
+
+       ok(lttng_log_level_rule_is_equal(a, a), "Same object is equal");
+       ok(lttng_log_level_rule_is_equal(a, b), "Object a and b are equal");
+       ok(!lttng_log_level_rule_is_equal(a, different_level), " Object of different levels are not equal");
+       ok(!lttng_log_level_rule_is_equal(a, different_type), " Object of different types are not equal");
+
+       lttng_log_level_rule_destroy(a);
+       lttng_log_level_rule_destroy(b);
+       lttng_log_level_rule_destroy(different_level);
+       lttng_log_level_rule_destroy(different_type);
+}
+
+static
+void test_log_level_rule_is_equal_at_least_as_severe_as(void)
+{
+       int level = 9000, no_eq_level = 420;
+       struct lttng_log_level_rule *a, *b, *different_level, *different_type;
+
+       /* Identical log level rules. */
+       a = lttng_log_level_rule_at_least_as_severe_as_create(level);
+       b = lttng_log_level_rule_at_least_as_severe_as_create(level);
+
+       /* Different level, same type. */
+       different_level = lttng_log_level_rule_at_least_as_severe_as_create(no_eq_level);
+
+       /* Different type */
+       different_type = lttng_log_level_rule_exactly_create(level);
+
+       assert(a && b && different_level && different_type);
+
+       ok(lttng_log_level_rule_is_equal(a, a), "Same object is equal");
+       ok(lttng_log_level_rule_is_equal(a, b), "Object a and b are equal");
+       ok(!lttng_log_level_rule_is_equal(a, different_level), " Object of different levels are not equal");
+       ok(!lttng_log_level_rule_is_equal(a, different_type), " Object of different types are not equal");
+
+       lttng_log_level_rule_destroy(a);
+       lttng_log_level_rule_destroy(b);
+       lttng_log_level_rule_destroy(different_level);
+       lttng_log_level_rule_destroy(different_type);
+}
+
+static void test_log_level_rule_exactly(void)
+{
+       int level = 9000;
+       int _level;
+       struct lttng_log_level_rule *exactly = NULL;
+       enum lttng_log_level_rule_status status;
+
+       exactly = lttng_log_level_rule_exactly_create(level);
+
+       ok(exactly, "Log level exactly allocated");
+       ok(lttng_log_level_rule_get_type(exactly) ==
+                                       LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY,
+                       "Log level rule exactly type");
+
+       status = lttng_log_level_rule_exactly_get_level(exactly, &_level);
+       ok(status == LTTNG_LOG_LEVEL_RULE_STATUS_OK, "Get the level");
+       ok(_level == level, "Level property is valid");
+
+       test_log_level_rule_is_equal_exactly();
+       test_log_level_rule_serialize_deserialize(exactly);
+}
+
+static void test_log_level_rule_at_least_as_severe_as(void)
+{
+       int level = 9000;
+       int _level;
+       struct lttng_log_level_rule *at_least_as_severe_as = NULL;
+       enum lttng_log_level_rule_status status;
+
+       at_least_as_severe_as = lttng_log_level_rule_at_least_as_severe_as_create(level);
+
+       ok(at_least_as_severe_as, "Log level at_least_as_severe_as allocated");
+       ok(lttng_log_level_rule_get_type(at_least_as_severe_as) ==
+                                       LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS,
+                       "Log level rule at_least_as_severe_as type");
+
+       status = lttng_log_level_rule_at_least_as_severe_as_get_level(at_least_as_severe_as, &_level);
+       ok(status == LTTNG_LOG_LEVEL_RULE_STATUS_OK, "Get the level");
+       ok(_level == level, "Level property is valid");
+
+       test_log_level_rule_is_equal_at_least_as_severe_as();
+       test_log_level_rule_serialize_deserialize(at_least_as_severe_as);
+}
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+       test_log_level_rule_exactly();
+       test_log_level_rule_at_least_as_severe_as();
+       test_log_level_rule_error();
+       return exit_status();
+}
diff --git a/tests/unit/test_map.c b/tests/unit/test_map.c
new file mode 100644 (file)
index 0000000..f8f6f84
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * test_map.c
+ *
+ * Unit tests for the map API.
+ *
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "lttng/domain.h"
+#include "lttng/map/map.h"
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <lttng/map/map-internal.h>
+
+#include <common/dynamic-buffer.h>
+#include <common/buffer-view.h>
+#include <common/payload.h>
+
+#define NUM_TESTS 70
+
+static
+void test_map_key_value_pair_serialize_deserialize(void)
+{
+       struct lttng_map_key_value_pair *kv;
+       struct lttng_map_key_value_pair *kv_from_payload;
+       struct lttng_payload buffer;
+       enum lttng_map_status map_status;
+       const char *kv_from_payload_key, *key = "ma_clé";
+       int64_t kv_from_payload_value, value = 133121;
+       int ret;
+
+       diag("Simple lttng_map_key_value_pair tests");
+
+       lttng_payload_init(&buffer);
+
+       kv = lttng_map_key_value_pair_create(key, value);
+       ok(kv, "Key-value pair created");
+
+       /* Test incr value action serialization */
+       ret = lttng_map_key_value_pair_serialize(kv, &buffer);
+       ok(ret == 0, "Key-value pair serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(&buffer, 0, -1);
+
+               (void) lttng_map_key_value_pair_create_from_payload(
+                               &view, &kv_from_payload);
+       }
+       ok(kv_from_payload, "Key-value pair created from payload is non-null");
+
+       map_status = lttng_map_key_value_pair_get_key(kv_from_payload,
+                       &kv_from_payload_key);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Key-value pair 1 key");
+       ok(strcmp(kv_from_payload_key, key) == 0, "Key-value pair from payload has correct key");
+
+       map_status = lttng_map_key_value_pair_get_value(kv_from_payload,
+                       &kv_from_payload_value);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Key-value pair 1 value");
+       ok(kv_from_payload_value == value, "Key-value pair from payload has correct value");
+
+       lttng_payload_reset(&buffer);
+       lttng_map_key_value_pair_destroy(kv);
+       lttng_map_key_value_pair_destroy(kv_from_payload);
+}
+
+static
+void test_map_key_value_pair_list_serialize_deserialize(void)
+{
+       struct lttng_map_key_value_pair *kv;
+       const struct lttng_map_key_value_pair *kv_from_payload = NULL;
+
+       struct lttng_map_key_value_pair_list *kv_pair_list;
+       struct lttng_map_key_value_pair_list *kv_pair_list_from_payload;
+
+       struct lttng_payload buffer;
+       enum lttng_map_status map_status;
+       const char *kv_from_payload_key, *key1 = "ma_clé", *key2 = "autre_clé";
+       int64_t kv_from_payload_value, value1 = 123456, value2 = 98765;
+       enum lttng_map_key_value_pair_list_type list_type =
+                       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID;
+       uint64_t identifier = 3192112;
+       bool summed_all_cpus = true;
+       unsigned int kv_count;
+       int ret;
+
+       diag("Simple lttng_map_key_value_pair_list tests");
+
+       lttng_payload_init(&buffer);
+
+       kv_pair_list = lttng_map_key_value_pair_list_create(list_type,
+                       summed_all_cpus);
+       ok(kv_pair_list, "Key-value pair_list list created");
+
+       map_status = lttng_map_key_value_pair_list_set_identifier(kv_pair_list, 
+                       identifier);
+       ok(kv_pair_list, "Key-value set identifier");
+
+       kv = lttng_map_key_value_pair_create(key1, value1);
+       ok(kv, "Key-value pair 1 created");
+
+       map_status = lttng_map_key_value_pair_list_append_key_value(kv_pair_list, kv);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Key value 1 appended to list");
+
+       kv = lttng_map_key_value_pair_create(key2, value2);
+       ok(kv, "Key-value pair 2 created");
+
+       map_status = lttng_map_key_value_pair_list_append_key_value(kv_pair_list, kv);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Key value 2 appended to list");
+
+       /* Test incr value action serialization */
+       ret = lttng_map_key_value_pair_list_serialize(kv_pair_list, &buffer);
+       ok(ret == 0, "Key-value pair_list list serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(&buffer, 0, -1);
+
+               (void) lttng_map_key_value_pair_list_create_from_payload(
+                               &view, &kv_pair_list_from_payload);
+       }
+       ok(kv_pair_list_from_payload, "Key-value pair list created from payload is non-null");
+
+       ok(lttng_map_key_value_pair_list_get_summed_all_cpu(kv_pair_list_from_payload) == summed_all_cpus,
+                       "Got the expected summed all cpu state");
+
+       ok(lttng_map_key_value_pair_list_get_type(kv_pair_list_from_payload) == list_type,
+                       "Got the expected list type");
+       ok(lttng_map_key_value_pair_list_get_identifer(kv_pair_list_from_payload) == identifier,
+                       "Got the expected list identifier");
+
+       map_status = lttng_map_key_value_pair_list_get_count(
+                       kv_pair_list_from_payload, &kv_count);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Got key value pair count");
+       ok(kv_count == 2, "Got the right key value pair count");
+
+       kv_from_payload = lttng_map_key_value_pair_list_get_at_index(
+                       kv_pair_list_from_payload, 0);
+       ok(kv_from_payload, "Key-value pair 1 created from payload");
+
+       map_status = lttng_map_key_value_pair_get_key(kv_from_payload,
+                       &kv_from_payload_key);
+       ok(strcmp(kv_from_payload_key, key1) == 0, "Key-value pair 1 from payload has correct key");
+
+       map_status = lttng_map_key_value_pair_get_value(kv_from_payload,
+                       &kv_from_payload_value);
+       ok(kv_from_payload_value == value1, "Key-value pair 1 from payload has correct value");
+
+       kv_from_payload = lttng_map_key_value_pair_list_get_at_index(
+                       kv_pair_list_from_payload, 1);
+       ok(kv_from_payload, "Key-value pair 2 created from payload");
+
+       map_status = lttng_map_key_value_pair_get_key(kv_from_payload,
+                       &kv_from_payload_key);
+       ok(strcmp(kv_from_payload_key, key2) == 0, "Key-value pair 2 from payload has correct key");
+
+       map_status = lttng_map_key_value_pair_get_value(kv_from_payload,
+                       &kv_from_payload_value);
+       ok(kv_from_payload_value == value2, "Key-value pair 2 from payload has correct value");
+
+       lttng_payload_reset(&buffer);
+       lttng_map_key_value_pair_list_destroy(kv_pair_list);
+       lttng_map_key_value_pair_list_destroy(kv_pair_list_from_payload);
+}
+
+static
+void test_map_content_serialize_deserialize(void)
+{
+       struct lttng_map_content *map_content, *map_content_from_payload;
+       enum lttng_map_status map_status;
+       struct lttng_payload buffer;
+       struct lttng_map_key_value_pair *kv1, *kv2;
+       const char *key1 = "ma_clé", *key2 = "autre_clé";
+       uint64_t value1 = 123456, value2 = 98765;
+       enum lttng_map_key_value_pair_list_type list_type1 =
+                       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID;
+       enum lttng_map_key_value_pair_list_type list_type2 =
+                       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID;
+       enum lttng_map_key_value_pair_list_type list_type3 =
+                       LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID_AGGREGATED;
+       uint64_t id1 = 958323, id2 = 121942;
+       struct lttng_map_key_value_pair_list *kv_pair_list1, *kv_pair_list2, *kv_pair_list3;
+       const struct lttng_map_key_value_pair_list *kv_pair_list1_from_payload;
+       const struct lttng_map_key_value_pair_list *kv_pair_list2_from_payload;
+       const struct lttng_map_key_value_pair_list *kv_pair_list3_from_payload;
+       unsigned int list_count;
+       enum lttng_buffer_type buffer_type = LTTNG_BUFFER_PER_UID;
+       int ret;
+
+       diag("Simple lttng_map_content tests");
+
+       lttng_payload_init(&buffer);
+
+       kv_pair_list1 = lttng_map_key_value_pair_list_create(list_type1, true);
+       map_status = lttng_map_key_value_pair_list_set_identifier(kv_pair_list1, id1);
+
+       kv_pair_list2 = lttng_map_key_value_pair_list_create(list_type2, false);
+       map_status = lttng_map_key_value_pair_list_set_identifier(kv_pair_list2, id2);
+
+       kv_pair_list3 = lttng_map_key_value_pair_list_create(list_type3, true);
+
+       kv1 = lttng_map_key_value_pair_create(key1, value1);
+       map_status = lttng_map_key_value_pair_list_append_key_value(kv_pair_list1, kv1);
+
+       kv2 = lttng_map_key_value_pair_create(key2, value2);
+       map_status = lttng_map_key_value_pair_list_append_key_value(kv_pair_list2, kv2);
+
+       map_content = lttng_map_content_create(buffer_type);
+
+       map_status = lttng_map_content_append_key_value_list(map_content, kv_pair_list1);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Key value list 1 appended to map_content");
+
+       map_status = lttng_map_content_append_key_value_list(map_content, kv_pair_list2);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Key value list 2 appended to map_content");
+
+       map_status = lttng_map_content_append_key_value_list(map_content, kv_pair_list3);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Key value list 3 appended to map_content");
+
+       ret = lttng_map_content_serialize(map_content, &buffer);
+       ok(ret == 0, "Map list serialized");
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(&buffer, 0, -1);
+               (void) lttng_map_content_create_from_payload(
+                               &view, &map_content_from_payload);
+       }
+
+       ok(map_content, "map content created from payload is non-null");
+       map_status = lttng_map_content_get_count(map_content_from_payload, &list_count);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Got key value pair count");
+       ok(list_count == 3, "Got the expected key-value list count");
+
+       ok(lttng_map_content_get_buffer_type(map_content_from_payload) == buffer_type,
+               "Got the expected buffer type");
+
+       kv_pair_list1_from_payload = lttng_map_content_get_at_index(map_content_from_payload, 0);
+       ok(kv_pair_list1_from_payload, "Key-value pair list created from payload is non-null");
+
+       ok(lttng_map_key_value_pair_list_get_type(kv_pair_list1_from_payload) == list_type1,
+                       "Got the expected list type");
+
+       ok(lttng_map_key_value_pair_list_get_identifer(kv_pair_list1_from_payload) == id1,
+                       "Got the expected list identifier");
+
+       kv_pair_list2_from_payload = lttng_map_content_get_at_index(map_content_from_payload, 1);
+       ok(kv_pair_list2_from_payload, "Key-value pair list created from payload is non-null");
+
+       ok(lttng_map_key_value_pair_list_get_type(kv_pair_list2_from_payload) == list_type2,
+                       "Got the expected list type");
+
+       ok(lttng_map_key_value_pair_list_get_identifer(kv_pair_list2_from_payload) == id2,
+                       "Got the expected list identifier");
+
+       kv_pair_list3_from_payload = lttng_map_content_get_at_index(map_content_from_payload, 2);
+       ok(kv_pair_list3_from_payload, "Key-value pair list created from payload is non-null");
+
+       ok(lttng_map_key_value_pair_list_get_type(kv_pair_list3_from_payload) == list_type3,
+                       "Got the expected list type");
+
+       lttng_payload_reset(&buffer);
+       lttng_map_content_destroy(map_content);
+       lttng_map_content_destroy(map_content_from_payload);
+}
+
+static
+void test_map(void)
+{
+       int ret;
+       struct lttng_payload buffer;
+       struct lttng_map *map, *map_from_payload = NULL;
+       enum lttng_map_status map_status;
+       const char *map_name = "map_name", *map_name_from_payload;
+       unsigned int dimension_count = 1;
+       uint64_t first_dim_size = 423;
+       uint64_t dimension_sizes[1] = {first_dim_size};
+       enum lttng_domain_type domain = LTTNG_DOMAIN_UST;
+       enum lttng_buffer_type buffer_type = LTTNG_BUFFER_PER_UID;
+       enum lttng_map_bitness bitness = LTTNG_MAP_BITNESS_32BITS;
+       enum lttng_map_boundary_policy boundary_policy = LTTNG_MAP_BOUNDARY_POLICY_OVERFLOW;
+       bool coalesce_hits = true;
+
+
+       diag("Simple lttng_map tests");
+       lttng_payload_init(&buffer);
+
+       map_status = lttng_map_create(map_name, dimension_count,
+                       dimension_sizes, domain, buffer_type, bitness,
+                       boundary_policy, coalesce_hits, &map);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Created map");
+
+       lttng_map_set_is_enabled(map, true);
+
+       ret = lttng_map_serialize(map, &buffer);
+       ok(ret == 0, "Map serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(&buffer, 0, -1);
+               (void) lttng_map_create_from_payload(
+                               &view, &map_from_payload);
+       }
+       ok(map_from_payload, "Map created from payload");
+
+       ok(lttng_map_get_dimension_count(map_from_payload) == dimension_count,
+                       "Got the expected dimension count from payload");
+
+       ok(lttng_map_get_is_enabled(map_from_payload) == 1,
+                       "Got the expected enabled state from payload");
+
+       ok(lttng_map_get_bitness(map_from_payload) == bitness,
+                       "Got the expected bitness from payload");
+
+       ok(lttng_map_get_domain(map_from_payload) == domain,
+                       "Got the expected domain from payload");
+
+       ok(lttng_map_get_buffer_type(map_from_payload) == buffer_type,
+                       "Got the expected buffer type from payload");
+
+       ok(lttng_map_get_boundary_policy(map_from_payload) == boundary_policy,
+                       "Got the expected boundary policy from payload");
+
+       ok(lttng_map_get_coalesce_hits(map_from_payload) == coalesce_hits,
+                       "Got the expected coalesce hits value from payload");
+
+       map_status = lttng_map_get_name(map_from_payload, &map_name_from_payload);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Got map name from payload");
+       ok(strcmp(map_name_from_payload, map_name) == 0,
+                       "Got the expected map name from payload");
+
+       lttng_map_destroy(map);
+       lttng_map_destroy(map_from_payload);
+       lttng_payload_reset(&buffer);
+}
+
+static
+void test_map_list(void)
+{
+       int ret;
+       struct lttng_payload buffer;
+       enum lttng_map_status map_status;
+       struct lttng_map *map1, *map2;
+       const struct lttng_map *map1_from_payload = NULL, *map2_from_payload = NULL;
+       struct lttng_map_list *map_list, *map_list_from_payload = NULL;
+       const char *map1_name = "map_name_1", *map1_name_from_payload;
+       const char *map2_name = "map_name_2", *map2_name_from_payload;
+       unsigned int dimension_count = 1, map_count = 0;
+       uint64_t first_dim_size = 423;
+       uint64_t dimension_sizes[1] = {first_dim_size};
+       enum lttng_domain_type domain = LTTNG_DOMAIN_KERNEL;
+       enum lttng_buffer_type buffer_type1 = LTTNG_BUFFER_PER_PID, buffer_type2 = LTTNG_BUFFER_PER_UID;
+       enum lttng_map_bitness bitness = LTTNG_MAP_BITNESS_64BITS;
+       enum lttng_map_boundary_policy boundary_policy = LTTNG_MAP_BOUNDARY_POLICY_OVERFLOW;
+       bool coalesce_hits = false;
+
+       diag("Simple lttng_map_list tests");
+
+       lttng_payload_init(&buffer);
+
+       map_status = lttng_map_create(map1_name, dimension_count,
+                       dimension_sizes, domain, buffer_type1, bitness,
+                       boundary_policy, coalesce_hits, &map1);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Created map 1");
+       lttng_map_set_is_enabled(map1, true);
+
+       map_status = lttng_map_create(map2_name, dimension_count,
+                       dimension_sizes, domain, buffer_type2, bitness,
+                       boundary_policy, coalesce_hits, &map2);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Created map 2");
+       lttng_map_set_is_enabled(map2, true);
+
+       map_list = lttng_map_list_create();
+       ok(map_list, "Map list created");
+
+       map_status = lttng_map_list_add(map_list, map1);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Map 1 added to map list");
+
+       map_status = lttng_map_list_add(map_list, map2);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Map 1 added to map list");
+
+       ret = lttng_map_list_serialize(map_list, &buffer);
+       ok(ret == 0, "Map list serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(&buffer, 0, -1);
+               (void) lttng_map_list_create_from_payload(
+                               &view, &map_list_from_payload);
+       }
+
+       map_status = lttng_map_list_get_count(map_list, &map_count);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Got map count from payload");
+       ok(map_count == 2, "Got the right map count from payload");
+
+       map1_from_payload = lttng_map_list_get_at_index(map_list, 0);
+       ok(map1_from_payload, "Got first map from payload");
+       map_status = lttng_map_get_name(map1_from_payload, &map1_name_from_payload);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Got map 1 name from payload");
+       ok(strcmp(map1_name_from_payload, map1_name) == 0,
+                       "Got right map 1 name from payload");
+       ok(lttng_map_get_is_enabled(map1_from_payload) == 1,
+                       "Got right map 1 enabled state from payload");
+
+       map2_from_payload = lttng_map_list_get_at_index(map_list, 1);
+       ok(map2_from_payload, "Got first map from payload");
+       map_status = lttng_map_get_name(map2_from_payload, &map2_name_from_payload);
+       ok(map_status == LTTNG_MAP_STATUS_OK, "Got map 2 name from payload");
+       ok(strcmp(map2_name_from_payload, map2_name) == 0,
+                       "Got right map 2 name from payload");
+       ok(lttng_map_get_is_enabled(map2_from_payload) == 1,
+                       "Got right map 2 enabled state from payload");
+
+       lttng_map_destroy(map1);
+       lttng_map_destroy(map2);
+       lttng_map_list_destroy(map_list);
+       lttng_map_list_destroy(map_list_from_payload);
+       lttng_payload_reset(&buffer);
+}
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+
+       test_map();
+       test_map_list();
+       test_map_key_value_pair_serialize_deserialize();
+       test_map_key_value_pair_list_serialize_deserialize();
+       test_map_content_serialize_deserialize();
+
+       return exit_status();
+}
diff --git a/tests/unit/test_map_key.c b/tests/unit/test_map_key.c
new file mode 100644 (file)
index 0000000..bdc1562
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * test_map_key.c
+ *
+ * Unit tests for the map-key API.
+ *
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <lttng/map-key-internal.h>
+
+#define NUM_TESTS 38
+
+const char *key_str1 = "simple_string";
+const char *key_str2 = "${EVENT_NAME}";
+const char *key_str3 = "foo_${EVENT_NAME}";
+const char *key_str4 = "foo_${EVENT_NAME}_bar";
+const char *key_str5 = "${EVENT_NAME}_bar_${EVENT_NAME}";
+const char *key_str6 = "foo_${NON_EXISTING_VAR}";
+const char *key_str7 = "foo_${}";
+const char *key_str8 = "foo_${PROVIDER_NAME}";
+
+static
+void test_map_key(void)
+{
+       struct lttng_map_key *key;
+       enum lttng_map_key_status status;
+       const struct lttng_map_key_token *token;
+       const struct lttng_map_key_token_variable *var_token;
+       unsigned int count;
+
+       key = lttng_map_key_parse_from_string(key_str6);
+       ok(!key, "Failed to create key from \"%s\" as expected", key_str6);
+
+       key = lttng_map_key_parse_from_string(key_str7);
+       ok(!key, "Failed to create key from \"%s\" as expected", key_str7);
+
+       key = lttng_map_key_parse_from_string(key_str1);
+       ok(key, "Created key from \"%s\"", key_str1);
+       status = lttng_map_key_get_token_count(key, &count);
+       ok(status == LTTNG_MAP_KEY_STATUS_OK, "Got count for key_str1");
+       ok(count == 1, "Got correct token count for key_str1");
+       token = lttng_map_key_get_token_at_index(key, 0);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING, "First token of string type");
+       lttng_map_key_destroy(key);
+
+       key = lttng_map_key_parse_from_string(key_str2);
+       ok(key, "Created key from \"%s\"", key_str2);
+       status = lttng_map_key_get_token_count(key, &count);
+       ok(status == LTTNG_MAP_KEY_STATUS_OK, "Got count for key_str2");
+       ok(count == 1, "Got correct token count for key_str2");
+       token = lttng_map_key_get_token_at_index(key, 0);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE, "First token of variable type");
+       var_token = (typeof(var_token)) token;
+       ok(var_token->type == LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME, "EVENT_NAME variable type");
+       lttng_map_key_destroy(key);
+
+       key = lttng_map_key_parse_from_string(key_str3);
+       ok(key, "Created key from \"%s\"", key_str3);
+       status = lttng_map_key_get_token_count(key, &count);
+       ok(status == LTTNG_MAP_KEY_STATUS_OK, "Got count for key_str3");
+       ok(count == 2, "Got correct token count for key_str3");
+       token = lttng_map_key_get_token_at_index(key, 0);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING, "First token of string type");
+       token = lttng_map_key_get_token_at_index(key, 1);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE, "Second token of variable type");
+       var_token = (typeof(var_token)) token;
+       ok(var_token->type == LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME, "EVENT_NAME variable type");
+       lttng_map_key_destroy(key);
+
+       key = lttng_map_key_parse_from_string(key_str4);
+       ok(key, "Created key from \"%s\"", key_str4);
+       status = lttng_map_key_get_token_count(key, &count);
+       ok(status == LTTNG_MAP_KEY_STATUS_OK, "Got count for key_str4");
+       ok(count == 3, "Got correct token count for key_str4");
+       token = lttng_map_key_get_token_at_index(key, 0);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING, "First token of string type");
+       token = lttng_map_key_get_token_at_index(key, 1);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE, "Second token of variable type");
+       var_token = (typeof(var_token)) token;
+       ok(var_token->type == LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME, "EVENT_NAME variable type");
+       token = lttng_map_key_get_token_at_index(key, 2);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING, "Third token of string type");
+       lttng_map_key_destroy(key);
+
+       key = lttng_map_key_parse_from_string(key_str5);
+       ok(key, "Created key from \"%s\"", key_str5);
+       status = lttng_map_key_get_token_count(key, &count);
+       ok(status == LTTNG_MAP_KEY_STATUS_OK, "Got count for key_str5");
+       ok(count == 3, "Got correct token count for key_str5");
+       token = lttng_map_key_get_token_at_index(key, 0);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE, "First token of variable type");
+       var_token = (typeof(var_token)) token;
+       ok(var_token->type == LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME, "EVENT_NAME variable type");
+       token = lttng_map_key_get_token_at_index(key, 1);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING, "Second token of string type");
+       token = lttng_map_key_get_token_at_index(key, 2);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE, "Third token of variable type");
+       var_token = (typeof(var_token)) token;
+       ok(var_token->type == LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME, "EVENT_NAME variable type");
+       lttng_map_key_destroy(key);
+
+       key = lttng_map_key_parse_from_string(key_str8);
+       ok(key, "Created key from \"%s\"", key_str8);
+       status = lttng_map_key_get_token_count(key, &count);
+       ok(status == LTTNG_MAP_KEY_STATUS_OK, "Got count for key_str8");
+       ok(count == 2, "Got correct token count for key_str8");
+       token = lttng_map_key_get_token_at_index(key, 0);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING, "First token of string type");
+       token = lttng_map_key_get_token_at_index(key, 1);
+       ok(token->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE, "Second token of variable type");
+       var_token = (typeof(var_token)) token;
+       ok(var_token->type == LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME, "PROVIDER_NAME variable type");
+       lttng_map_key_destroy(key);
+}
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+       test_map_key();
+       return exit_status();
+}
diff --git a/tests/unit/test_map_query.c b/tests/unit/test_map_query.c
new file mode 100644 (file)
index 0000000..76dd8b6
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * test_map_query.c
+ *
+ * Unit tests for the map query API.
+ *
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <lttng/map/map-query-internal.h>
+
+#include <common/dynamic-buffer.h>
+#include <common/buffer-view.h>
+#include <common/payload.h>
+
+#define NUM_TESTS 56
+
+static
+void test_map_query_key_filter_all_cpus_all_uids_64_no_sum(void)
+{
+       int ret;
+       struct lttng_payload buffer;
+       struct lttng_map_query *query, *query_from_payload = NULL;
+       const char *filter = "pitarifique_key";
+       const char *filter_from_payload;
+       enum lttng_map_query_status status;
+
+       enum lttng_map_query_config_cpu config_cpu =
+                       LTTNG_MAP_QUERY_CONFIG_CPU_ALL;
+       enum lttng_map_query_config_buffer config_buffer =
+                       LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_ALL;
+       enum lttng_map_query_config_app_bitness config_bitness =
+                       LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_ALL;
+
+       diag("Map query, all cpus, all uids, 64bits, no sum");
+       lttng_payload_init(&buffer);
+
+       query = lttng_map_query_create(config_cpu, config_buffer,
+                       config_bitness);
+       ok(query, "Map query created succesfully");
+
+       status = lttng_map_query_add_key_filter(query, filter);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Key filter created succesfully");
+
+       /* Add a cpu manually with a _CONFIG_CPU_ALL should fail. */
+       status = lttng_map_query_add_cpu(query, 121);
+       ok(status == LTTNG_MAP_QUERY_STATUS_INVALID, "Adding a cpu failed as expected");
+
+       /* Add a pid manually with a _CONFIG_BUFFER_UST_UID_ should fail. */
+       status = lttng_map_query_add_pid(query, 931214);
+       ok(status == LTTNG_MAP_QUERY_STATUS_INVALID, "Adding a PID of uid map query failed as expected");
+
+       ret = lttng_map_query_serialize(query, &buffer);
+       ok(ret == 0, "Map query serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(&buffer, 0, -1);
+               (void) lttng_map_query_create_from_payload(
+                               &view, &query_from_payload);
+       }
+
+       ok(query_from_payload, "Map query created from payload");
+
+       ok(lttng_map_query_get_config_app_bitness(query_from_payload) ==
+                       config_bitness, "Getting app bitness config from payload");
+
+       ok(lttng_map_query_get_config_buffer(query_from_payload) ==
+                       config_buffer, "Buffer config");
+
+       ok(lttng_map_query_get_config_cpu(query_from_payload) ==
+                       config_cpu, "CPU config");
+
+       ok(lttng_map_query_get_config_app_bitness(query_from_payload) ==
+                       config_bitness, "App bitness config");
+
+       status = lttng_map_query_get_key_filter(query_from_payload, &filter_from_payload);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Key filter");
+       ok(strcmp(filter_from_payload, filter) == 0, "Key filter");
+
+       lttng_map_query_destroy(query);
+       lttng_map_query_destroy(query_from_payload);
+       lttng_payload_reset(&buffer);
+}
+
+static
+void test_map_query_key_some_cpu_some_uid_summed_by_uid(void)
+{
+       int ret;
+       struct lttng_payload buffer;
+       struct lttng_map_query *query, *query_from_payload = NULL;
+       unsigned int cpu_count, uid_count;
+       bool sum_by_cpu = false, sum_by_uid = true;
+       uid_t uid1 = 12131, uid1_from_payload;
+       int cpu1 = 494581, cpu1_from_payload;
+       enum lttng_map_query_status status;
+
+       enum lttng_map_query_config_cpu config_cpu =
+                       LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET;
+       enum lttng_map_query_config_buffer config_buffer =
+                       LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_UID_SUBSET;
+       enum lttng_map_query_config_app_bitness config_bitness =
+                       LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_ALL;
+
+       diag("Map query some cpus, some uids, summed by uid");
+       lttng_payload_init(&buffer);
+
+       query = lttng_map_query_create(config_cpu, config_buffer,
+                       config_bitness);
+       ok(query, "Map query created succesfully");
+
+       status = lttng_map_query_set_sum_by_cpu(query, sum_by_cpu);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Setting sum-by-cpu option");
+
+       status = lttng_map_query_set_sum_by_uid(query, sum_by_uid);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Setting sum-by-uid option");
+
+       status = lttng_map_query_add_cpu(query, cpu1);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Adding a cpu %d", cpu1);
+
+       status = lttng_map_query_add_uid(query, uid1);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Adding a uid %d", uid1);
+
+       /* Add a pid manually with a _CONFIG_BUFFER_UST_UID_ should fail. */
+       status = lttng_map_query_add_pid(query, 931214);
+       ok(status == LTTNG_MAP_QUERY_STATUS_INVALID, "Adding a PID of uid map query failed as expected");
+
+       ret = lttng_map_query_serialize(query, &buffer);
+       ok(ret == 0, "Map query serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(&buffer, 0, -1);
+               (void) lttng_map_query_create_from_payload(
+                               &view, &query_from_payload);
+       }
+
+       ok(query_from_payload, "Map query created from payload");
+
+       ok(lttng_map_query_get_config_app_bitness(query_from_payload) ==
+                       config_bitness, "Getting app bitness config from payload");
+
+       ok(lttng_map_query_get_config_sum_by_cpu(query_from_payload) ==
+                       sum_by_cpu, "Getting sum-by-cpu config from payload");
+
+       ok(lttng_map_query_get_config_sum_by_uid(query_from_payload) ==
+                       sum_by_uid, "Getting sum-by-uid config from payload");
+
+       ok(lttng_map_query_get_config_buffer(query_from_payload) ==
+                       config_buffer, "Buffer config");
+
+       ok(lttng_map_query_get_config_cpu(query_from_payload) ==
+                       config_cpu, "CPU config");
+
+       ok(lttng_map_query_get_config_app_bitness(query_from_payload) ==
+                       config_bitness, "App bitness config");
+
+       status = lttng_map_query_get_cpu_count(query, &cpu_count);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Getting cpu count");
+       ok(cpu_count == 1, "Getting cpu count");
+
+       status = lttng_map_query_get_cpu_at_index(query, 0, &cpu1_from_payload);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Getting cpu count");
+       ok(cpu1_from_payload == cpu1, "Getting cpu value");
+
+       status = lttng_map_query_get_uid_count(query, &uid_count);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Getting uid count");
+       ok(uid_count == 1, "Getting uid count");
+
+       status = lttng_map_query_get_uid_at_index(query, 0, &uid1_from_payload);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Getting uid count");
+       ok(uid1_from_payload == uid1, "Getting uid value");
+
+       lttng_map_query_destroy(query);
+       lttng_map_query_destroy(query_from_payload);
+       lttng_payload_reset(&buffer);
+}
+
+static
+void test_map_query_key_one_cpu_some_pid_summed_by_cpu(void)
+{
+       int ret;
+       struct lttng_payload buffer;
+       struct lttng_map_query *query, *query_from_payload = NULL;
+       unsigned int cpu_count, pid_count;
+       pid_t pid1 = 12131, pid1_from_payload;
+       int cpu1 = 494581, cpu1_from_payload;
+       bool sum_by_cpu = true, sum_by_pid = false;
+       enum lttng_map_query_status status;
+
+       enum lttng_map_query_config_cpu config_cpu =
+                       LTTNG_MAP_QUERY_CONFIG_CPU_SUBSET;
+       enum lttng_map_query_config_buffer config_buffer =
+                       LTTNG_MAP_QUERY_CONFIG_BUFFER_UST_PID_SUBSET;
+       enum lttng_map_query_config_app_bitness config_bitness =
+                       LTTNG_MAP_QUERY_CONFIG_APP_BITNESS_ALL;
+
+       diag("Map query one cpu, some pid, summed by cpu");
+       lttng_payload_init(&buffer);
+
+       query = lttng_map_query_create(config_cpu, config_buffer,
+                       config_bitness);
+       ok(query, "Map query created succesfully");
+
+       status = lttng_map_query_set_sum_by_cpu(query, sum_by_cpu);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Setting sum-by-cpu option");
+
+       status = lttng_map_query_set_sum_by_pid(query, sum_by_pid);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Setting sum-by-pid option");
+
+       status = lttng_map_query_add_cpu(query, cpu1);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Adding a cpu %d", cpu1);
+
+       status = lttng_map_query_add_pid(query, pid1);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Adding a pid %d", pid1);
+
+       /* Add a pid manually with a _CONFIG_BUFFER_UST_PID_ should fail. */
+       status = lttng_map_query_add_uid(query, 931214);
+       ok(status == LTTNG_MAP_QUERY_STATUS_INVALID, "Adding a UID of pid map query failed as expected");
+
+       ret = lttng_map_query_serialize(query, &buffer);
+       ok(ret == 0, "Map query serialized");
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(&buffer, 0, -1);
+               (void) lttng_map_query_create_from_payload(
+                               &view, &query_from_payload);
+       }
+
+       ok(query_from_payload, "Map query created from payload");
+
+       ok(lttng_map_query_get_config_app_bitness(query_from_payload) ==
+                       config_bitness, "Getting app bitness config from payload");
+
+       ok(lttng_map_query_get_config_sum_by_cpu(query_from_payload) ==
+                       sum_by_cpu, "Getting sum-by-cpu config from payload");
+
+       ok(lttng_map_query_get_config_sum_by_pid(query_from_payload) ==
+                       sum_by_pid, "Getting sum-by-pid config from payload");
+
+       ok(lttng_map_query_get_config_buffer(query_from_payload) ==
+                       config_buffer, "Getting buffer config from payload");
+
+       ok(lttng_map_query_get_config_cpu(query_from_payload) ==
+                       config_cpu, "Getting CPU config from payload");
+
+       ok(lttng_map_query_get_config_app_bitness(query_from_payload) ==
+                       config_bitness, "App bitness config from payload");
+
+       status = lttng_map_query_get_cpu_count(query, &cpu_count);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Getting cpu count from payload");
+       ok(cpu_count == 1, "Getting cpu count from payload");
+
+       status = lttng_map_query_get_cpu_at_index(query, 0, &cpu1_from_payload);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Getting cpu count from payload");
+       ok(cpu1_from_payload == cpu1, "Getting cpu value from payload");
+
+       status = lttng_map_query_get_pid_count(query, &pid_count);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Getting pid count from payload");
+       ok(pid_count == 1, "Getting pid count from payload");
+
+       status = lttng_map_query_get_pid_at_index(query, 0, &pid1_from_payload);
+       ok(status == LTTNG_MAP_QUERY_STATUS_OK, "Getting pid count from payload");
+       ok(pid1_from_payload == pid1, "Getting pid value from payload");
+
+       lttng_map_query_destroy(query);
+       lttng_map_query_destroy(query_from_payload);
+       lttng_payload_reset(&buffer);
+}
+
+int main(int argc, const char *argv[])
+{
+       plan_tests(NUM_TESTS);
+
+       test_map_query_key_filter_all_cpus_all_uids_64_no_sum();
+       test_map_query_key_some_cpu_some_uid_summed_by_uid();
+       test_map_query_key_one_cpu_some_pid_summed_by_cpu();
+
+       return exit_status();
+}
index ec61ffbad60285d16d2c0e789dd52ec9ea9765ea..330d49e59d7cc61e89257ad79ab0e9014e154e27 100644 (file)
@@ -125,7 +125,8 @@ static void test_create_ust_event(void)
        ev.type = LTTNG_EVENT_TRACEPOINT;
        ev.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
 
-       ret = trace_ust_create_event(&ev, NULL, NULL, NULL, false, &event);
+       ret = trace_ust_create_event(0, ev.name, NULL, ev.type, ev.loglevel_type,
+                       ev.loglevel, NULL, NULL, NULL, false, &event);
 
        ok(ret == LTTNG_OK, "Create UST event");
 
@@ -181,7 +182,8 @@ static void test_create_ust_event_exclusion(void)
        strncpy(LTTNG_EVENT_EXCLUSION_NAME_AT(exclusion, 1), random_name,
                LTTNG_SYMBOL_NAME_LEN);
 
-       ret = trace_ust_create_event(&ev, NULL, NULL, exclusion, false, &event);
+       ret = trace_ust_create_event(0, ev.name, NULL, ev.type, ev.loglevel_type,
+                       ev.loglevel, NULL, NULL, exclusion, false, &event);
        exclusion = NULL;
 
        ok(ret != LTTNG_OK, "Create UST event with identical exclusion names fails");
@@ -219,7 +221,8 @@ static void test_create_ust_event_exclusion(void)
        strncpy(LTTNG_EVENT_EXCLUSION_NAME_AT(exclusion_copy, 1),
                LTTNG_EVENT_EXCLUSION_NAME_AT(exclusion, 1), LTTNG_SYMBOL_NAME_LEN);
 
-       ret = trace_ust_create_event(&ev, NULL, NULL, exclusion, false, &event);
+       ret = trace_ust_create_event(0, ev.name, NULL, ev.type, ev.loglevel_type,
+                       ev.loglevel, NULL, NULL, exclusion, false, &event);
        exclusion = NULL;
        ok(ret == LTTNG_OK, "Create UST event with different exclusion names");
 
index 9ab65093307513666b76fe5100919d163b35ded8..1a2882f99780bf4ed865c4be2842199763a7c59e 100644 (file)
@@ -93,7 +93,6 @@ int main(int argc, char **argv)
        if (argc != 4) {
                fprintf(stderr, "Error: Missing argument\n");
                fprintf(stderr, "USAGE: %s PATH_WAIT_FILE PATH1_TO_OPEN PATH2_TO_OPEN\n", argv[0]);
-               fprintf(stderr, "USAGE: %s PATH_WAIT_FILE\n", argv[0]);
                ret = -1;
                goto error;
        }
index a1e142487024b8a6966321a8aba87e04f4a685eb..de2cdc324749c58dd1771198e6d92b39d156402d 100644 (file)
@@ -325,6 +325,28 @@ function lttng_disable_kernel_syscall_fail()
        lttng_disable_kernel_syscall 1 "$@"
 }
 
+function lttng_enable_kernel_function_event ()
+{
+       local expected_to_fail="$1"
+       local sess_name="$2"
+       local target="$3"
+       local event_name="$4"
+
+       "$TESTDIR/../src/bin/lttng/$LTTNG_BIN" enable-event --kernel --function="$target" "$event_name" -s "$sess_name" > "$OUTPUT_DEST" 2> "$ERROR_OUTPUT_DEST"
+       ret=$?
+       if [[ $expected_to_fail -eq "1" ]]; then
+               test $ret -ne "0"
+               ok $? "Enable kernel function event for session $sess_name failed as expected"
+       else
+               ok $ret "Enable kernel function event for session $sess_name"
+       fi
+}
+
+function lttng_enable_kernel_function_event_ok ()
+{
+       lttng_enable_kernel_function_event 0 "$@"
+}
+
 function lttng_enable_kernel_userspace_probe_event ()
 {
        local expected_to_fail="$1"
@@ -543,6 +565,10 @@ function start_lttng_sessiond_opt()
        local withtap=$1
        local load_path=$2
 
+       # The rest of the arguments will be passed directly to lttng-sessiond.
+       shift
+       shift
+
        local env_vars=""
        local consumerd=""
 
@@ -587,10 +613,10 @@ function start_lttng_sessiond_opt()
                # Have a load path ?
                if [ -n "$load_path" ]; then
                        # shellcheck disable=SC2086
-                       env $env_vars --load "$load_path" --background "$consumerd"
+                       env $env_vars --load "$load_path" --background "$consumerd" "$@"
                else
                        # shellcheck disable=SC2086
-                       env $env_vars --background "$consumerd"
+                       env $env_vars --background "$consumerd" "$@"
                fi
                #$DIR/../src/bin/lttng-sessiond/$SESSIOND_BIN --background --consumerd32-path="$DIR/../src/bin/lttng-consumerd/lttng-consumerd" --consumerd64-path="$DIR/../src/bin/lttng-consumerd/lttng-consumerd" --verbose-consumer >>/tmp/sessiond.log 2>&1
                status=$?
@@ -1491,7 +1517,8 @@ function lttng_load()
        local expected_to_fail=$1
        local opts=$2
 
-       $TESTDIR/../src/bin/lttng/$LTTNG_BIN load $opts 1> $OUTPUT_DEST 2> $ERROR_OUTPUT_DEST
+       diag "$TESTDIR/../src/bin/lttng/$LTTNG_BIN load $opts"
+       $TESTDIR/../src/bin/lttng/$LTTNG_BIN load $opts
        ret=$?
        if [[ $expected_to_fail -eq "1" ]]; then
                test $ret -ne "0"
@@ -2104,3 +2131,85 @@ function lttng_clear_all ()
        $TESTDIR/../src/bin/lttng/$LTTNG_BIN clear --all 1> $OUTPUT_DEST 2> $ERROR_OUTPUT_DEST
        ok $? "Clear all lttng sessions"
 }
+
+function lttng_add_trigger()
+{
+       local expected_to_fail="$1"
+       local trigger_name="$2"
+       shift 2
+
+       $TESTDIR/../src/bin/lttng/$LTTNG_BIN add-trigger --id "$trigger_name" "$@" 1> /dev/null 2> /dev/null
+       ret=$?
+       if [[ $expected_to_fail -eq "1" ]]; then
+               test "$ret" -ne "0"
+               ok $? "Add trigger $trigger_name failed as expected"
+       else
+               ok $ret "Add trigger $trigger_name"
+       fi
+}
+
+function lttng_remove_trigger()
+{
+       local expected_to_fail="$1"
+       local trigger_name="$2"
+
+       $TESTDIR/../src/bin/lttng/$LTTNG_BIN remove-trigger "$trigger_name" 1> /dev/null 2> /dev/null
+       ret=$?
+       if [[ $expected_to_fail -eq "1" ]]; then
+               test "$ret" -ne "0"
+               ok $? "Remove trigger $trigger_name failed as expected"
+       else
+               ok $ret "Remove trigger $trigger_name"
+       fi
+}
+
+function lttng_add_trigger_ok()
+{
+       lttng_add_trigger 0 "$@"
+}
+
+function lttng_add_trigger_fail()
+{
+       lttng_add_trigger 1 "$@"
+}
+
+function lttng_remove_trigger_ok()
+{
+       lttng_remove_trigger 0 "$@"
+}
+
+function lttng_add_map()
+{
+       local expected_to_fail="$1"
+       local map_name="$2"
+       local session_name="$3"
+       local domain="$4"
+       local bitness="$5"
+       local buf_option="$6"
+       local coalesced="$7"
+
+       local args=("$domain" "--bitness=$bitness" "$buf_option" "--session=$session_name" "$map_name")
+       if [ -n "$buf_option" ]
+       then
+               args+=("$buf_option")
+       fi
+
+       if [ -n "$coalesced" ]
+       then
+               args+=("$coalesced")
+       fi
+
+       "$FULL_LTTNG_BIN" add-map ${args[@]} > /dev/null
+       ret=$?
+       if [[ $expected_to_fail -eq "1" ]]; then
+               test "$ret" -ne "0"
+               ok $? "Map $domain --bitness $bitness creating failed as expected"
+       else
+               ok $ret "Map $domain --bitness $bitness created succesfully"
+       fi
+}
+
+function lttng_add_map_ok()
+{
+       lttng_add_map 0 "$@"
+}
This page took 0.482261 seconds and 5 git commands to generate.