@@ -2,6 +2,7 @@ message("\n src ...")
message(STATUS "libkshark")
add_library(kshark SHARED libkshark.c
+ libkshark-json.c
libkshark-model.c
libkshark-collection.c)
new file mode 100644
@@ -0,0 +1,601 @@
+// SPDX-License-Identifier: LGPL-2.1
+
+/*
+ * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
+ */
+
+ /**
+ * @file libkshark-json.c
+ * @brief Json Confoguration I/O.
+ */
+
+// C
+/** Use GNU C Library. */
+#define _GNU_SOURCE
+#include <stdio.h>
+
+// KernelShark
+#include "libkshark.h"
+
+/**
+ * @brief Create an empty Json document and set its type description.
+ *
+ * @param type: String describing the type of the document,
+ * e.g. "kshark.record.config" or "kshark.filter.config".
+ *
+ * @returns json_object instance. Use json_object_put() to free the object.
+ */
+struct json_object *kshark_config_alloc(const char *type)
+{
+ json_object *jobj, *jtype;
+
+ jobj = json_object_new_object();
+ jtype = json_object_new_string(type);
+
+ if (!jobj || !jtype)
+ goto fail;
+
+ /* Set the type of this Json document. */
+ json_object_object_add(jobj, "type", jtype);
+
+ return jobj;
+
+ fail:
+ fprintf(stderr, "Failed to allocate memory for json_object.\n");
+ json_object_put(jobj);
+ json_object_put(jtype);
+
+ return NULL;
+}
+
+/**
+ * @brief Create an empty Record Configuration document. The type description
+ * is set to "kshark.record.config".
+ *
+ * @returns json_object instance. Use json_object_put() to free the object.
+ */
+struct json_object *kshark_record_config_alloc()
+{
+ return kshark_config_alloc("kshark.record.config");
+}
+
+/**
+ * @brief Create an empty Filter Configuration document. The type description
+ * is set to "kshark.filter.config".
+ *
+ * @returns json_object instance. Use json_object_put() to free the object.
+ */
+struct json_object *kshark_filter_config_alloc()
+{
+ return kshark_config_alloc("kshark.filter.config");;
+}
+
+/**
+ * @brief Record the current configuration of an Event Id filter into a Json
+ * document.
+ *
+ * @param pevt: Input location for the Page event.
+ * @param filter: Input location for an Id filter.
+ * @param filter_name: The name of the filter to show up in the Json document.
+ * @param jobj: Input location for the json_object instance.
+ */
+void kshark_event_filter_to_json(struct pevent *pevt,
+ struct tracecmd_filter_id *filter,
+ const char *filter_name,
+ struct json_object *jobj)
+{
+ json_object *jfilter_data, *jevent, *jsystem, *jname;
+ int i, evt, *ids;
+ char *temp;
+
+ /* Get the array of Ids to be fitered. */
+ ids = tracecmd_filter_ids(filter);
+
+ /* Create a Json array and fill the Id values into it. */
+ jfilter_data = json_object_new_array();
+ if (!jfilter_data)
+ goto fail;
+
+ for (i = 0; i < filter->count; ++i) {
+ for (evt = 0; evt < pevt->nr_events; ++evt) {
+ if (pevt->events[evt]->id == ids[i]) {
+ jevent = json_object_new_object();
+
+ temp = pevt->events[evt]->system;
+ jsystem = json_object_new_string(temp);
+
+ temp = pevt->events[evt]->name;
+ jname = json_object_new_string(temp);
+
+ if (!jevent || !jsystem || !jname)
+ goto fail;
+
+ json_object_object_add(jevent, "system",
+ jsystem);
+
+ json_object_object_add(jevent, "name",
+ jname);
+
+ json_object_array_add(jfilter_data, jevent);
+
+ break;
+ }
+ }
+ }
+
+ /* Add the array of Ids to the filter config document. */
+ json_object_object_add(jobj, filter_name, jfilter_data);
+
+ return;
+
+ fail:
+ fprintf(stderr, "Failed to allocate memory for json_object.\n");
+ json_object_put(jfilter_data);
+ json_object_put(jevent);
+ json_object_put(jsystem);
+ json_object_put(jname);
+}
+
+/**
+ * @brief Load from Json document the configuration of an Event Id filter.
+ *
+ * @param pevt: Input location for the Page event.
+ * @param filter: Input location for an Id filter.
+ * @param filter_name: The name of the filter as showing up in the Json
+ * document.
+ * @param jobj: Input location for the json_object instance.
+ *
+ * @returns True, if a filter has been loaded. If the filter configuration
+ * document contains no data for this particular filter or in a case
+ * of an error, the function returns False.
+ */
+bool kshark_event_filter_from_json(struct pevent *pevt,
+ struct tracecmd_filter_id *filter,
+ const char *filter_name,
+ struct json_object *jobj)
+{
+ json_object *jfilter, *jevent, *jsystem, *jname;
+ const char *system_str, *name_str;
+ struct event_format *event;
+ int i, length;
+
+ /*
+ * Use the name of the filter to find the array of events associated
+ * with this filter. Notice that the filter config document may
+ * contain no data for this particular filter.
+ */
+ json_object_object_get_ex(jobj, filter_name, &jfilter);
+ if (!jfilter || json_object_get_type(jfilter) != json_type_array)
+ return false;
+
+ /* Set the filter. */
+ length = json_object_array_length(jfilter);
+ for (i = 0; i < length; ++i) {
+ jevent = json_object_array_get_idx(jfilter, i);
+
+ json_object_object_get_ex(jevent, "system", &jsystem);
+ json_object_object_get_ex(jevent, "name", &jname);
+ if (!jsystem || !jname)
+ goto fail;
+
+ system_str = json_object_get_string(jsystem);
+ name_str = json_object_get_string(jname);
+
+ event = pevent_find_event_by_name(pevt, system_str, name_str);
+ if (!event)
+ goto fail;
+
+ tracecmd_filter_id_add(filter, event->id);
+ }
+
+ return true;
+
+ fail:
+ fprintf(stderr, "Failed to load event filter from json_object.\n");
+ return false;
+}
+
+static void kshark_task_filter_to_json(struct tracecmd_filter_id *filter,
+ const char *filter_name,
+ struct json_object *jobj)
+{
+ json_object *jfilter_data, *jpid;
+ int i, *ids;
+
+ /* Get the array of Ids to be fitered. */
+ ids = tracecmd_filter_ids(filter);
+
+ /* Create a Json array and fill the Id values into it. */
+ jfilter_data = json_object_new_array();
+ if (!jfilter_data)
+ goto fail;
+
+ for (i = 0; i < filter->count; ++i) {
+ jpid = json_object_new_int(ids[i]);
+ if (!jpid)
+ goto fail;
+
+ json_object_array_add(jfilter_data, jpid);
+ }
+
+ /* Add the array of Ids to the filter config document. */
+ json_object_object_add(jobj, filter_name, jfilter_data);
+
+ return;
+
+ fail:
+ fprintf(stderr, "Failed to allocate memory for json_object.\n");
+ json_object_put(jfilter_data);
+ json_object_put(jpid);
+}
+
+static bool kshark_task_filter_from_json(struct tracecmd_filter_id *filter,
+ const char *filter_name,
+ struct json_object *jobj)
+{
+ json_object *jfilter, *jpid;
+ int i, length;
+
+ /*
+ * Use the name of the filter to find the array of events associated
+ * with this filter. Notice that the filter config document may
+ * contain no data for this particular filter.
+ */
+ json_object_object_get_ex(jobj, filter_name, &jfilter);
+ if (!jfilter || json_object_get_type(jfilter) != json_type_array)
+ return false;
+
+ /* Set the filter. */
+ length = json_object_array_length(jfilter);
+ for (i = 0; i < length; ++i) {
+ jpid = json_object_array_get_idx(jfilter, i);
+ if (!jpid)
+ goto fail;
+
+ tracecmd_filter_id_add(filter, json_object_get_int(jpid));
+ }
+
+ return true;
+
+ fail:
+ fprintf(stderr, "Failed to load task filter from json_object.\n");
+ return false;
+}
+
+/**
+ * @brief Record the current configuration of the advanced filter into a Json
+ * document.
+ *
+ * @param kshark_ctx: Input location for session context pointer.
+ * @param jobj: Input location for the json_object instance.
+ */
+void kshark_adv_filters_to_json(struct kshark_context *kshark_ctx,
+ struct json_object *jobj)
+{
+ struct event_filter *adv_filter = kshark_ctx->advanced_event_filter;
+ json_object *jfilter_data, *jevent, *jsystem, *jname, *jfilter;
+ struct event_format **events;
+ char *str;
+ int i;
+
+ if (!kshark_ctx->advanced_event_filter->filters)
+ return;
+
+ /* Create a Json array and fill the Id values into it. */
+ jfilter_data = json_object_new_array();
+ if (!jfilter_data)
+ goto fail;
+
+ events = pevent_list_events(kshark_ctx->pevent, EVENT_SORT_SYSTEM);
+
+ for (i = 0; events[i]; i++) {
+ str = pevent_filter_make_string(adv_filter,
+ events[i]->id);
+ if (!str)
+ continue;
+
+ jevent = json_object_new_object();
+ jsystem = json_object_new_string(events[i]->system);
+ jname = json_object_new_string(events[i]->name);
+ jfilter = json_object_new_string(str);
+ if (!jevent || !jsystem || !jname || !jfilter)
+ goto fail;
+
+ json_object_object_add(jevent, "system", jsystem);
+ json_object_object_add(jevent, "name", jname);
+ json_object_object_add(jevent, "condition", jfilter);
+
+ json_object_array_add(jfilter_data, jevent);
+ }
+
+ /* Add the array of advanced filters to the filter config document. */
+ json_object_object_add(jobj, "adv event filter", jfilter_data);
+
+ return;
+
+ fail:
+ fprintf(stderr, "Failed to allocate memory for json_object.\n");
+ json_object_put(jfilter_data);
+ json_object_put(jevent);
+ json_object_put(jsystem);
+ json_object_put(jname);
+ json_object_put(jfilter);
+}
+
+/**
+ * @brief Load from Json document the configuration of the advanced filter.
+ *
+ * @param kshark_ctx: Input location for session context pointer.
+ * @param jobj: Input location for the json_object instance.
+ *
+ * @returns True, if a filter has been loaded. If the filter configuration
+ * document contains no data for this particular filter or in a case
+ * of an error, the function returns False.
+ */
+bool kshark_adv_filters_from_json(struct kshark_context *kshark_ctx,
+ struct json_object *jobj)
+{
+ struct event_filter *adv_filter = kshark_ctx->advanced_event_filter;
+ json_object *jfilter, *jsystem, *jname, *jcond;
+ int i, length, ret;
+ char *filter_str;
+
+ /*
+ * Use the name of the filter to find the array of events associated
+ * with this filter. Notice that the filter config document may
+ * contain no data for this particular filter.
+ */
+ json_object_object_get_ex(jobj, "adv event filter", &jfilter);
+ if (!jfilter || json_object_get_type(jfilter) != json_type_array) {
+ return false;
+ }
+
+ /* Set the filter. */
+ length = json_object_array_length(jfilter);
+ for (i = 0; i < length; ++i) {
+ jfilter = json_object_array_get_idx(jfilter, i);
+ json_object_object_get_ex(jfilter, "system", &jsystem);
+ json_object_object_get_ex(jfilter, "name", &jname);
+ json_object_object_get_ex(jfilter, "condition", &jcond);
+ if (!jsystem || !jname || !jcond)
+ goto fail;
+
+ asprintf(&filter_str, "%s/%s:%s",
+ json_object_get_string(jsystem),
+ json_object_get_string(jname),
+ json_object_get_string(jcond));
+
+ ret = pevent_filter_add_filter_str(adv_filter,
+ filter_str);
+ if (ret < 0)
+ goto fail;
+ }
+
+ return true;
+
+ fail:
+ fprintf(stderr, "Failed to laod Advanced filters.\n");
+ char error_str[200];
+ int error_status =
+ pevent_strerror(kshark_ctx->pevent, ret, error_str,
+ sizeof(error_str));
+
+ if (error_status == 0)
+ fprintf(stderr, "filter failed due to: %s\n", error_str);
+
+ free(filter_str);
+ return false;
+}
+
+static bool filter_is_set(struct tracecmd_filter_id *filter)
+{
+ return filter && filter->count;
+}
+
+/**
+ * @brief Record the current configuration of "show task" and "hide task"
+ * filters into a Json document.
+ *
+ * @param kshark_ctx: Input location for session context pointer.
+ * @param jobj: Input location for the json_object instance. If NULL a new
+ * Filter Configuration document will be created.
+ */
+void kshark_all_event_filters_to_json(struct kshark_context *kshark_ctx,
+ struct json_object **jobj)
+{
+ if (!*jobj)
+ *jobj = kshark_filter_config_alloc();
+
+ /* Save a filter only if it contains Id values. */
+ if (filter_is_set(kshark_ctx->show_event_filter))
+ kshark_event_filter_to_json(kshark_ctx->pevent,
+ kshark_ctx->show_event_filter,
+ "show event filter",
+ *jobj);
+
+ if (filter_is_set(kshark_ctx->hide_event_filter))
+ kshark_event_filter_to_json(kshark_ctx->pevent,
+ kshark_ctx->hide_event_filter,
+ "hide event filter",
+ *jobj);
+}
+
+/**
+ * @brief Record the current configuration of "show task" and "hide task"
+ * filters into a Json document.
+ *
+ * @param kshark_ctx: Input location for session context pointer.
+ * @param jobj: Input location for the json_object instance. If NULL a new
+ * Filter Configuration document will be created.
+ */
+void kshark_all_task_filters_to_json(struct kshark_context *kshark_ctx,
+ struct json_object **jobj)
+{
+ if (!*jobj)
+ *jobj = kshark_filter_config_alloc();
+
+ /* Save a filter only if it contains Id values. */
+ if (filter_is_set(kshark_ctx->show_task_filter))
+ kshark_task_filter_to_json(kshark_ctx->show_task_filter,
+ "show task filter",
+ *jobj);
+
+ if (filter_is_set(kshark_ctx->hide_task_filter))
+ kshark_task_filter_to_json(kshark_ctx->hide_task_filter,
+ "hide task filter",
+ *jobj);
+}
+
+/**
+ * @brief Load from Json document the configuration of "show event" and
+ * "hide event" filters.
+ *
+ * @param kshark_ctx: Input location for session context pointer.
+ * @param jobj: Input location for the json_object instance.
+ *
+ * @returns True, if a filter has been loaded. If the filter configuration
+ * document contains no data for any event filter or in a case
+ * of an error, the function returns False.
+ */
+bool kshark_all_event_filters_from_json(struct kshark_context *kshark_ctx,
+ struct json_object *jobj)
+{
+ bool status;
+
+ status = kshark_event_filter_from_json(kshark_ctx->pevent,
+ kshark_ctx->hide_event_filter,
+ "hide event filter",
+ jobj);
+
+ status |= kshark_event_filter_from_json(kshark_ctx->pevent,
+ kshark_ctx->show_event_filter,
+ "show event filter",
+ jobj);
+
+ return status;
+}
+
+/**
+ * @brief Load from Json document the configuration of "show task" and
+ * "hide task" filters.
+ *
+ * @param kshark_ctx: Input location for session context pointer.
+ * @param jobj: Input location for the json_object instance.
+ *
+ * @returns True, if a filter has been loaded. If the filter configuration
+ * document contains no data for any task filter or in a case of an
+ * error, the function returns False.
+ */
+bool kshark_all_task_filters_from_json(struct kshark_context *kshark_ctx,
+ struct json_object *jobj)
+{
+ bool status;
+
+ status = kshark_task_filter_from_json(kshark_ctx->hide_task_filter,
+ "hide task filter",
+ jobj);
+
+ status |= kshark_task_filter_from_json(kshark_ctx->show_task_filter,
+ "show task filter",
+ jobj);
+
+ return status;
+}
+
+/**
+ * @brief Create a Filter Configuration document containing the current
+ * configuration of all filters.
+ *
+ * @param kshark_ctx: Input location for session context pointer.
+ *
+ * @returns json_object instance. Use json_object_put() to free the object.
+ */
+struct json_object *
+kshark_all_filters_to_json(struct kshark_context *kshark_ctx)
+{
+ struct json_object *jobj;
+
+ /* Create a new Json document. */
+ jobj = kshark_filter_config_alloc();
+
+ /* Save a filter only if it contains Id values. */
+ kshark_all_event_filters_to_json(kshark_ctx, &jobj);
+ kshark_all_task_filters_to_json(kshark_ctx, &jobj);
+ kshark_adv_filters_to_json(kshark_ctx, jobj);
+
+ return jobj;
+}
+
+/**
+ * @brief Load from Json document the configuration of all filters.
+ *
+ * @param kshark_ctx: Input location for session context pointer.
+ * @param jobj: Input location for the json_object instance.
+ *
+ * @returns True, if a filter has been loaded. If the filter configuration
+ * document contains no data for any filter or in a case of an error,
+ * the function returns False.
+ */
+bool kshark_all_filters_from_json(struct kshark_context *kshark_ctx,
+ struct json_object *jobj)
+{
+ bool status;
+ status = kshark_all_task_filters_from_json(kshark_ctx, jobj);
+ status |= kshark_all_event_filters_from_json(kshark_ctx, jobj);
+ status |= kshark_adv_filters_from_json(kshark_ctx, jobj);
+
+ return status;
+}
+
+/**
+ * @brief Save a Json Configuration document into a file.
+ *
+ * @param file_name: The name of the file.
+ * @param jobj: Input location for the json_object instance.
+ */
+void kshark_save_json_file(const char *file_name,
+ struct json_object *jobj)
+{
+ int flags;
+
+ /* Save the file in a human-readable form. */
+ flags = JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY;
+ json_object_to_file_ext(file_name, jobj, flags);
+}
+
+/**
+ * @brief Open a Jason file and check if it has the expected type.
+ *
+ * @param file_name: The name of the file.
+ * @param type: String describing the expected type of the document,
+ * e.g. "kshark.record.config" or "kshark.filter.config".
+ *
+ * @returns json_object instance on success, or NULL on failure. Use
+ * json_object_put() to free the object.
+ */
+struct json_object *kshark_open_json_file(const char *file_name,
+ const char *type)
+{
+ struct json_object *jobj, *var;
+ const char *type_var;
+
+ jobj = json_object_from_file(file_name);
+
+ if (!jobj)
+ return NULL;
+
+ /* Get the type of the document. */
+ json_object_object_get_ex(jobj, "type", &var);
+ type_var = json_object_get_string(var);
+
+ if (strcmp(type, type_var) != 0) {
+ /* The document has a wrong type. */
+ fprintf(stderr, "Failed to open Json file %s\n.", file_name);
+ fprintf(stderr, "The document has a wrong type.\n");
+
+ json_object_put(jobj);
+ return NULL;
+ }
+
+ return jobj;
+}
@@ -16,6 +16,9 @@
#include <stdint.h>
#include <pthread.h>
+// Json-C
+#include <json.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -367,6 +370,52 @@ kshark_get_collection_entry_back(struct kshark_entry_request **req,
const struct kshark_entry_collection *col,
ssize_t *index);
+struct json_object *kshark_config_alloc(const char *type);
+
+struct json_object *kshark_record_config_alloc();
+
+struct json_object *kshark_filter_config_alloc();
+
+void kshark_adv_filters_to_json(struct kshark_context *kshark_ctx,
+ struct json_object *jobj);
+
+bool kshark_adv_filters_from_json(struct kshark_context *kshark_ctx,
+ struct json_object *jobj);
+
+void kshark_event_filter_to_json(struct pevent *pevt,
+ struct tracecmd_filter_id *filter,
+ const char *filter_name,
+ struct json_object *jobj);
+
+bool kshark_event_filter_from_json(struct pevent *pevt,
+ struct tracecmd_filter_id *filter,
+ const char *filter_name,
+ struct json_object *jobj);
+
+void kshark_all_event_filters_to_json(struct kshark_context *kshark_ctx,
+ struct json_object **jobj);
+
+void kshark_all_task_filters_to_json(struct kshark_context *kshark_ctx,
+ struct json_object **jobj);
+
+struct json_object *
+kshark_all_filters_to_json(struct kshark_context *kshark_ctx);
+
+bool kshark_all_event_filters_from_json(struct kshark_context *kshark_ctx,
+ struct json_object *jobj);
+
+bool kshark_all_task_filters_from_json(struct kshark_context *kshark_ctx,
+ struct json_object *jobj);
+
+bool kshark_all_filters_from_json(struct kshark_context *kshark_ctx,
+ struct json_object *jobj);
+
+void kshark_save_json_file(const char *filter_name,
+ struct json_object *jobj);
+
+struct json_object *kshark_open_json_file(const char *filter_name,
+ const char *type);
+
#ifdef __cplusplus
}
#endif
Add to the C API of KernelShark instruments for saving/loading of filter configuration to/from Json files. Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com> --- kernel-shark-qt/src/CMakeLists.txt | 1 + kernel-shark-qt/src/libkshark-json.c | 601 +++++++++++++++++++++++++++ kernel-shark-qt/src/libkshark.h | 49 +++ 3 files changed, 651 insertions(+) create mode 100644 kernel-shark-qt/src/libkshark-json.c