Common Trace Format 2 generation
[lttng-tools.git] / src / common / tracker.cpp
CommitLineData
2d97a006 1/*
4942c256 2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
159b042f 3 * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
2d97a006 4 *
ab5be9fa 5 * SPDX-License-Identifier: LGPL-2.1-only
2d97a006 6 *
2d97a006
JR
7 */
8
159b042f
JG
9#include <lttng/domain.h>
10#include <lttng/lttng-error.h>
11#include <lttng/tracker.h>
2d97a006 12
7532fa3b
MD
13#include <common/dynamic-array.hpp>
14#include <common/error.hpp>
15#include <common/hashtable/hashtable.hpp>
16#include <common/hashtable/utils.hpp>
17#include <common/tracker.hpp>
159b042f
JG
18
19#include <stdbool.h>
7532fa3b 20#include <type_traits>
159b042f
JG
21
22struct process_attr_tracker_values_comm_header {
23 uint32_t count;
24};
25
26struct process_attr_tracker_value_comm {
27 /* enum lttng_process_attr_value_type */
28 int32_t type;
29 union {
30 struct process_attr_integral_value_comm integral;
31 /* Includes the '\0' terminator. */
32 uint32_t name_len;
33 } value;
34};
35
36#define GET_INTEGRAL_COMM_VALUE(value_ptr, as_type) \
7532fa3b
MD
37 ((as_type)(std::is_signed<as_type>::value ? \
38 (value_ptr)->u._signed : (value_ptr)->u._unsigned))
159b042f 39
7532fa3b
MD
40#define SET_INTEGRAL_COMM_VALUE(comm_value, from_value) \
41 if (std::is_signed<decltype(from_value)>::value) { \
159b042f 42 (comm_value)->u._signed = \
7532fa3b 43 (typeof((comm_value)->u._signed)) from_value; \
159b042f
JG
44 } else { \
45 (comm_value)->u._unsigned = \
7532fa3b 46 (typeof((comm_value)->u._unsigned)) from_value; \
2d97a006
JR
47 }
48
159b042f
JG
49static inline bool is_virtual_process_attr(enum lttng_process_attr process_attr)
50{
51 return process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID ||
52 process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID ||
53 process_attr == LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID;
2d97a006
JR
54}
55
159b042f
JG
56static inline bool is_value_type_name(
57 enum lttng_process_attr_value_type value_type)
2d97a006 58{
159b042f
JG
59 return value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ||
60 value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME;
2d97a006
JR
61}
62
159b042f
JG
63enum lttng_error_code process_attr_value_from_comm(
64 enum lttng_domain_type domain,
65 enum lttng_process_attr process_attr,
66 enum lttng_process_attr_value_type value_type,
67 const struct process_attr_integral_value_comm *integral_value,
68 const struct lttng_buffer_view *value_view,
69 struct process_attr_value **_value)
2d97a006 70{
159b042f
JG
71 char *name = NULL;
72 enum lttng_error_code ret = LTTNG_OK;
a6bc4ca9 73 struct process_attr_value *value = (process_attr_value *) zmalloc(sizeof(*value));
2d97a006 74
159b042f
JG
75 if (!value) {
76 ret = LTTNG_ERR_NOMEM;
2d97a006
JR
77 goto error;
78 }
79
159b042f
JG
80 if (value_view && value_view->size > 0) {
81 if (value_view->data[value_view->size - 1] != '\0') {
82 ret = LTTNG_ERR_INVALID;
83 goto error;
84 }
85 name = strdup(value_view->data);
86 if (!name) {
87 ret = LTTNG_ERR_NOMEM;
74675e31 88 goto error;
159b042f
JG
89 }
90 }
2d97a006 91
159b042f
JG
92 if (domain != LTTNG_DOMAIN_UST && domain != LTTNG_DOMAIN_KERNEL) {
93 ERR("Only the user space and kernel space domains may be specified to configure process attribute trackers");
94 ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
95 goto error;
96 }
2d97a006 97
159b042f
JG
98 if (!is_virtual_process_attr(process_attr) &&
99 domain != LTTNG_DOMAIN_KERNEL) {
100 ERR("Non-virtual process attributes can only be used in the kernel domain");
101 ret = LTTNG_ERR_UNSUPPORTED_DOMAIN;
102 goto error;
103 }
2d97a006 104
159b042f 105 /* Only expect a payload for name value types. */
b78dab17
JG
106 if (is_value_type_name(value_type) &&
107 (!value_view || value_view->size == 0)) {
159b042f
JG
108 ret = LTTNG_ERR_INVALID_PROTOCOL;
109 goto error;
1ad5cb59
JG
110 } else if (!is_value_type_name(value_type) && value_view &&
111 value_view->size != 0) {
159b042f
JG
112 ret = LTTNG_ERR_INVALID_PROTOCOL;
113 goto error;
2d97a006
JR
114 }
115
159b042f
JG
116 value->type = value_type;
117 switch (process_attr) {
118 case LTTNG_PROCESS_ATTR_PROCESS_ID:
119 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
120 if (value_type != LTTNG_PROCESS_ATTR_VALUE_TYPE_PID) {
121 ERR("Invalid value type used for process ID process attribute");
122 ret = LTTNG_ERR_INVALID;
123 goto error;
124 }
125 value->value.pid =
126 GET_INTEGRAL_COMM_VALUE(integral_value, pid_t);
127 break;
128 case LTTNG_PROCESS_ATTR_USER_ID:
129 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
130 switch (value_type) {
131 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
132 value->value.uid = GET_INTEGRAL_COMM_VALUE(
133 integral_value, uid_t);
134 break;
135 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
136 if (!name) {
137 ret = LTTNG_ERR_INVALID;
138 goto error;
139 }
140
141 value->value.user_name = name;
142 name = NULL;
143 break;
144 default:
145 ERR("Invalid value type used for user ID process attribute");
146 ret = LTTNG_ERR_INVALID;
147 goto error;
148 }
149 break;
150 case LTTNG_PROCESS_ATTR_GROUP_ID:
151 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
152 switch (value_type) {
153 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
154 value->value.gid = GET_INTEGRAL_COMM_VALUE(
155 integral_value, gid_t);
156 break;
157 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
158 if (!name) {
159 ret = LTTNG_ERR_INVALID;
160 goto error;
161 }
162
163 value->value.group_name = name;
164 name = NULL;
165 break;
166 default:
167 ERR("Invalid value type used for group ID process attribute");
168 ret = LTTNG_ERR_INVALID;
169 goto error;
170 }
171 break;
172 default:
173 ret = LTTNG_ERR_INVALID_PROTOCOL;
174 goto error;
2d97a006
JR
175 }
176
159b042f
JG
177 *_value = value;
178 value = NULL;
d4e37173 179 free(name);
159b042f
JG
180 return LTTNG_OK;
181error:
182 free(name);
183 process_attr_value_destroy(value);
184 return ret;
2d97a006
JR
185}
186
159b042f 187const char *lttng_process_attr_to_string(enum lttng_process_attr process_attr)
2d97a006 188{
159b042f
JG
189 switch (process_attr) {
190 case LTTNG_PROCESS_ATTR_PROCESS_ID:
191 return "process ID";
192 case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
193 return "virtual process ID";
194 case LTTNG_PROCESS_ATTR_USER_ID:
195 return "user ID";
196 case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
197 return "virtual user ID";
198 case LTTNG_PROCESS_ATTR_GROUP_ID:
199 return "group ID";
200 case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
201 return "virtual group ID";
202 default:
203 return "unknown process attribute";
2d97a006 204 }
2d97a006
JR
205}
206
159b042f 207static void process_attr_tracker_value_destructor(void *ptr)
2d97a006 208{
159b042f
JG
209 struct process_attr_value *value = (typeof(value)) ptr;
210
211 process_attr_value_destroy(value);
2d97a006
JR
212}
213
159b042f 214struct lttng_process_attr_values *lttng_process_attr_values_create(void)
2d97a006 215{
a6bc4ca9 216 struct lttng_process_attr_values *values = (lttng_process_attr_values *) zmalloc(sizeof(*values));
2d97a006 217
159b042f
JG
218 if (!values) {
219 goto end;
2d97a006
JR
220 }
221
159b042f
JG
222 lttng_dynamic_pointer_array_init(
223 &values->array, process_attr_tracker_value_destructor);
224end:
225 return values;
2d97a006
JR
226}
227
159b042f
JG
228unsigned int _lttng_process_attr_values_get_count(
229 const struct lttng_process_attr_values *values)
2d97a006 230{
159b042f
JG
231 return (unsigned int) lttng_dynamic_pointer_array_get_count(
232 &values->array);
2d97a006
JR
233}
234
159b042f
JG
235const struct process_attr_value *lttng_process_attr_tracker_values_get_at_index(
236 const struct lttng_process_attr_values *values,
237 unsigned int index)
2d97a006 238{
a6bc4ca9 239 return (process_attr_value *) lttng_dynamic_pointer_array_get_pointer(&values->array, index);
159b042f 240}
2d97a006 241
159b042f
JG
242static
243int process_attr_tracker_value_serialize(const struct process_attr_value *value,
244 struct lttng_dynamic_buffer *buffer)
245{
246 int ret;
247 struct process_attr_tracker_value_comm value_comm = {
248 .type = (int32_t) value->type,
249 };
250 const char *name = NULL;
251
252 switch (value->type) {
253 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
254 SET_INTEGRAL_COMM_VALUE(
255 &value_comm.value.integral, value->value.pid);
2d97a006 256 break;
159b042f
JG
257 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
258 SET_INTEGRAL_COMM_VALUE(
259 &value_comm.value.integral, value->value.uid);
2d97a006 260 break;
159b042f
JG
261 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
262 SET_INTEGRAL_COMM_VALUE(
263 &value_comm.value.integral, value->value.gid);
2d97a006 264 break;
159b042f
JG
265 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
266 name = value->value.user_name;
2d97a006 267 break;
159b042f
JG
268 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
269 name = value->value.group_name;
270 break;
271 default:
272 abort();
2d97a006
JR
273 }
274
159b042f
JG
275 if (name) {
276 value_comm.value.name_len = strlen(name) + 1;
a7a533cd 277 }
159b042f
JG
278
279 ret = lttng_dynamic_buffer_append(
280 buffer, &value_comm, sizeof(value_comm));
281 if (ret) {
282 goto end;
283 }
284
285 if (name) {
286 ret = lttng_dynamic_buffer_append(
287 buffer, name, value_comm.value.name_len);
288 }
289end:
a7a533cd
JR
290 return ret;
291}
292
159b042f
JG
293int lttng_process_attr_values_serialize(
294 const struct lttng_process_attr_values *values,
295 struct lttng_dynamic_buffer *buffer)
a7a533cd
JR
296{
297 int ret;
159b042f
JG
298 unsigned int count, i;
299 struct process_attr_tracker_values_comm_header header = {};
a7a533cd 300
159b042f
JG
301 count = _lttng_process_attr_values_get_count(values);
302 header.count = (uint32_t) count;
a7a533cd 303
159b042f 304 ret = lttng_dynamic_buffer_append(buffer, &header, sizeof(header));
a7a533cd 305 if (ret) {
159b042f 306 goto end;
2d97a006
JR
307 }
308
159b042f
JG
309 for (i = 0; i < count; i++) {
310 const struct process_attr_value *value =
311 lttng_process_attr_tracker_values_get_at_index(
312 values, i);
2d97a006 313
159b042f
JG
314 ret = process_attr_tracker_value_serialize(value, buffer);
315 if (ret) {
316 goto end;
317 }
2d97a006 318 }
159b042f
JG
319end:
320 return ret;
2d97a006 321}
a7a533cd 322
159b042f
JG
323ssize_t lttng_process_attr_values_create_from_buffer(
324 enum lttng_domain_type domain,
325 enum lttng_process_attr process_attr,
326 const struct lttng_buffer_view *buffer_view,
327 struct lttng_process_attr_values **_values)
a7a533cd 328{
159b042f
JG
329 ssize_t offset;
330 unsigned int i;
331 struct lttng_process_attr_values *values;
332 struct lttng_buffer_view header_view;
333 const struct process_attr_tracker_values_comm_header *header;
a7a533cd 334
159b042f
JG
335 values = lttng_process_attr_values_create();
336 if (!values) {
a7a533cd
JR
337 goto error;
338 }
339
159b042f
JG
340 header_view = lttng_buffer_view_from_view(
341 buffer_view, 0, sizeof(*header));
3e6e0df2 342 if (!lttng_buffer_view_is_valid(&header_view)) {
a7a533cd
JR
343 goto error;
344 }
3e6e0df2 345
159b042f
JG
346 offset = header_view.size;
347 header = (typeof(header)) header_view.data;
348
349 /*
350 * Check that the number of values is not absurdly large with respect to
351 * the received buffer's size.
352 */
353 if (buffer_view->size <
354 header->count * sizeof(struct process_attr_tracker_value_comm)) {
355 goto error;
356 }
357 for (i = 0; i < (unsigned int) header->count; i++) {
358 int ret;
359 enum lttng_error_code ret_code;
360 const struct process_attr_tracker_value_comm *value_comm;
361 struct process_attr_value *value;
362 enum lttng_process_attr_value_type type;
363 struct lttng_buffer_view value_view;
364 struct lttng_buffer_view value_name_view = {};
365
366 value_view = lttng_buffer_view_from_view(
367 buffer_view, offset, sizeof(*value_comm));
3e6e0df2 368 if (!lttng_buffer_view_is_valid(&value_view)) {
159b042f
JG
369 goto error;
370 }
a7a533cd 371
159b042f
JG
372 offset += value_view.size;
373 value_comm = (typeof(value_comm)) value_view.data;
374 type = (typeof(type)) value_comm->type;
a7a533cd 375
159b042f
JG
376 if (is_value_type_name(type)) {
377 value_name_view = lttng_buffer_view_from_view(
378 buffer_view, offset,
379 value_comm->value.name_len);
3e6e0df2
JG
380 if (!lttng_buffer_view_is_valid(&value_name_view)) {
381 goto error;
382 }
383
159b042f
JG
384 offset += value_name_view.size;
385 }
3e6e0df2 386
159b042f
JG
387 ret_code = process_attr_value_from_comm(domain, process_attr,
388 type, &value_comm->value.integral,
389 &value_name_view, &value);
390 if (ret_code != LTTNG_OK) {
391 goto error;
392 }
a7a533cd 393
159b042f
JG
394 ret = lttng_dynamic_pointer_array_add_pointer(
395 &values->array, value);
396 if (ret) {
397 process_attr_value_destroy(value);
398 goto error;
399 }
a7a533cd
JR
400 }
401
159b042f
JG
402 *_values = values;
403 return offset;
404error:
405 lttng_process_attr_values_destroy(values);
406 return -1;
a7a533cd
JR
407}
408
159b042f 409void lttng_process_attr_values_destroy(struct lttng_process_attr_values *values)
a7a533cd 410{
159b042f
JG
411 if (!values) {
412 return;
413 }
414 lttng_dynamic_pointer_array_reset(&values->array);
415 free(values);
a7a533cd
JR
416}
417
159b042f
JG
418struct process_attr_value *process_attr_value_copy(
419 const struct process_attr_value *value)
a7a533cd 420{
159b042f 421 struct process_attr_value *new_value = NULL;
e283e4a0 422
159b042f 423 if (!value) {
e283e4a0
JR
424 goto end;
425 }
426
a6bc4ca9 427 new_value = (process_attr_value *) zmalloc(sizeof(*new_value));
159b042f
JG
428 if (!new_value) {
429 goto end;
430 }
431 if (is_value_type_name(value->type)) {
432 const char *src =
433 value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
434 value->value.user_name :
435 value->value.group_name;
436 char **dst = value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
437 &new_value->value.user_name :
438 &new_value->value.group_name;
439
440 new_value->type = value->type;
441 *dst = strdup(src);
442 if (!*dst) {
443 goto error;
444 }
445 } else {
446 *new_value = *value;
447 }
e283e4a0 448end:
159b042f
JG
449 return new_value;
450error:
451 free(new_value);
452 return NULL;
a7a533cd
JR
453}
454
159b042f 455unsigned long process_attr_value_hash(const struct process_attr_value *a)
a7a533cd 456{
159b042f 457 unsigned long hash = hash_key_ulong((void *) a->type, lttng_ht_seed);
9df6c82a 458
159b042f
JG
459 switch (a->type) {
460 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
461 hash ^= hash_key_ulong((void *) (unsigned long) a->value.pid,
462 lttng_ht_seed);
463 break;
464 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
465 hash ^= hash_key_ulong((void *) (unsigned long) a->value.uid,
466 lttng_ht_seed);
467 break;
468 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
469 hash ^= hash_key_ulong((void *) (unsigned long) a->value.gid,
470 lttng_ht_seed);
471 break;
472 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
473 hash ^= hash_key_str(a->value.user_name, lttng_ht_seed);
474 break;
475 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
476 hash ^= hash_key_str(a->value.group_name, lttng_ht_seed);
477 break;
478 default:
479 abort();
a7a533cd
JR
480 }
481
159b042f 482 return hash;
a7a533cd 483}
f19f5c96 484
159b042f
JG
485bool process_attr_tracker_value_equal(const struct process_attr_value *a,
486 const struct process_attr_value *b)
f19f5c96 487{
159b042f
JG
488 if (a->type != b->type) {
489 return false;
f19f5c96 490 }
159b042f
JG
491 switch (a->type) {
492 case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
493 return a->value.pid == b->value.pid;
494 case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
495 return a->value.uid == b->value.uid;
496 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
497 return a->value.gid == b->value.gid;
498 case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
499 return !strcmp(a->value.user_name, b->value.user_name);
500 case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
501 return !strcmp(a->value.group_name, b->value.group_name);
502 default:
503 abort();
504 }
505}
f19f5c96 506
159b042f
JG
507void process_attr_value_destroy(struct process_attr_value *value)
508{
509 if (!value) {
510 return;
f19f5c96 511 }
159b042f
JG
512 if (is_value_type_name(value->type)) {
513 free(value->type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ?
514 value->value.user_name :
515 value->value.group_name);
516 }
517 free(value);
f19f5c96 518}
This page took 0.069528 seconds and 5 git commands to generate.