Commit | Line | Data |
---|---|---|
ce5aef0b | 1 | /* |
c0c0989a | 2 | * SPDX-License-Identifier: LGPL-2.1-only |
ce5aef0b | 3 | * |
c0c0989a | 4 | * Copyright 2010-2012 (C) Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
e92f3e28 | 5 | * |
c0c0989a | 6 | * Holds LTTng probes registry. |
ce5aef0b MD |
7 | */ |
8 | ||
3fbec7dc | 9 | #define _LGPL_SOURCE |
8d8a24c8 MD |
10 | #include <string.h> |
11 | #include <errno.h> | |
12 | #include <urcu/list.h> | |
1f18504e | 13 | #include <urcu/hlist.h> |
4318ae1b | 14 | #include <lttng/ust-events.h> |
902e1379 | 15 | #include <lttng/tracepoint.h> |
8f51c684 | 16 | #include "common/tracepoint.h" |
a3bb4b27 | 17 | #include <assert.h> |
9d315d6d | 18 | #include "common/macros.h" |
48740cab | 19 | #include <ctype.h> |
ce5aef0b | 20 | |
7dd08bec | 21 | #include "lttng-tracer-core.h" |
e58e5ad5 | 22 | #include "common/jhash.h" |
36c52fff | 23 | #include "lib/lttng-ust/events.h" |
8165c8da MD |
24 | |
25 | /* | |
17dfb34b | 26 | * probe list is protected by ust_lock()/ust_unlock(). |
8165c8da | 27 | */ |
ac69b35b | 28 | static CDS_LIST_HEAD(_probe_list); |
e58095ef | 29 | |
6715d7d1 MD |
30 | /* |
31 | * List of probes registered by not yet processed. | |
32 | */ | |
33 | static CDS_LIST_HEAD(lazy_probe_init); | |
df854e41 | 34 | |
6715d7d1 MD |
35 | /* |
36 | * lazy_nesting counter ensures we don't trigger lazy probe registration | |
37 | * fixup while we are performing the fixup. It is protected by the ust | |
38 | * mutex. | |
39 | */ | |
40 | static int lazy_nesting; | |
df854e41 | 41 | |
f6173469 MD |
42 | static |
43 | int check_provider_version(const struct lttng_ust_probe_desc *desc) | |
44 | { | |
45 | /* | |
46 | * Check tracepoint provider version compatibility. | |
47 | */ | |
48 | if (desc->major <= LTTNG_UST_PROVIDER_MAJOR && | |
49 | desc->major >= LTTNG_UST_PROVIDER_MAJOR_OLDEST_COMPATIBLE) { | |
50 | DBG("Provider \"%s\" accepted, version %u.%u is compatible " | |
51 | "with LTTng UST provider version %u.%u.", | |
52 | desc->provider_name, desc->major, desc->minor, | |
53 | LTTNG_UST_PROVIDER_MAJOR, | |
54 | LTTNG_UST_PROVIDER_MINOR); | |
55 | if (desc->major < LTTNG_UST_PROVIDER_MAJOR) { | |
56 | DBG("However, some LTTng UST features might not be " | |
57 | "available for this provider unless it is " | |
58 | "recompiled against a more recent LTTng UST."); | |
59 | } | |
60 | return 1; /* accept */ | |
61 | } else { | |
62 | ERR("Provider \"%s\" rejected, version %u.%u is incompatible " | |
63 | "with LTTng UST provider version %u.%u. Please upgrade " | |
64 | "LTTng UST.", | |
65 | desc->provider_name, desc->major, desc->minor, | |
66 | LTTNG_UST_PROVIDER_MAJOR, | |
67 | LTTNG_UST_PROVIDER_MINOR); | |
68 | return 0; /* reject */ | |
69 | } | |
70 | } | |
71 | ||
6715d7d1 | 72 | /* |
5b4c6da4 | 73 | * Validate that each event within the probe provider refers to the |
f6173469 MD |
74 | * right probe, that the resulting name is not too long, and that the |
75 | * event class belongs to a provider with compatible version. | |
6715d7d1 | 76 | */ |
ce5aef0b | 77 | static |
4e48b5d2 | 78 | bool check_event_provider(const struct lttng_ust_probe_desc *probe_desc) |
ce5aef0b | 79 | { |
ce5aef0b | 80 | int i; |
5b4c6da4 MD |
81 | |
82 | for (i = 0; i < probe_desc->nr_events; i++) { | |
83 | const struct lttng_ust_event_desc *event_desc = probe_desc->event_desc[i]; | |
84 | ||
85 | if (event_desc->probe_desc != probe_desc) { | |
86 | ERR("Error registering probe provider '%s'. Event '%s:%s' refers to the wrong provider descriptor.", | |
87 | probe_desc->provider_name, probe_desc->provider_name, event_desc->event_name); | |
88 | return false; /* provider mismatch */ | |
89 | } | |
90 | if (!lttng_ust_validate_event_name(event_desc)) { | |
91 | ERR("Error registering probe provider '%s'. Event '%s:%s' name is too long.", | |
92 | probe_desc->provider_name, probe_desc->provider_name, event_desc->event_name); | |
93 | return false; /* provider mismatch */ | |
94 | } | |
f6173469 MD |
95 | if (!check_provider_version(event_desc->tp_class->probe_desc)) { |
96 | ERR("Error registering probe provider '%s'. Event '%s:%s' refers to an event class in a provider with incompatible version.", | |
97 | probe_desc->provider_name, probe_desc->provider_name, event_desc->event_name); | |
98 | return false; | |
99 | } | |
ce5aef0b | 100 | } |
5b4c6da4 | 101 | return true; |
ce5aef0b MD |
102 | } |
103 | ||
6715d7d1 MD |
104 | /* |
105 | * Called under ust lock. | |
106 | */ | |
107 | static | |
4e48b5d2 | 108 | void lttng_lazy_probe_register(struct lttng_ust_registered_probe *reg_probe) |
ce5aef0b | 109 | { |
4e48b5d2 | 110 | struct lttng_ust_registered_probe *iter; |
ac69b35b | 111 | struct cds_list_head *probe_list; |
48205d60 | 112 | |
48205d60 MD |
113 | /* |
114 | * The provider ensures there are no duplicate event names. | |
7f2f82c3 | 115 | * Duplicated LTTNG_UST_TRACEPOINT_EVENT event names would generate a |
48205d60 | 116 | * compile-time error due to duplicated symbol names. |
ce5aef0b | 117 | */ |
df854e41 MD |
118 | |
119 | /* | |
dc11f93f | 120 | * We sort the providers by struct lttng_ust_probe_desc pointer |
df854e41 MD |
121 | * address. |
122 | */ | |
6715d7d1 | 123 | probe_list = &_probe_list; |
ac69b35b | 124 | cds_list_for_each_entry_reverse(iter, probe_list, head) { |
4e48b5d2 MD |
125 | BUG_ON(iter == reg_probe); /* Should never be in the list twice */ |
126 | if (iter < reg_probe) { | |
df854e41 | 127 | /* We belong to the location right after iter. */ |
4e48b5d2 MD |
128 | cds_list_add(®_probe->head, &iter->head); |
129 | goto probe_added; | |
df854e41 MD |
130 | } |
131 | } | |
132 | /* We should be added at the head of the list */ | |
4e48b5d2 MD |
133 | cds_list_add(®_probe->head, probe_list); |
134 | probe_added: | |
e81a53af | 135 | DBG("just registered probe %s containing %u events", |
4e48b5d2 | 136 | reg_probe->desc->provider_name, reg_probe->desc->nr_events); |
6715d7d1 MD |
137 | } |
138 | ||
139 | /* | |
140 | * Called under ust lock. | |
141 | */ | |
142 | static | |
143 | void fixup_lazy_probes(void) | |
144 | { | |
4e48b5d2 | 145 | struct lttng_ust_registered_probe *iter, *tmp; |
5f733922 | 146 | int ret; |
6715d7d1 MD |
147 | |
148 | lazy_nesting++; | |
149 | cds_list_for_each_entry_safe(iter, tmp, | |
150 | &lazy_probe_init, lazy_init_head) { | |
151 | lttng_lazy_probe_register(iter); | |
152 | iter->lazy = 0; | |
153 | cds_list_del(&iter->lazy_init_head); | |
154 | } | |
5f733922 MD |
155 | ret = lttng_fix_pending_events(); |
156 | assert(!ret); | |
6715d7d1 MD |
157 | lazy_nesting--; |
158 | } | |
159 | ||
160 | /* | |
161 | * Called under ust lock. | |
162 | */ | |
163 | struct cds_list_head *lttng_get_probe_list_head(void) | |
164 | { | |
165 | if (!lazy_nesting && !cds_list_empty(&lazy_probe_init)) | |
166 | fixup_lazy_probes(); | |
167 | return &_probe_list; | |
168 | } | |
169 | ||
71d31690 | 170 | |
4e48b5d2 | 171 | struct lttng_ust_registered_probe *lttng_ust_probe_register(const struct lttng_ust_probe_desc *desc) |
6715d7d1 | 172 | { |
4e48b5d2 | 173 | struct lttng_ust_registered_probe *reg_probe = NULL; |
6715d7d1 | 174 | |
a9fd951a | 175 | lttng_ust_alloc_tls(); |
c362addf | 176 | |
71d31690 MD |
177 | /* |
178 | * If version mismatch, don't register, but don't trigger assert | |
179 | * on caller. The version check just prints an error. | |
180 | */ | |
181 | if (!check_provider_version(desc)) | |
4e48b5d2 | 182 | return NULL; |
5b4c6da4 | 183 | if (!check_event_provider(desc)) |
4e48b5d2 | 184 | return NULL; |
71d31690 | 185 | |
3327ac33 | 186 | ust_lock_nocheck(); |
6715d7d1 | 187 | |
4e48b5d2 MD |
188 | reg_probe = zmalloc(sizeof(struct lttng_ust_registered_probe)); |
189 | if (!reg_probe) | |
190 | goto end; | |
191 | reg_probe->desc = desc; | |
192 | cds_list_add(®_probe->lazy_init_head, &lazy_probe_init); | |
193 | reg_probe->lazy = 1; | |
194 | ||
6715d7d1 | 195 | DBG("adding probe %s containing %u events to lazy registration list", |
5b4c6da4 | 196 | desc->provider_name, desc->nr_events); |
6715d7d1 MD |
197 | /* |
198 | * If there is at least one active session, we need to register | |
199 | * the probe immediately, since we cannot delay event | |
200 | * registration because they are needed ASAP. | |
201 | */ | |
202 | if (lttng_session_active()) | |
203 | fixup_lazy_probes(); | |
0fdd0b89 | 204 | |
d8d2416d | 205 | lttng_fix_pending_event_notifiers(); |
4e48b5d2 | 206 | end: |
17dfb34b | 207 | ust_unlock(); |
4e48b5d2 | 208 | return reg_probe; |
ce5aef0b | 209 | } |
ce5aef0b | 210 | |
4e48b5d2 | 211 | void lttng_ust_probe_unregister(struct lttng_ust_registered_probe *reg_probe) |
ce5aef0b | 212 | { |
a9fd951a | 213 | lttng_ust_alloc_tls(); |
c362addf | 214 | |
4e48b5d2 MD |
215 | if (!reg_probe) |
216 | return; | |
217 | if (!check_provider_version(reg_probe->desc)) | |
71d31690 MD |
218 | return; |
219 | ||
3327ac33 | 220 | ust_lock_nocheck(); |
4e48b5d2 MD |
221 | if (!reg_probe->lazy) |
222 | cds_list_del(®_probe->head); | |
6715d7d1 | 223 | else |
4e48b5d2 | 224 | cds_list_del(®_probe->lazy_init_head); |
2c05c691 | 225 | |
4e48b5d2 MD |
226 | lttng_probe_provider_unregister_events(reg_probe->desc); |
227 | DBG("just unregistered probes of provider %s", reg_probe->desc->provider_name); | |
17dfb34b | 228 | ust_unlock(); |
4e48b5d2 | 229 | free(reg_probe); |
ce5aef0b | 230 | } |
ce5aef0b | 231 | |
7dd08bec | 232 | void lttng_probes_prune_event_list(struct lttng_ust_tracepoint_list *list) |
c8fcf224 MD |
233 | { |
234 | struct tp_list_entry *list_entry, *tmp; | |
235 | ||
236 | cds_list_for_each_entry_safe(list_entry, tmp, &list->head, head) { | |
237 | cds_list_del(&list_entry->head); | |
238 | free(list_entry); | |
239 | } | |
240 | } | |
241 | ||
242 | /* | |
243 | * called with UST lock held. | |
244 | */ | |
7dd08bec | 245 | int lttng_probes_get_event_list(struct lttng_ust_tracepoint_list *list) |
c8fcf224 | 246 | { |
4e48b5d2 | 247 | struct lttng_ust_registered_probe *reg_probe; |
ac69b35b | 248 | struct cds_list_head *probe_list; |
4e48b5d2 | 249 | int i; |
c8fcf224 | 250 | |
ac69b35b | 251 | probe_list = lttng_get_probe_list_head(); |
c8fcf224 | 252 | CDS_INIT_LIST_HEAD(&list->head); |
4e48b5d2 MD |
253 | cds_list_for_each_entry(reg_probe, probe_list, head) { |
254 | const struct lttng_ust_probe_desc *probe_desc = reg_probe->desc; | |
255 | ||
c8fcf224 | 256 | for (i = 0; i < probe_desc->nr_events; i++) { |
5b4c6da4 MD |
257 | const struct lttng_ust_event_desc *event_desc = |
258 | probe_desc->event_desc[i]; | |
c8fcf224 MD |
259 | struct tp_list_entry *list_entry; |
260 | ||
5b4c6da4 MD |
261 | /* Skip event if name is too long. */ |
262 | if (!lttng_ust_validate_event_name(event_desc)) | |
263 | continue; | |
c8fcf224 MD |
264 | list_entry = zmalloc(sizeof(*list_entry)); |
265 | if (!list_entry) | |
266 | goto err_nomem; | |
267 | cds_list_add(&list_entry->head, &list->head); | |
5b4c6da4 MD |
268 | lttng_ust_format_event_name(event_desc, list_entry->tp.name); |
269 | if (!event_desc->loglevel) { | |
612e9ce4 | 270 | list_entry->tp.loglevel = LTTNG_UST_TRACEPOINT_LOGLEVEL_DEFAULT; |
c8fcf224 | 271 | } else { |
5b4c6da4 | 272 | list_entry->tp.loglevel = *(*event_desc->loglevel); |
c8fcf224 MD |
273 | } |
274 | } | |
275 | } | |
276 | if (cds_list_empty(&list->head)) | |
277 | list->iter = NULL; | |
278 | else | |
279 | list->iter = | |
280 | cds_list_first_entry(&list->head, struct tp_list_entry, head); | |
281 | return 0; | |
282 | ||
283 | err_nomem: | |
7dd08bec | 284 | lttng_probes_prune_event_list(list); |
c8fcf224 MD |
285 | return -ENOMEM; |
286 | } | |
287 | ||
288 | /* | |
289 | * Return current iteration position, advance internal iterator to next. | |
290 | * Return NULL if end of list. | |
291 | */ | |
fd17d7ce | 292 | struct lttng_ust_abi_tracepoint_iter * |
c8fcf224 MD |
293 | lttng_ust_tracepoint_list_get_iter_next(struct lttng_ust_tracepoint_list *list) |
294 | { | |
295 | struct tp_list_entry *entry; | |
296 | ||
297 | if (!list->iter) | |
298 | return NULL; | |
299 | entry = list->iter; | |
300 | if (entry->head.next == &list->head) | |
301 | list->iter = NULL; | |
302 | else | |
303 | list->iter = cds_list_entry(entry->head.next, | |
304 | struct tp_list_entry, head); | |
305 | return &entry->tp; | |
306 | } | |
1f18504e | 307 | |
7dd08bec | 308 | void lttng_probes_prune_field_list(struct lttng_ust_field_list *list) |
06d4f27e MD |
309 | { |
310 | struct tp_field_list_entry *list_entry, *tmp; | |
311 | ||
312 | cds_list_for_each_entry_safe(list_entry, tmp, &list->head, head) { | |
313 | cds_list_del(&list_entry->head); | |
314 | free(list_entry); | |
315 | } | |
316 | } | |
317 | ||
318 | /* | |
319 | * called with UST lock held. | |
320 | */ | |
7dd08bec | 321 | int lttng_probes_get_field_list(struct lttng_ust_field_list *list) |
06d4f27e | 322 | { |
4e48b5d2 | 323 | struct lttng_ust_registered_probe *reg_probe; |
ac69b35b | 324 | struct cds_list_head *probe_list; |
4e48b5d2 | 325 | int i; |
06d4f27e | 326 | |
ac69b35b | 327 | probe_list = lttng_get_probe_list_head(); |
06d4f27e | 328 | CDS_INIT_LIST_HEAD(&list->head); |
4e48b5d2 MD |
329 | cds_list_for_each_entry(reg_probe, probe_list, head) { |
330 | const struct lttng_ust_probe_desc *probe_desc = reg_probe->desc; | |
331 | ||
06d4f27e | 332 | for (i = 0; i < probe_desc->nr_events; i++) { |
dc11f93f | 333 | const struct lttng_ust_event_desc *event_desc = |
06d4f27e MD |
334 | probe_desc->event_desc[i]; |
335 | int j; | |
336 | ||
5b675300 | 337 | if (event_desc->tp_class->nr_fields == 0) { |
26329f26 MD |
338 | /* Events without fields. */ |
339 | struct tp_field_list_entry *list_entry; | |
340 | ||
5b4c6da4 MD |
341 | /* Skip event if name is too long. */ |
342 | if (!lttng_ust_validate_event_name(event_desc)) | |
343 | continue; | |
26329f26 MD |
344 | list_entry = zmalloc(sizeof(*list_entry)); |
345 | if (!list_entry) | |
346 | goto err_nomem; | |
347 | cds_list_add(&list_entry->head, &list->head); | |
5b4c6da4 | 348 | lttng_ust_format_event_name(event_desc, list_entry->field.event_name); |
26329f26 | 349 | list_entry->field.field_name[0] = '\0'; |
fd17d7ce | 350 | list_entry->field.type = LTTNG_UST_ABI_FIELD_OTHER; |
26329f26 | 351 | if (!event_desc->loglevel) { |
612e9ce4 | 352 | list_entry->field.loglevel = LTTNG_UST_TRACEPOINT_LOGLEVEL_DEFAULT; |
26329f26 MD |
353 | } else { |
354 | list_entry->field.loglevel = *(*event_desc->loglevel); | |
355 | } | |
356 | list_entry->field.nowrite = 1; | |
357 | } | |
358 | ||
5b675300 | 359 | for (j = 0; j < event_desc->tp_class->nr_fields; j++) { |
25cff019 | 360 | const struct lttng_ust_event_field *event_field = |
5b675300 | 361 | event_desc->tp_class->fields[j]; |
06d4f27e MD |
362 | struct tp_field_list_entry *list_entry; |
363 | ||
5b4c6da4 MD |
364 | /* Skip event if name is too long. */ |
365 | if (!lttng_ust_validate_event_name(event_desc)) | |
366 | continue; | |
06d4f27e MD |
367 | list_entry = zmalloc(sizeof(*list_entry)); |
368 | if (!list_entry) | |
369 | goto err_nomem; | |
370 | cds_list_add(&list_entry->head, &list->head); | |
5b4c6da4 | 371 | lttng_ust_format_event_name(event_desc, list_entry->field.event_name); |
06d4f27e MD |
372 | strncpy(list_entry->field.field_name, |
373 | event_field->name, | |
fd17d7ce MD |
374 | LTTNG_UST_ABI_SYM_NAME_LEN); |
375 | list_entry->field.field_name[LTTNG_UST_ABI_SYM_NAME_LEN - 1] = '\0'; | |
a084756d MD |
376 | switch (event_field->type->type) { |
377 | case lttng_ust_type_integer: | |
fd17d7ce | 378 | list_entry->field.type = LTTNG_UST_ABI_FIELD_INTEGER; |
40003310 | 379 | break; |
a084756d | 380 | case lttng_ust_type_string: |
fd17d7ce | 381 | list_entry->field.type = LTTNG_UST_ABI_FIELD_STRING; |
40003310 | 382 | break; |
a084756d MD |
383 | case lttng_ust_type_array: |
384 | if (lttng_ust_get_type_array(event_field->type)->encoding == lttng_ust_string_encoding_none) | |
fd17d7ce | 385 | list_entry->field.type = LTTNG_UST_ABI_FIELD_OTHER; |
40003310 | 386 | else |
fd17d7ce | 387 | list_entry->field.type = LTTNG_UST_ABI_FIELD_STRING; |
40003310 | 388 | break; |
a084756d MD |
389 | case lttng_ust_type_sequence: |
390 | if (lttng_ust_get_type_sequence(event_field->type)->encoding == lttng_ust_string_encoding_none) | |
fd17d7ce | 391 | list_entry->field.type = LTTNG_UST_ABI_FIELD_OTHER; |
40003310 | 392 | else |
fd17d7ce | 393 | list_entry->field.type = LTTNG_UST_ABI_FIELD_STRING; |
40003310 | 394 | break; |
a084756d | 395 | case lttng_ust_type_float: |
fd17d7ce | 396 | list_entry->field.type = LTTNG_UST_ABI_FIELD_FLOAT; |
40003310 | 397 | break; |
a084756d | 398 | case lttng_ust_type_enum: |
fd17d7ce | 399 | list_entry->field.type = LTTNG_UST_ABI_FIELD_ENUM; |
40003310 MD |
400 | break; |
401 | default: | |
fd17d7ce | 402 | list_entry->field.type = LTTNG_UST_ABI_FIELD_OTHER; |
40003310 | 403 | } |
06d4f27e | 404 | if (!event_desc->loglevel) { |
612e9ce4 | 405 | list_entry->field.loglevel = LTTNG_UST_TRACEPOINT_LOGLEVEL_DEFAULT; |
06d4f27e MD |
406 | } else { |
407 | list_entry->field.loglevel = *(*event_desc->loglevel); | |
408 | } | |
180901e6 | 409 | list_entry->field.nowrite = event_field->nowrite; |
06d4f27e MD |
410 | } |
411 | } | |
412 | } | |
413 | if (cds_list_empty(&list->head)) | |
414 | list->iter = NULL; | |
415 | else | |
416 | list->iter = | |
417 | cds_list_first_entry(&list->head, | |
418 | struct tp_field_list_entry, head); | |
419 | return 0; | |
420 | ||
421 | err_nomem: | |
7dd08bec | 422 | lttng_probes_prune_field_list(list); |
06d4f27e MD |
423 | return -ENOMEM; |
424 | } | |
425 | ||
426 | /* | |
427 | * Return current iteration position, advance internal iterator to next. | |
428 | * Return NULL if end of list. | |
429 | */ | |
fd17d7ce | 430 | struct lttng_ust_abi_field_iter * |
06d4f27e MD |
431 | lttng_ust_field_list_get_iter_next(struct lttng_ust_field_list *list) |
432 | { | |
433 | struct tp_field_list_entry *entry; | |
434 | ||
435 | if (!list->iter) | |
436 | return NULL; | |
437 | entry = list->iter; | |
438 | if (entry->head.next == &list->head) | |
439 | list->iter = NULL; | |
440 | else | |
441 | list->iter = cds_list_entry(entry->head.next, | |
442 | struct tp_field_list_entry, head); | |
443 | return &entry->field; | |
444 | } |