/*
- * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2 only,
- * as published by the Free Software Foundation.
+ * SPDX-License-Identifier: GPL-2.0-only
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define _LGPL_SOURCE
CONTEXT_PREEMPTIBLE = 17,
CONTEXT_NEED_RESCHEDULE = 18,
CONTEXT_MIGRATABLE = 19,
+ CONTEXT_CALLSTACK_KERNEL = 20,
+ CONTEXT_CALLSTACK_USER = 21,
+ CONTEXT_CGROUP_NS = 22,
+ CONTEXT_IPC_NS = 23,
+ CONTEXT_MNT_NS = 24,
+ CONTEXT_NET_NS = 25,
+ CONTEXT_PID_NS = 26,
+ CONTEXT_USER_NS = 27,
+ CONTEXT_UTS_NS = 28,
+ CONTEXT_UID = 29,
+ CONTEXT_EUID = 30,
+ CONTEXT_SUID = 31,
+ CONTEXT_GID = 32,
+ CONTEXT_EGID = 33,
+ CONTEXT_SGID = 34,
+ CONTEXT_VUID = 35,
+ CONTEXT_VEUID = 36,
+ CONTEXT_VSUID = 37,
+ CONTEXT_VGID = 38,
+ CONTEXT_VEGID = 39,
+ CONTEXT_VSGID = 40,
+ CONTEXT_TIME_NS = 41,
};
/*
*/
#define PERF_HW(optstr, name, type, hide) \
{ \
- optstr, type, hide, \
+ (char *) optstr, type, hide, \
.u.perf = { PERF_TYPE_HARDWARE, PERF_COUNT_HW_##name, },\
}
#define PERF_SW(optstr, name, type, hide) \
{ \
- optstr, type, hide, \
+ (char *) optstr, type, hide, \
.u.perf = { PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##name, },\
}
#define _PERF_HW_CACHE(optstr, name, type, op, result, hide) \
{ \
- optstr, type, hide, \
+ (char *) optstr, type, hide, \
.u.perf = { \
PERF_TYPE_HW_CACHE, \
(uint64_t) PERF_COUNT_HW_CACHE_##name \
} app_ctx;
} u;
} ctx_opts[] = {
- { "pid", CONTEXT_PID },
- { "procname", CONTEXT_PROCNAME },
- { "prio", CONTEXT_PRIO },
- { "nice", CONTEXT_NICE },
- { "vpid", CONTEXT_VPID },
- { "tid", CONTEXT_TID },
- { "pthread_id", CONTEXT_PTHREAD_ID },
- { "vtid", CONTEXT_VTID },
- { "ppid", CONTEXT_PPID },
- { "vppid", CONTEXT_VPPID },
- { "hostname", CONTEXT_HOSTNAME },
- { "ip", CONTEXT_IP },
- { "interruptible", CONTEXT_INTERRUPTIBLE },
- { "preemptible", CONTEXT_PREEMPTIBLE },
- { "need_reschedule", CONTEXT_NEED_RESCHEDULE },
- { "migratable", CONTEXT_MIGRATABLE },
+ /*
+ * These (char *) casts (as well as those in the PERF_* macros) are
+ * safe because we never free these instances of `struct ctx_opts`.
+ */
+ { (char *) "pid", CONTEXT_PID },
+ { (char *) "procname", CONTEXT_PROCNAME },
+ { (char *) "prio", CONTEXT_PRIO },
+ { (char *) "nice", CONTEXT_NICE },
+ { (char *) "vpid", CONTEXT_VPID },
+ { (char *) "tid", CONTEXT_TID },
+ { (char *) "pthread_id", CONTEXT_PTHREAD_ID },
+ { (char *) "vtid", CONTEXT_VTID },
+ { (char *) "ppid", CONTEXT_PPID },
+ { (char *) "vppid", CONTEXT_VPPID },
+ { (char *) "hostname", CONTEXT_HOSTNAME },
+ { (char *) "ip", CONTEXT_IP },
+ { (char *) "interruptible", CONTEXT_INTERRUPTIBLE },
+ { (char *) "preemptible", CONTEXT_PREEMPTIBLE },
+ { (char *) "need_reschedule", CONTEXT_NEED_RESCHEDULE },
+ { (char *) "migratable", CONTEXT_MIGRATABLE },
+ { (char *) "callstack-kernel", CONTEXT_CALLSTACK_KERNEL },
+#if HAVE_MODULES_USERSPACE_CALLSTACK_CONTEXT
+ { (char *) "callstack-user", CONTEXT_CALLSTACK_USER },
+#endif
+ { (char *) "cgroup_ns", CONTEXT_CGROUP_NS },
+ { (char *) "ipc_ns", CONTEXT_IPC_NS },
+ { (char *) "mnt_ns", CONTEXT_MNT_NS },
+ { (char *) "net_ns", CONTEXT_NET_NS },
+ { (char *) "pid_ns", CONTEXT_PID_NS },
+ { (char *) "time_ns", CONTEXT_TIME_NS },
+ { (char *) "user_ns", CONTEXT_USER_NS },
+ { (char *) "uts_ns", CONTEXT_UTS_NS },
+ { (char *) "uid", CONTEXT_UID },
+ { (char *) "euid", CONTEXT_EUID },
+ { (char *) "suid", CONTEXT_SUID },
+ { (char *) "gid", CONTEXT_GID },
+ { (char *) "egid", CONTEXT_EGID },
+ { (char *) "sgid", CONTEXT_SGID },
+ { (char *) "vuid", CONTEXT_VUID },
+ { (char *) "veuid", CONTEXT_VEUID },
+ { (char *) "vsuid", CONTEXT_VSUID },
+ { (char *) "vgid", CONTEXT_VGID },
+ { (char *) "vegid", CONTEXT_VEGID },
+ { (char *) "vsgid", CONTEXT_VSGID },
/* Perf options */
.head = CDS_LIST_HEAD_INIT(ctx_type_list.head),
};
-/*
- * Pretty print context type.
- */
-static void print_ctx_type(FILE *ofp)
-{
- int i = 0;
- while (ctx_opts[i].symbol != NULL) {
- if (!ctx_opts[i].hide_help) {
- fprintf(ofp, "%s\n", ctx_opts[i].symbol);
- }
- i++;
- }
-}
/*
* Find context numerical value from string.
}
}
+static
+int mi_open(void)
+{
+ int ret;
+
+ /* MI check */
+ if (!lttng_opt_mi) {
+ ret = 0;
+ goto end;
+ }
+
+ ret = fileno(stdout);
+ if (ret < 0) {
+ PERROR("Unable to retrieve fileno of stdout");
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ writer = mi_lttng_writer_create(ret, lttng_opt_mi);
+ if (!writer) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ /* Open command element */
+ ret = mi_lttng_writer_command_open(writer,
+ mi_lttng_element_command_add_context);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ /* Open output element */
+ ret = mi_lttng_writer_open_element(writer,
+ mi_lttng_element_command_output);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+end:
+ return ret;
+}
+
+static
+int mi_close(enum cmd_error_code success)
+{
+ int ret;
+
+ /* MI closing */
+ if (!lttng_opt_mi) {
+ ret = 0;
+ goto end;
+ }
+ /* Close output element */
+ ret = mi_lttng_writer_close_element(writer);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ /* Success ? */
+ ret = mi_lttng_writer_write_element_bool(writer,
+ mi_lttng_element_command_success, !success);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ /* Command element close */
+ ret = mi_lttng_writer_command_close(writer);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+end:
+ return ret;
+}
+
+static
+void populate_context(struct lttng_event_context *context,
+ const struct ctx_opts *opt)
+{
+ char *ptr;
+
+ context->ctx = (enum lttng_event_context_type) opt->ctx_type;
+ switch (context->ctx) {
+ case LTTNG_EVENT_CONTEXT_PERF_COUNTER:
+ case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER:
+ case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER:
+ context->u.perf_counter.type = opt->u.perf.type;
+ context->u.perf_counter.config = opt->u.perf.config;
+ strncpy(context->u.perf_counter.name, opt->symbol,
+ LTTNG_SYMBOL_NAME_LEN);
+ context->u.perf_counter.name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
+ /* Replace : and - by _ */
+ while ((ptr = strchr(context->u.perf_counter.name, '-')) != NULL) {
+ *ptr = '_';
+ }
+ while ((ptr = strchr(context->u.perf_counter.name, ':')) != NULL) {
+ *ptr = '_';
+ }
+ break;
+ case LTTNG_EVENT_CONTEXT_APP_CONTEXT:
+ context->u.app_ctx.provider_name =
+ opt->u.app_ctx.provider_name;
+ context->u.app_ctx.ctx_name =
+ opt->u.app_ctx.ctx_name;
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * Pretty print context type.
+ */
+static
+int print_ctx_type(void)
+{
+
+ FILE *ofp = stdout;
+ int i = 0;
+ int ret;
+ struct lttng_event_context context;
+
+ memset(&context, 0, sizeof(context));
+
+ ret = mi_open();
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ if (lttng_opt_mi) {
+ /* Open a contexts element */
+ ret = mi_lttng_writer_open_element(writer, config_element_contexts);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+ }
+
+ while (ctx_opts[i].symbol != NULL) {
+ if (!ctx_opts[i].hide_help) {
+ if (lttng_opt_mi) {
+ populate_context(&context, &ctx_opts[i]);
+ ret = mi_lttng_context(writer, &context, 1);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ ret = mi_lttng_writer_write_element_string(
+ writer,
+ mi_lttng_element_context_symbol,
+ ctx_opts[i].symbol);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ ret = mi_lttng_writer_close_element(writer);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto end;
+ }
+ } else {
+ fprintf(ofp, "%s\n", ctx_opts[i].symbol);
+ }
+ }
+ i++;
+ }
+
+ if (lttng_opt_mi) {
+ /* Close contexts element */
+ ret = mi_lttng_writer_close_element(writer);
+ if (ret) {
+ goto end;
+ }
+ }
+
+end:
+ ret = mi_close(ret);
+ if (ret) {
+ ret = CMD_ERROR;
+ }
+ return ret;
+}
+
/*
* Add context to channel or event.
*/
struct lttng_event_context context;
struct lttng_domain dom;
struct ctx_type *type;
- char *ptr;
memset(&context, 0, sizeof(context));
memset(&dom, 0, sizeof(dom));
/* Iterate over all the context types given */
cds_list_for_each_entry(type, &ctx_type_list.head, list) {
- context.ctx = (enum lttng_event_context_type) type->opt->ctx_type;
- switch (context.ctx) {
- case LTTNG_EVENT_CONTEXT_PERF_COUNTER:
- case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER:
- case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER:
- context.u.perf_counter.type = type->opt->u.perf.type;
- context.u.perf_counter.config = type->opt->u.perf.config;
- strncpy(context.u.perf_counter.name, type->opt->symbol,
- LTTNG_SYMBOL_NAME_LEN);
- context.u.perf_counter.name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
- /* Replace : and - by _ */
- while ((ptr = strchr(context.u.perf_counter.name, '-')) != NULL) {
- *ptr = '_';
- }
- while ((ptr = strchr(context.u.perf_counter.name, ':')) != NULL) {
- *ptr = '_';
- }
- break;
- case LTTNG_EVENT_CONTEXT_APP_CONTEXT:
- context.u.app_ctx.provider_name =
- type->opt->u.app_ctx.provider_name;
- context.u.app_ctx.ctx_name =
- type->opt->u.app_ctx.ctx_name;
- break;
- default:
- break;
- }
DBG("Adding context...");
+ populate_context(&context, type->opt);
+
if (lttng_opt_mi) {
/* We leave context open the update the success of the command */
ret = mi_lttng_context(writer, &context, 1);
ret = CMD_ERROR;
goto error;
}
+
+ ret = mi_lttng_writer_write_element_string(writer,
+ mi_lttng_element_context_symbol,
+ type->opt->symbol);
+ if (ret) {
+ ret = CMD_ERROR;
+ goto error;
+ }
}
ret = lttng_add_context(handle, &context, NULL, opt_channel_name);
int cmd_add_context(int argc, const char **argv)
{
int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
- int success = 1;
static poptContext pc;
struct ctx_type *type, *tmptype;
char *session_name = NULL;
+ const char *leftover = NULL;
if (argc < 2) {
ret = CMD_ERROR;
SHOW_HELP();
goto end;
case OPT_LIST:
- print_ctx_type(stdout);
+ ret = print_ctx_type();
goto end;
case OPT_TYPE:
{
}
}
- ret = print_missing_or_multiple_domains(opt_kernel + opt_userspace +
- opt_jul + opt_log4j);
+ leftover = poptGetArg(pc);
+ if (leftover) {
+ ERR("Unknown argument: %s", leftover);
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ ret = print_missing_or_multiple_domains(
+ opt_kernel + opt_userspace + opt_jul + opt_log4j, true);
if (ret) {
ret = CMD_ERROR;
goto end;
session_name = opt_session_name;
}
- /* Mi check */
- if (lttng_opt_mi) {
- writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
- if (!writer) {
- ret = -LTTNG_ERR_NOMEM;
- goto end;
- }
-
- /* Open command element */
- ret = mi_lttng_writer_command_open(writer,
- mi_lttng_element_command_add_context);
- if (ret) {
- ret = CMD_ERROR;
- goto end;
- }
-
- /* Open output element */
- ret = mi_lttng_writer_open_element(writer,
- mi_lttng_element_command_output);
- if (ret) {
- ret = CMD_ERROR;
- goto end;
- }
+ ret = mi_open();
+ if (ret) {
+ goto end;
}
command_ret = add_context(session_name);
- if (command_ret) {
- success = 0;
- }
-
- /* Mi closing */
- if (lttng_opt_mi) {
- /* Close output element */
- ret = mi_lttng_writer_close_element(writer);
- if (ret) {
- ret = CMD_ERROR;
- goto end;
- }
-
- /* Success ? */
- ret = mi_lttng_writer_write_element_bool(writer,
- mi_lttng_element_command_success, success);
- if (ret) {
- ret = CMD_ERROR;
- goto end;
- }
-
- /* Command element close */
- ret = mi_lttng_writer_command_close(writer);
- if (ret) {
- ret = CMD_ERROR;
- goto end;
- }
+ ret = mi_close(command_ret);
+ if (ret) {
+ goto end;
}
end: