162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <stdio.h>
362306a36Sopenharmony_ci#include <unistd.h>
462306a36Sopenharmony_ci#include <stdlib.h>
562306a36Sopenharmony_ci#include <errno.h>
662306a36Sopenharmony_ci#include <sys/types.h>
762306a36Sopenharmony_ci#include <sys/stat.h>
862306a36Sopenharmony_ci#include <fcntl.h>
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <traceevent/event-parse.h>
1262306a36Sopenharmony_ci#include <api/fs/tracing_path.h>
1362306a36Sopenharmony_ci#include <api/fs/fs.h>
1462306a36Sopenharmony_ci#include "trace-event.h"
1562306a36Sopenharmony_ci#include "machine.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * global trace_event object used by trace_event__tp_format
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * TODO There's no cleanup call for this. Add some sort of
2162306a36Sopenharmony_ci * __exit function support and call trace_event__cleanup
2262306a36Sopenharmony_ci * there.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_cistatic struct trace_event tevent;
2562306a36Sopenharmony_cistatic bool tevent_initialized;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciint trace_event__init(struct trace_event *t)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct tep_handle *pevent = tep_alloc();
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	if (pevent) {
3262306a36Sopenharmony_ci		t->plugin_list = tep_load_plugins(pevent);
3362306a36Sopenharmony_ci		t->pevent  = pevent;
3462306a36Sopenharmony_ci	}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	return pevent ? 0 : -1;
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic int trace_event__init2(void)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	int be = tep_is_bigendian();
4262306a36Sopenharmony_ci	struct tep_handle *pevent;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (trace_event__init(&tevent))
4562306a36Sopenharmony_ci		return -1;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	pevent = tevent.pevent;
4862306a36Sopenharmony_ci	tep_set_flag(pevent, TEP_NSEC_OUTPUT);
4962306a36Sopenharmony_ci	tep_set_file_bigendian(pevent, be);
5062306a36Sopenharmony_ci	tep_set_local_bigendian(pevent, be);
5162306a36Sopenharmony_ci	tevent_initialized = true;
5262306a36Sopenharmony_ci	return 0;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ciint trace_event__register_resolver(struct machine *machine,
5662306a36Sopenharmony_ci				   tep_func_resolver_t *func)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	if (!tevent_initialized && trace_event__init2())
5962306a36Sopenharmony_ci		return -1;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return tep_set_function_resolver(tevent.pevent, func, machine);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_civoid trace_event__cleanup(struct trace_event *t)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	tep_unload_plugins(t->plugin_list, t->pevent);
6762306a36Sopenharmony_ci	tep_free(t->pevent);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/*
7162306a36Sopenharmony_ci * Returns pointer with encoded error via <linux/err.h> interface.
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_cistatic struct tep_event*
7462306a36Sopenharmony_citp_format(const char *sys, const char *name)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	char *tp_dir = get_events_file(sys);
7762306a36Sopenharmony_ci	struct tep_handle *pevent = tevent.pevent;
7862306a36Sopenharmony_ci	struct tep_event *event = NULL;
7962306a36Sopenharmony_ci	char path[PATH_MAX];
8062306a36Sopenharmony_ci	size_t size;
8162306a36Sopenharmony_ci	char *data;
8262306a36Sopenharmony_ci	int err;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (!tp_dir)
8562306a36Sopenharmony_ci		return ERR_PTR(-errno);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	scnprintf(path, PATH_MAX, "%s/%s/format", tp_dir, name);
8862306a36Sopenharmony_ci	put_events_file(tp_dir);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	err = filename__read_str(path, &data, &size);
9162306a36Sopenharmony_ci	if (err)
9262306a36Sopenharmony_ci		return ERR_PTR(err);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	tep_parse_format(pevent, &event, data, size, sys);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	free(data);
9762306a36Sopenharmony_ci	return event;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/*
10162306a36Sopenharmony_ci * Returns pointer with encoded error via <linux/err.h> interface.
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_cistruct tep_event*
10462306a36Sopenharmony_citrace_event__tp_format(const char *sys, const char *name)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	if (!tevent_initialized && trace_event__init2())
10762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return tp_format(sys, name);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistruct tep_event *trace_event__tp_format_id(int id)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	if (!tevent_initialized && trace_event__init2())
11562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return tep_find_event(tevent.pevent, id);
11862306a36Sopenharmony_ci}
119