Add the helper function that parses a trace event captured by libtraceevent in a tep handle. All the parsed fields are added to a json object. The json object is added to the provided list in the input parameter.
Tested-by: Alison Schofield <[email protected]> Signed-off-by: Dave Jiang <[email protected]> --- cxl/event_trace.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++++ cxl/event_trace.h | 14 ++++ cxl/meson.build | 2 + meson.build | 1 4 files changed, 210 insertions(+) create mode 100644 cxl/event_trace.c create mode 100644 cxl/event_trace.h diff --git a/cxl/event_trace.c b/cxl/event_trace.c new file mode 100644 index 000000000000..3c9fb684139a --- /dev/null +++ b/cxl/event_trace.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2022, Intel Corp. All rights reserved. +#include <stdio.h> +#include <errno.h> +#include <json-c/json.h> +#include <util/json.h> +#include <util/util.h> +#include <util/strbuf.h> +#include <ccan/list/list.h> +#include <uuid/uuid.h> +#include <traceevent/event-parse.h> +#include "event_trace.h" + +#define _GNU_SOURCE +#include <string.h> + +static struct json_object *num_to_json(void *num, int elem_size, unsigned long flags) +{ + bool sign = flags & TEP_FIELD_IS_SIGNED; + int64_t val = 0; + + /* special case 64 bit as the call depends on sign */ + if (elem_size == 8) { + if (sign) + return json_object_new_int64(*(int64_t *)num); + else + return json_object_new_uint64(*(uint64_t *)num); + } + + /* All others fit in a signed 64 bit */ + switch (elem_size) { + case 1: + if (sign) + val = *(int8_t *)num; + else + val = *(uint8_t *)num; + break; + case 2: + if (sign) + val = *(int16_t *)num; + else + val = *(uint16_t *)num; + break; + case 4: + if (sign) + val = *(int32_t *)num; + else + val = *(uint32_t *)num; + break; + default: + /* + * Odd sizes are converted in the kernel to one of the above. + * It is an error to see them here. + */ + return NULL; + } + + return json_object_new_int64(val); +} + +static int cxl_event_to_json(struct tep_event *event, struct tep_record *record, + struct list_head *jlist_head) +{ + struct json_object *jevent, *jobj, *jarray; + struct tep_format_field **fields; + struct jlist_node *jnode; + int i, j, rc = 0; + + jnode = malloc(sizeof(*jnode)); + if (!jnode) + return -ENOMEM; + + jevent = json_object_new_object(); + if (!jevent) { + rc = -ENOMEM; + goto err_jnode; + } + jnode->jobj = jevent; + + fields = tep_event_fields(event); + if (!fields) { + rc = -ENOENT; + goto err_jevent; + } + + jobj = json_object_new_string(event->system); + if (!jobj) { + rc = -ENOMEM; + goto err_jevent; + } + json_object_object_add(jevent, "system", jobj); + + jobj = json_object_new_string(event->name); + if (!jobj) { + rc = -ENOMEM; + goto err_jevent; + } + json_object_object_add(jevent, "event", jobj); + + jobj = json_object_new_uint64(record->ts); + if (!jobj) { + rc = -ENOMEM; + goto err_jevent; + } + json_object_object_add(jevent, "timestamp", jobj); + + for (i = 0; fields[i]; i++) { + struct tep_format_field *f = fields[i]; + int len; + + if (f->flags & TEP_FIELD_IS_STRING) { + char *str; + + str = tep_get_field_raw(NULL, event, f->name, record, &len, 0); + if (!str) + continue; + + jobj = json_object_new_string(str); + if (!jobj) { + rc = -ENOMEM; + goto err_jevent; + } + + json_object_object_add(jevent, f->name, jobj); + } else if (f->flags & TEP_FIELD_IS_ARRAY) { + unsigned char *data; + int chunks; + + data = tep_get_field_raw(NULL, event, f->name, record, &len, 0); + if (!data) + continue; + + jarray = json_object_new_array(); + if (!jarray) { + rc = -ENOMEM; + goto err_jevent; + } + + chunks = f->size / f->elementsize; + for (j = 0; j < chunks; j++) { + jobj = num_to_json(data, f->elementsize, f->flags); + if (!jobj) { + json_object_put(jarray); + return -ENOMEM; + } + json_object_array_add(jarray, jobj); + data += f->elementsize; + } + + json_object_object_add(jevent, f->name, jarray); + } else { /* single number */ + unsigned char *data; + char *tmp; + + data = tep_get_field_raw(NULL, event, f->name, record, &len, 0); + if (!data) + continue; + + /* check to see if we have a UUID */ + tmp = strcasestr(f->type, "uuid_t"); + if (tmp) { + char uuid[40]; + + uuid_unparse(data, uuid); + jobj = json_object_new_string(uuid); + if (!jobj) { + rc = -ENOMEM; + goto err_jevent; + } + + json_object_object_add(jevent, f->name, jobj); + continue; + } + + jobj = num_to_json(data, f->elementsize, f->flags); + if (!jobj) { + rc = -ENOMEM; + goto err_jevent; + } + + json_object_object_add(jevent, f->name, jobj); + } + } + + list_add_tail(jlist_head, &jnode->list); + return 0; + +err_jevent: + json_object_put(jevent); +err_jnode: + free(jnode); + return rc; +} diff --git a/cxl/event_trace.h b/cxl/event_trace.h new file mode 100644 index 000000000000..00975a0b5680 --- /dev/null +++ b/cxl/event_trace.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2022 Intel Corporation. All rights reserved. */ +#ifndef __CXL_EVENT_TRACE_H__ +#define __CXL_EVENT_TRACE_H__ + +#include <json-c/json.h> +#include <ccan/list/list.h> + +struct jlist_node { + struct json_object *jobj; + struct list_node list; +}; + +#endif diff --git a/cxl/meson.build b/cxl/meson.build index f2474aaa6e2e..8c7733431613 100644 --- a/cxl/meson.build +++ b/cxl/meson.build @@ -7,6 +7,7 @@ cxl_src = [ 'memdev.c', 'json.c', 'filter.c', + 'event_trace.c', ] cxl_tool = executable('cxl', @@ -19,6 +20,7 @@ cxl_tool = executable('cxl', kmod, json, versiondep, + traceevent, ], install : true, install_dir : rootbindir, diff --git a/meson.build b/meson.build index 20a646d135c7..f611e0bdd7f3 100644 --- a/meson.build +++ b/meson.build @@ -142,6 +142,7 @@ kmod = dependency('libkmod') libudev = dependency('libudev') uuid = dependency('uuid') json = dependency('json-c') +traceevent = dependency('libtraceevent') if get_option('docs').enabled() if get_option('asciidoctor').enabled() asciidoc = find_program('asciidoctor', required : true)
