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