Fix: Possible use-after-free in create_ctx_type()
[lttng-tools.git] / src / bin / lttng / commands / add_context.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Copyright (C) 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #define _LGPL_SOURCE
20 #include <ctype.h>
21 #include <popt.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <assert.h>
29
30 #include <urcu/list.h>
31
32 #include <common/mi-lttng.h>
33
34 #include "../command.h"
35
36 #define PRINT_LINE_LEN 80
37
38 static char *opt_channel_name;
39 static char *opt_session_name;
40 static int opt_kernel;
41 static int opt_userspace;
42 static int opt_jul;
43 static int opt_log4j;
44 static char *opt_type;
45
46 enum {
47 OPT_HELP = 1,
48 OPT_TYPE,
49 OPT_USERSPACE,
50 OPT_JUL,
51 OPT_LOG4J,
52 OPT_LIST_OPTIONS,
53 };
54
55 static struct lttng_handle *handle;
56 static struct mi_writer *writer;
57
58 /*
59 * Taken from the LTTng ABI
60 */
61 enum context_type {
62 CONTEXT_PID = 0,
63 CONTEXT_PERF_COUNTER = 1, /* Backward compat. */
64 CONTEXT_PROCNAME = 2,
65 CONTEXT_PRIO = 3,
66 CONTEXT_NICE = 4,
67 CONTEXT_VPID = 5,
68 CONTEXT_TID = 6,
69 CONTEXT_VTID = 7,
70 CONTEXT_PPID = 8,
71 CONTEXT_VPPID = 9,
72 CONTEXT_PTHREAD_ID = 10,
73 CONTEXT_HOSTNAME = 11,
74 CONTEXT_IP = 12,
75 CONTEXT_PERF_CPU_COUNTER = 13,
76 CONTEXT_PERF_THREAD_COUNTER = 14,
77 CONTEXT_APP_CONTEXT = 15,
78 };
79
80 /*
81 * Taken from the Perf ABI (all enum perf_*)
82 */
83 enum perf_type {
84 PERF_TYPE_HARDWARE = 0,
85 PERF_TYPE_SOFTWARE = 1,
86 PERF_TYPE_HW_CACHE = 3,
87 };
88
89 enum perf_count_hard {
90 PERF_COUNT_HW_CPU_CYCLES = 0,
91 PERF_COUNT_HW_INSTRUCTIONS = 1,
92 PERF_COUNT_HW_CACHE_REFERENCES = 2,
93 PERF_COUNT_HW_CACHE_MISSES = 3,
94 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
95 PERF_COUNT_HW_BRANCH_MISSES = 5,
96 PERF_COUNT_HW_BUS_CYCLES = 6,
97 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
98 PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
99 };
100
101 enum perf_count_soft {
102 PERF_COUNT_SW_CPU_CLOCK = 0,
103 PERF_COUNT_SW_TASK_CLOCK = 1,
104 PERF_COUNT_SW_PAGE_FAULTS = 2,
105 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
106 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
107 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
108 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
109 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
110 PERF_COUNT_SW_EMULATION_FAULTS = 8,
111 };
112
113 /*
114 * Generalized hardware cache events:
115 *
116 * { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
117 * { read, write, prefetch } x
118 * { accesses, misses }
119 */
120 enum perf_hw_cache_id {
121 PERF_COUNT_HW_CACHE_L1D = 0,
122 PERF_COUNT_HW_CACHE_L1I = 1,
123 PERF_COUNT_HW_CACHE_LL = 2,
124 PERF_COUNT_HW_CACHE_DTLB = 3,
125 PERF_COUNT_HW_CACHE_ITLB = 4,
126 PERF_COUNT_HW_CACHE_BPU = 5,
127
128 PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
129 };
130
131 enum perf_hw_cache_op_id {
132 PERF_COUNT_HW_CACHE_OP_READ = 0,
133 PERF_COUNT_HW_CACHE_OP_WRITE = 1,
134 PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
135
136 PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
137 };
138
139 enum perf_hw_cache_op_result_id {
140 PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
141 PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
142
143 PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
144 };
145
146 static struct poptOption long_options[] = {
147 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
148 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
149 {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
150 {"channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
151 {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
152 {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
153 {"jul", 'j', POPT_ARG_NONE, 0, OPT_JUL, 0, 0},
154 {"log4j", 'l', POPT_ARG_NONE, 0, OPT_LOG4J, 0, 0},
155 {"type", 't', POPT_ARG_STRING, &opt_type, OPT_TYPE, 0, 0},
156 {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
157 {0, 0, 0, 0, 0, 0, 0}
158 };
159
160 /*
161 * Context options
162 */
163 #define PERF_HW(optstr, name, type, hide) \
164 { \
165 optstr, type, hide, \
166 .u.perf = { PERF_TYPE_HARDWARE, PERF_COUNT_HW_##name, },\
167 }
168
169 #define PERF_SW(optstr, name, type, hide) \
170 { \
171 optstr, type, hide, \
172 .u.perf = { PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##name, },\
173 }
174
175 #define _PERF_HW_CACHE(optstr, name, type, op, result, hide) \
176 { \
177 optstr, type, hide, \
178 .u.perf = { \
179 PERF_TYPE_HW_CACHE, \
180 (uint64_t) PERF_COUNT_HW_CACHE_##name \
181 | ((uint64_t) PERF_COUNT_HW_CACHE_OP_##op << 8) \
182 | ((uint64_t) PERF_COUNT_HW_CACHE_RESULT_##result << 16), \
183 }, \
184 }
185
186 #define PERF_HW_CACHE(optstr, name, type, hide) \
187 _PERF_HW_CACHE(optstr "-loads", name, type, \
188 READ, ACCESS, hide), \
189 _PERF_HW_CACHE(optstr "-load-misses", name, type, \
190 READ, MISS, hide), \
191 _PERF_HW_CACHE(optstr "-stores", name, type, \
192 WRITE, ACCESS, hide), \
193 _PERF_HW_CACHE(optstr "-store-misses", name, type, \
194 WRITE, MISS, hide), \
195 _PERF_HW_CACHE(optstr "-prefetches", name, type, \
196 PREFETCH, ACCESS, hide), \
197 _PERF_HW_CACHE(optstr "-prefetch-misses", name, type, \
198 PREFETCH, MISS, hide)
199
200 static
201 const struct ctx_opts {
202 char *symbol;
203 enum context_type ctx_type;
204 int hide_help; /* Hide from --help */
205 union {
206 struct {
207 uint32_t type;
208 uint64_t config;
209 } perf;
210 struct {
211 char *provider_name;
212 char *ctx_name;
213 } app_ctx;
214 } u;
215 } ctx_opts[] = {
216 { "pid", CONTEXT_PID },
217 { "procname", CONTEXT_PROCNAME },
218 { "prio", CONTEXT_PRIO },
219 { "nice", CONTEXT_NICE },
220 { "vpid", CONTEXT_VPID },
221 { "tid", CONTEXT_TID },
222 { "pthread_id", CONTEXT_PTHREAD_ID },
223 { "vtid", CONTEXT_VTID },
224 { "ppid", CONTEXT_PPID },
225 { "vppid", CONTEXT_VPPID },
226 { "hostname", CONTEXT_HOSTNAME },
227 { "ip", CONTEXT_IP },
228
229 /* Perf options */
230
231 /* Perf per-CPU counters */
232 PERF_HW("perf:cpu:cpu-cycles", CPU_CYCLES,
233 CONTEXT_PERF_CPU_COUNTER, 0),
234 PERF_HW("perf:cpu:cycles", CPU_CYCLES,
235 CONTEXT_PERF_CPU_COUNTER, 0),
236 PERF_HW("perf:cpu:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
237 CONTEXT_PERF_CPU_COUNTER, 0),
238 PERF_HW("perf:cpu:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
239 CONTEXT_PERF_CPU_COUNTER, 0),
240 PERF_HW("perf:cpu:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
241 CONTEXT_PERF_CPU_COUNTER, 0),
242 PERF_HW("perf:cpu:idle-cycles-backend", STALLED_CYCLES_BACKEND,
243 CONTEXT_PERF_CPU_COUNTER, 0),
244 PERF_HW("perf:cpu:instructions", INSTRUCTIONS,
245 CONTEXT_PERF_CPU_COUNTER, 0),
246 PERF_HW("perf:cpu:cache-references", CACHE_REFERENCES,
247 CONTEXT_PERF_CPU_COUNTER, 0),
248 PERF_HW("perf:cpu:cache-misses", CACHE_MISSES,
249 CONTEXT_PERF_CPU_COUNTER, 0),
250 PERF_HW("perf:cpu:branch-instructions", BRANCH_INSTRUCTIONS,
251 CONTEXT_PERF_CPU_COUNTER, 0),
252 PERF_HW("perf:cpu:branches", BRANCH_INSTRUCTIONS,
253 CONTEXT_PERF_CPU_COUNTER, 0),
254 PERF_HW("perf:cpu:branch-misses", BRANCH_MISSES,
255 CONTEXT_PERF_CPU_COUNTER, 0),
256 PERF_HW("perf:cpu:bus-cycles", BUS_CYCLES,
257 CONTEXT_PERF_CPU_COUNTER, 0),
258
259 PERF_HW_CACHE("perf:cpu:L1-dcache", L1D,
260 CONTEXT_PERF_CPU_COUNTER, 0),
261 PERF_HW_CACHE("perf:cpu:L1-icache", L1I,
262 CONTEXT_PERF_CPU_COUNTER, 0),
263 PERF_HW_CACHE("perf:cpu:LLC", LL,
264 CONTEXT_PERF_CPU_COUNTER, 0),
265 PERF_HW_CACHE("perf:cpu:dTLB", DTLB,
266 CONTEXT_PERF_CPU_COUNTER, 0),
267 _PERF_HW_CACHE("perf:cpu:iTLB-loads", ITLB,
268 CONTEXT_PERF_CPU_COUNTER, READ, ACCESS, 0),
269 _PERF_HW_CACHE("perf:cpu:iTLB-load-misses", ITLB,
270 CONTEXT_PERF_CPU_COUNTER, READ, MISS, 0),
271 _PERF_HW_CACHE("perf:cpu:branch-loads", BPU,
272 CONTEXT_PERF_CPU_COUNTER, READ, ACCESS, 0),
273 _PERF_HW_CACHE("perf:cpu:branch-load-misses", BPU,
274 CONTEXT_PERF_CPU_COUNTER, READ, MISS, 0),
275
276 PERF_SW("perf:cpu:cpu-clock", CPU_CLOCK,
277 CONTEXT_PERF_CPU_COUNTER, 0),
278 PERF_SW("perf:cpu:task-clock", TASK_CLOCK,
279 CONTEXT_PERF_CPU_COUNTER, 0),
280 PERF_SW("perf:cpu:page-fault", PAGE_FAULTS,
281 CONTEXT_PERF_CPU_COUNTER, 0),
282 PERF_SW("perf:cpu:faults", PAGE_FAULTS,
283 CONTEXT_PERF_CPU_COUNTER, 0),
284 PERF_SW("perf:cpu:major-faults", PAGE_FAULTS_MAJ,
285 CONTEXT_PERF_CPU_COUNTER, 0),
286 PERF_SW("perf:cpu:minor-faults", PAGE_FAULTS_MIN,
287 CONTEXT_PERF_CPU_COUNTER, 0),
288 PERF_SW("perf:cpu:context-switches", CONTEXT_SWITCHES,
289 CONTEXT_PERF_CPU_COUNTER, 0),
290 PERF_SW("perf:cpu:cs", CONTEXT_SWITCHES,
291 CONTEXT_PERF_CPU_COUNTER, 0),
292 PERF_SW("perf:cpu:cpu-migrations", CPU_MIGRATIONS,
293 CONTEXT_PERF_CPU_COUNTER, 0),
294 PERF_SW("perf:cpu:migrations", CPU_MIGRATIONS,
295 CONTEXT_PERF_CPU_COUNTER, 0),
296 PERF_SW("perf:cpu:alignment-faults", ALIGNMENT_FAULTS,
297 CONTEXT_PERF_CPU_COUNTER, 0),
298 PERF_SW("perf:cpu:emulation-faults", EMULATION_FAULTS,
299 CONTEXT_PERF_CPU_COUNTER, 0),
300
301 /* Perf per-thread counters */
302 PERF_HW("perf:thread:cpu-cycles", CPU_CYCLES,
303 CONTEXT_PERF_THREAD_COUNTER, 0),
304 PERF_HW("perf:thread:cycles", CPU_CYCLES,
305 CONTEXT_PERF_THREAD_COUNTER, 0),
306 PERF_HW("perf:thread:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
307 CONTEXT_PERF_THREAD_COUNTER, 0),
308 PERF_HW("perf:thread:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
309 CONTEXT_PERF_THREAD_COUNTER, 0),
310 PERF_HW("perf:thread:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
311 CONTEXT_PERF_THREAD_COUNTER, 0),
312 PERF_HW("perf:thread:idle-cycles-backend", STALLED_CYCLES_BACKEND,
313 CONTEXT_PERF_THREAD_COUNTER, 0),
314 PERF_HW("perf:thread:instructions", INSTRUCTIONS,
315 CONTEXT_PERF_THREAD_COUNTER, 0),
316 PERF_HW("perf:thread:cache-references", CACHE_REFERENCES,
317 CONTEXT_PERF_THREAD_COUNTER, 0),
318 PERF_HW("perf:thread:cache-misses", CACHE_MISSES,
319 CONTEXT_PERF_THREAD_COUNTER, 0),
320 PERF_HW("perf:thread:branch-instructions", BRANCH_INSTRUCTIONS,
321 CONTEXT_PERF_THREAD_COUNTER, 0),
322 PERF_HW("perf:thread:branches", BRANCH_INSTRUCTIONS,
323 CONTEXT_PERF_THREAD_COUNTER, 0),
324 PERF_HW("perf:thread:branch-misses", BRANCH_MISSES,
325 CONTEXT_PERF_THREAD_COUNTER, 0),
326 PERF_HW("perf:thread:bus-cycles", BUS_CYCLES,
327 CONTEXT_PERF_THREAD_COUNTER, 0),
328
329 PERF_HW_CACHE("perf:thread:L1-dcache", L1D,
330 CONTEXT_PERF_THREAD_COUNTER, 0),
331 PERF_HW_CACHE("perf:thread:L1-icache", L1I,
332 CONTEXT_PERF_THREAD_COUNTER, 0),
333 PERF_HW_CACHE("perf:thread:LLC", LL,
334 CONTEXT_PERF_THREAD_COUNTER, 0),
335 PERF_HW_CACHE("perf:thread:dTLB", DTLB,
336 CONTEXT_PERF_THREAD_COUNTER, 0),
337 _PERF_HW_CACHE("perf:thread:iTLB-loads", ITLB,
338 CONTEXT_PERF_THREAD_COUNTER, READ, ACCESS, 0),
339 _PERF_HW_CACHE("perf:thread:iTLB-load-misses", ITLB,
340 CONTEXT_PERF_THREAD_COUNTER, READ, MISS, 0),
341 _PERF_HW_CACHE("perf:thread:branch-loads", BPU,
342 CONTEXT_PERF_THREAD_COUNTER, READ, ACCESS, 0),
343 _PERF_HW_CACHE("perf:thread:branch-load-misses", BPU,
344 CONTEXT_PERF_THREAD_COUNTER, READ, MISS, 0),
345
346 PERF_SW("perf:thread:cpu-clock", CPU_CLOCK,
347 CONTEXT_PERF_THREAD_COUNTER, 0),
348 PERF_SW("perf:thread:task-clock", TASK_CLOCK,
349 CONTEXT_PERF_THREAD_COUNTER, 0),
350 PERF_SW("perf:thread:page-fault", PAGE_FAULTS,
351 CONTEXT_PERF_THREAD_COUNTER, 0),
352 PERF_SW("perf:thread:faults", PAGE_FAULTS,
353 CONTEXT_PERF_THREAD_COUNTER, 0),
354 PERF_SW("perf:thread:major-faults", PAGE_FAULTS_MAJ,
355 CONTEXT_PERF_THREAD_COUNTER, 0),
356 PERF_SW("perf:thread:minor-faults", PAGE_FAULTS_MIN,
357 CONTEXT_PERF_THREAD_COUNTER, 0),
358 PERF_SW("perf:thread:context-switches", CONTEXT_SWITCHES,
359 CONTEXT_PERF_THREAD_COUNTER, 0),
360 PERF_SW("perf:thread:cs", CONTEXT_SWITCHES,
361 CONTEXT_PERF_THREAD_COUNTER, 0),
362 PERF_SW("perf:thread:cpu-migrations", CPU_MIGRATIONS,
363 CONTEXT_PERF_THREAD_COUNTER, 0),
364 PERF_SW("perf:thread:migrations", CPU_MIGRATIONS,
365 CONTEXT_PERF_THREAD_COUNTER, 0),
366 PERF_SW("perf:thread:alignment-faults", ALIGNMENT_FAULTS,
367 CONTEXT_PERF_THREAD_COUNTER, 0),
368 PERF_SW("perf:thread:emulation-faults", EMULATION_FAULTS,
369 CONTEXT_PERF_THREAD_COUNTER, 0),
370
371 /*
372 * Perf per-CPU counters, backward compatibilty for names.
373 * Hidden from help listing.
374 */
375 PERF_HW("perf:cpu-cycles", CPU_CYCLES,
376 CONTEXT_PERF_COUNTER, 1),
377 PERF_HW("perf:cycles", CPU_CYCLES,
378 CONTEXT_PERF_COUNTER, 1),
379 PERF_HW("perf:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
380 CONTEXT_PERF_COUNTER, 1),
381 PERF_HW("perf:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
382 CONTEXT_PERF_COUNTER, 1),
383 PERF_HW("perf:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
384 CONTEXT_PERF_COUNTER, 1),
385 PERF_HW("perf:idle-cycles-backend", STALLED_CYCLES_BACKEND,
386 CONTEXT_PERF_COUNTER, 1),
387 PERF_HW("perf:instructions", INSTRUCTIONS,
388 CONTEXT_PERF_COUNTER, 1),
389 PERF_HW("perf:cache-references", CACHE_REFERENCES,
390 CONTEXT_PERF_COUNTER, 1),
391 PERF_HW("perf:cache-misses", CACHE_MISSES,
392 CONTEXT_PERF_COUNTER, 1),
393 PERF_HW("perf:branch-instructions", BRANCH_INSTRUCTIONS,
394 CONTEXT_PERF_COUNTER, 1),
395 PERF_HW("perf:branches", BRANCH_INSTRUCTIONS,
396 CONTEXT_PERF_COUNTER, 1),
397 PERF_HW("perf:branch-misses", BRANCH_MISSES,
398 CONTEXT_PERF_COUNTER, 1),
399 PERF_HW("perf:bus-cycles", BUS_CYCLES,
400 CONTEXT_PERF_COUNTER, 1),
401
402 PERF_HW_CACHE("perf:L1-dcache", L1D,
403 CONTEXT_PERF_COUNTER, 1),
404 PERF_HW_CACHE("perf:L1-icache", L1I,
405 CONTEXT_PERF_COUNTER, 1),
406 PERF_HW_CACHE("perf:LLC", LL,
407 CONTEXT_PERF_COUNTER, 1),
408 PERF_HW_CACHE("perf:dTLB", DTLB,
409 CONTEXT_PERF_COUNTER, 1),
410 _PERF_HW_CACHE("perf:iTLB-loads", ITLB,
411 CONTEXT_PERF_COUNTER, READ, ACCESS, 1),
412 _PERF_HW_CACHE("perf:iTLB-load-misses", ITLB,
413 CONTEXT_PERF_COUNTER, READ, MISS, 1),
414 _PERF_HW_CACHE("perf:branch-loads", BPU,
415 CONTEXT_PERF_COUNTER, READ, ACCESS, 1),
416 _PERF_HW_CACHE("perf:branch-load-misses", BPU,
417 CONTEXT_PERF_COUNTER, READ, MISS, 1),
418
419 PERF_SW("perf:cpu-clock", CPU_CLOCK,
420 CONTEXT_PERF_COUNTER, 1),
421 PERF_SW("perf:task-clock", TASK_CLOCK,
422 CONTEXT_PERF_COUNTER, 1),
423 PERF_SW("perf:page-fault", PAGE_FAULTS,
424 CONTEXT_PERF_COUNTER, 1),
425 PERF_SW("perf:faults", PAGE_FAULTS,
426 CONTEXT_PERF_COUNTER, 1),
427 PERF_SW("perf:major-faults", PAGE_FAULTS_MAJ,
428 CONTEXT_PERF_COUNTER, 1),
429 PERF_SW("perf:minor-faults", PAGE_FAULTS_MIN,
430 CONTEXT_PERF_COUNTER, 1),
431 PERF_SW("perf:context-switches", CONTEXT_SWITCHES,
432 CONTEXT_PERF_COUNTER, 1),
433 PERF_SW("perf:cs", CONTEXT_SWITCHES,
434 CONTEXT_PERF_COUNTER, 1),
435 PERF_SW("perf:cpu-migrations", CPU_MIGRATIONS,
436 CONTEXT_PERF_COUNTER, 1),
437 PERF_SW("perf:migrations", CPU_MIGRATIONS,
438 CONTEXT_PERF_COUNTER, 1),
439 PERF_SW("perf:alignment-faults", ALIGNMENT_FAULTS,
440 CONTEXT_PERF_COUNTER, 1),
441 PERF_SW("perf:emulation-faults", EMULATION_FAULTS,
442 CONTEXT_PERF_COUNTER, 1),
443
444 { NULL, -1 }, /* Closure */
445 };
446
447 #undef PERF_HW_CACHE
448 #undef _PERF_HW_CACHE
449 #undef PERF_SW
450 #undef PERF_HW
451
452 /*
453 * Context type for command line option parsing.
454 */
455 struct ctx_type {
456 struct ctx_opts *opt;
457 struct cds_list_head list;
458 };
459
460 /*
461 * List of context type. Use to enable multiple context on a single command
462 * line entry.
463 */
464 struct ctx_type_list {
465 struct cds_list_head head;
466 } ctx_type_list = {
467 .head = CDS_LIST_HEAD_INIT(ctx_type_list.head),
468 };
469
470 /*
471 * Pretty print context type.
472 */
473 static void print_ctx_type(FILE *ofp)
474 {
475 const char *indent = " ";
476 int indent_len = strlen(indent);
477 int len, i = 0;
478
479 fprintf(ofp, "%s", indent);
480 len = indent_len;
481 while (ctx_opts[i].symbol != NULL) {
482 if (!ctx_opts[i].hide_help) {
483 if (len > indent_len) {
484 if (len + strlen(ctx_opts[i].symbol) + 2
485 >= PRINT_LINE_LEN) {
486 fprintf(ofp, ",\n");
487 fprintf(ofp, "%s", indent);
488 len = indent_len;
489 } else {
490 len += fprintf(ofp, ", ");
491 }
492 }
493 len += fprintf(ofp, "%s", ctx_opts[i].symbol);
494 }
495 i++;
496 }
497 }
498
499 /*
500 * usage
501 */
502 static void usage(FILE *ofp)
503 {
504 fprintf(ofp, "usage: lttng add-context -t TYPE [-k|-u] [OPTIONS]\n");
505 fprintf(ofp, "\n");
506 fprintf(ofp, "If no channel is given (-c), the context is added to\n");
507 fprintf(ofp, "all channels.\n");
508 fprintf(ofp, "\n");
509 fprintf(ofp, "Otherwise the context is added only to the channel (-c).\n");
510 fprintf(ofp, "\n");
511 fprintf(ofp, "Exactly one domain (-k or -u) must be specified.\n");
512 fprintf(ofp, "\n");
513 fprintf(ofp, "Options:\n");
514 fprintf(ofp, " -h, --help Show this help\n");
515 fprintf(ofp, " --list-options Simple listing of options\n");
516 fprintf(ofp, " -s, --session NAME Apply to session name\n");
517 fprintf(ofp, " -c, --channel NAME Apply to channel\n");
518 fprintf(ofp, " -k, --kernel Apply to the kernel tracer\n");
519 fprintf(ofp, " -u, --userspace Apply to the user-space tracer\n");
520 fprintf(ofp, " -j, --jul Apply to Java application using JUL\n");
521 fprintf(ofp, " -l, --log4j Apply for Java application using LOG4j\n");
522 fprintf(ofp, "\n");
523 fprintf(ofp, "Context:\n");
524 fprintf(ofp, " -t, --type TYPE Context type. You can repeat that option on\n");
525 fprintf(ofp, " the command line to specify multiple contexts at once.\n");
526 fprintf(ofp, " (--kernel preempts --userspace)\n");
527 fprintf(ofp, " TYPE can be one of the strings below:\n");
528 print_ctx_type(ofp);
529 fprintf(ofp, "\n");
530 fprintf(ofp, "Note that the vpid, vppid and vtid context types represent the virtual process id,\n"
531 "virtual parent process id and virtual thread id as seen from the current execution context\n"
532 "as opposed to the pid, ppid and tid which are kernel internal data structures.\n\n");
533 fprintf(ofp, "Example:\n");
534 fprintf(ofp, "This command will add the context information 'prio' and two per-cpu\n"
535 "perf counters (hardware branch misses and cache misses), to all channels\n"
536 "in the trace data output:\n");
537 fprintf(ofp, "# lttng add-context -k -t prio -t perf:cpu:branch-misses -t perf:cpu:cache-misses\n");
538 fprintf(ofp, "\n");
539 }
540
541 /*
542 * Find context numerical value from string.
543 *
544 * Return -1 if not found.
545 */
546 static int find_ctx_type_idx(const char *opt)
547 {
548 int ret, i = 0;
549
550 while (ctx_opts[i].symbol != NULL) {
551 if (strcmp(opt, ctx_opts[i].symbol) == 0) {
552 ret = i;
553 goto end;
554 }
555 i++;
556 }
557
558 ret = -1;
559 end:
560 return ret;
561 }
562
563 static
564 enum lttng_domain_type get_domain(void)
565 {
566 if (opt_kernel) {
567 return LTTNG_DOMAIN_KERNEL;
568 } else if (opt_userspace) {
569 return LTTNG_DOMAIN_UST;
570 } else if (opt_jul) {
571 return LTTNG_DOMAIN_JUL;
572 } else if (opt_log4j) {
573 return LTTNG_DOMAIN_LOG4J;
574 } else {
575 assert(0);
576 }
577 }
578
579 /*
580 * Add context to channel or event.
581 */
582 static int add_context(char *session_name)
583 {
584 int ret = CMD_SUCCESS, warn = 0, success = 0;
585 struct lttng_event_context context;
586 struct lttng_domain dom;
587 struct ctx_type *type;
588 char *ptr;
589
590 memset(&context, 0, sizeof(context));
591 memset(&dom, 0, sizeof(dom));
592
593 dom.type = get_domain();
594 handle = lttng_create_handle(session_name, &dom);
595 if (handle == NULL) {
596 ret = CMD_ERROR;
597 goto error;
598 }
599
600 if (lttng_opt_mi) {
601 /* Open a contexts element */
602 ret = mi_lttng_writer_open_element(writer, config_element_contexts);
603 if (ret) {
604 goto error;
605 }
606 }
607
608 /* Iterate over all the context types given */
609 cds_list_for_each_entry(type, &ctx_type_list.head, list) {
610 context.ctx = (enum lttng_event_context_type) type->opt->ctx_type;
611 switch (context.ctx) {
612 case LTTNG_EVENT_CONTEXT_PERF_COUNTER:
613 case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER:
614 case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER:
615 context.u.perf_counter.type = type->opt->u.perf.type;
616 context.u.perf_counter.config = type->opt->u.perf.config;
617 strncpy(context.u.perf_counter.name, type->opt->symbol,
618 LTTNG_SYMBOL_NAME_LEN);
619 context.u.perf_counter.name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
620 /* Replace : and - by _ */
621 while ((ptr = strchr(context.u.perf_counter.name, '-')) != NULL) {
622 *ptr = '_';
623 }
624 while ((ptr = strchr(context.u.perf_counter.name, ':')) != NULL) {
625 *ptr = '_';
626 }
627 break;
628 case LTTNG_EVENT_CONTEXT_APP_CONTEXT:
629 context.u.app_ctx.provider_name =
630 type->opt->u.app_ctx.provider_name;
631 context.u.app_ctx.ctx_name =
632 type->opt->u.app_ctx.ctx_name;
633 break;
634 default:
635 break;
636 }
637 DBG("Adding context...");
638
639 if (lttng_opt_mi) {
640 /* We leave context open the update the success of the command */
641 ret = mi_lttng_context(writer, &context, 1);
642 if (ret) {
643 ret = CMD_ERROR;
644 goto error;
645 }
646 }
647
648 ret = lttng_add_context(handle, &context, NULL, opt_channel_name);
649 if (ret < 0) {
650 ERR("%s: %s", type->opt->symbol, lttng_strerror(ret));
651 warn = 1;
652 success = 0;
653 } else {
654 if (opt_channel_name) {
655 MSG("%s context %s added to channel %s",
656 opt_kernel ? "kernel" : "UST", type->opt->symbol,
657 opt_channel_name);
658 } else {
659 MSG("%s context %s added to all channels",
660 opt_kernel ? "kernel" : "UST", type->opt->symbol)
661 }
662 success = 1;
663 }
664
665 if (lttng_opt_mi) {
666 /* Is the single operation a success ? */
667 ret = mi_lttng_writer_write_element_bool(writer,
668 mi_lttng_element_success, success);
669 if (ret) {
670 ret = CMD_ERROR;
671 goto error;
672 }
673
674 /* Close the context element */
675 ret = mi_lttng_writer_close_element(writer);
676 if (ret) {
677 ret = CMD_ERROR;
678 goto error;
679 }
680 }
681 }
682
683 if (lttng_opt_mi) {
684 /* Close contexts element */
685 ret = mi_lttng_writer_close_element(writer);
686 if (ret) {
687 goto error;
688 }
689 }
690
691 ret = CMD_SUCCESS;
692
693 error:
694 lttng_destroy_handle(handle);
695
696 /*
697 * This means that at least one add_context failed and tells the user to
698 * look on stderr for error(s).
699 */
700 if (!ret && warn) {
701 ret = CMD_WARNING;
702 }
703 return ret;
704 }
705
706 static
707 void destroy_ctx_type(struct ctx_type *type)
708 {
709 if (!type) {
710 return;
711 }
712 free(type->opt->symbol);
713 free(type->opt);
714 free(type);
715 }
716
717 static
718 struct ctx_type *create_ctx_type(void)
719 {
720 struct ctx_type *type = zmalloc(sizeof(*type));
721
722 if (!type) {
723 PERROR("malloc ctx_type");
724 goto end;
725 }
726
727 type->opt = zmalloc(sizeof(*type->opt));
728 if (!type->opt) {
729 PERROR("malloc ctx_type options");
730 destroy_ctx_type(type);
731 type = NULL;
732 goto end;
733 }
734 end:
735 return type;
736 }
737
738 static
739 struct ctx_type *get_context_type(const char *ctx)
740 {
741 int opt_index;
742 struct ctx_type *type = NULL;
743 const char app_ctx_prefix[] = "$app.";
744 char *provider_name = NULL, *ctx_name = NULL;
745 size_t i, len, colon_pos = 0, provider_name_len, ctx_name_len;
746
747 if (!ctx) {
748 goto not_found;
749 }
750
751 type = create_ctx_type();
752 if (!type) {
753 goto not_found;
754 }
755
756 /* Check if ctx matches a known static context. */
757 opt_index = find_ctx_type_idx(ctx);
758 if (opt_index >= 0) {
759 *type->opt = ctx_opts[opt_index];
760 type->opt->symbol = strdup(ctx_opts[opt_index].symbol);
761 goto found;
762 }
763
764 /*
765 * No match found against static contexts; check if it is an app
766 * context.
767 */
768 len = strlen(ctx);
769 if (len <= sizeof(app_ctx_prefix) - 1) {
770 goto not_found;
771 }
772
773 /* String starts with $app. */
774 if (strncmp(ctx, app_ctx_prefix, sizeof(app_ctx_prefix) - 1)) {
775 goto not_found;
776 }
777
778 /* Validate that the ':' separator is present. */
779 for (i = sizeof(app_ctx_prefix); i < len; i++) {
780 const char c = ctx[i];
781
782 if (c == ':') {
783 colon_pos = i;
784 break;
785 }
786 }
787
788 /*
789 * No colon found or no ctx name ("$app.provider:") or no provider name
790 * given ("$app.:..."), which is invalid.
791 */
792 if (!colon_pos || colon_pos == len ||
793 colon_pos == sizeof(app_ctx_prefix)) {
794 ERR("Invalid application context provided: no provider or context name provided.");
795 goto not_found;
796 }
797
798 provider_name_len = colon_pos - sizeof(app_ctx_prefix) + 2;
799 provider_name = zmalloc(provider_name_len);
800 if (!provider_name) {
801 PERROR("malloc provider_name");
802 goto not_found;
803 }
804 strncpy(provider_name, ctx + sizeof(app_ctx_prefix) - 1,
805 provider_name_len - 1);
806 type->opt->u.app_ctx.provider_name = provider_name;
807
808 ctx_name_len = len - colon_pos;
809 ctx_name = zmalloc(ctx_name_len);
810 if (!ctx_name) {
811 PERROR("malloc ctx_name");
812 goto not_found;
813 }
814 strncpy(ctx_name, ctx + colon_pos + 1, ctx_name_len - 1);
815 type->opt->u.app_ctx.ctx_name = ctx_name;
816 type->opt->ctx_type = CONTEXT_APP_CONTEXT;
817 type->opt->symbol = strdup(ctx);
818 found:
819 return type;
820 not_found:
821 free(provider_name);
822 free(ctx_name);
823 destroy_ctx_type(type);
824 return NULL;
825 }
826
827 /*
828 * Add context to channel or event.
829 */
830 int cmd_add_context(int argc, const char **argv)
831 {
832 int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
833 int success = 1;
834 static poptContext pc;
835 struct ctx_type *type, *tmptype;
836 char *session_name = NULL;
837
838 if (argc < 2) {
839 usage(stderr);
840 ret = CMD_ERROR;
841 goto end;
842 }
843
844 pc = poptGetContext(NULL, argc, argv, long_options, 0);
845 poptReadDefaultConfig(pc, 0);
846
847 while ((opt = poptGetNextOpt(pc)) != -1) {
848 switch (opt) {
849 case OPT_HELP:
850 usage(stdout);
851 goto end;
852 case OPT_TYPE:
853 {
854 type = get_context_type(opt_type);
855 if (!type) {
856 ERR("Unknown context type %s", opt_type);
857 ret = CMD_FATAL;
858 goto end;
859 }
860 cds_list_add_tail(&type->list, &ctx_type_list.head);
861 break;
862 }
863 case OPT_USERSPACE:
864 opt_userspace = 1;
865 break;
866 case OPT_JUL:
867 opt_jul = 1;
868 break;
869 case OPT_LOG4J:
870 opt_log4j = 1;
871 break;
872 case OPT_LIST_OPTIONS:
873 list_cmd_options(stdout, long_options);
874 goto end;
875 default:
876 usage(stderr);
877 ret = CMD_UNDEFINED;
878 goto end;
879 }
880 }
881
882 ret = print_missing_or_multiple_domains(opt_kernel + opt_userspace +
883 opt_jul + opt_log4j);
884 if (ret) {
885 ret = CMD_ERROR;
886 goto end;
887 }
888
889 if (!opt_type) {
890 ERR("Missing mandatory -t TYPE");
891 usage(stderr);
892 ret = CMD_ERROR;
893 goto end;
894 }
895
896 if (!opt_session_name) {
897 session_name = get_session_name();
898 if (session_name == NULL) {
899 ret = CMD_ERROR;
900 goto end;
901 }
902 } else {
903 session_name = opt_session_name;
904 }
905
906 /* Mi check */
907 if (lttng_opt_mi) {
908 writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
909 if (!writer) {
910 ret = -LTTNG_ERR_NOMEM;
911 goto end;
912 }
913
914 /* Open command element */
915 ret = mi_lttng_writer_command_open(writer,
916 mi_lttng_element_command_add_context);
917 if (ret) {
918 ret = CMD_ERROR;
919 goto end;
920 }
921
922 /* Open output element */
923 ret = mi_lttng_writer_open_element(writer,
924 mi_lttng_element_command_output);
925 if (ret) {
926 ret = CMD_ERROR;
927 goto end;
928 }
929 }
930
931 command_ret = add_context(session_name);
932 if (command_ret) {
933 success = 0;
934 }
935
936 /* Mi closing */
937 if (lttng_opt_mi) {
938 /* Close output element */
939 ret = mi_lttng_writer_close_element(writer);
940 if (ret) {
941 ret = CMD_ERROR;
942 goto end;
943 }
944
945 /* Success ? */
946 ret = mi_lttng_writer_write_element_bool(writer,
947 mi_lttng_element_command_success, success);
948 if (ret) {
949 ret = CMD_ERROR;
950 goto end;
951 }
952
953 /* Command element close */
954 ret = mi_lttng_writer_command_close(writer);
955 if (ret) {
956 ret = CMD_ERROR;
957 goto end;
958 }
959 }
960
961 end:
962 if (!opt_session_name) {
963 free(session_name);
964 }
965
966 /* Mi clean-up */
967 if (writer && mi_lttng_writer_destroy(writer)) {
968 /* Preserve original error code */
969 ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
970 }
971
972 /* Cleanup allocated memory */
973 cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
974 destroy_ctx_type(type);
975 }
976
977 /* Overwrite ret if an error occurred during add_context() */
978 ret = command_ret ? command_ret : ret;
979
980 poptFreeContext(pc);
981 return ret;
982 }
This page took 0.082514 seconds and 4 git commands to generate.