18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * db-export.c: Support for exporting data suitable for import to a database
48c2ecf20Sopenharmony_ci * Copyright (c) 2014, Intel Corporation.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <errno.h>
88c2ecf20Sopenharmony_ci#include <stdlib.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "dso.h"
118c2ecf20Sopenharmony_ci#include "evsel.h"
128c2ecf20Sopenharmony_ci#include "machine.h"
138c2ecf20Sopenharmony_ci#include "thread.h"
148c2ecf20Sopenharmony_ci#include "comm.h"
158c2ecf20Sopenharmony_ci#include "symbol.h"
168c2ecf20Sopenharmony_ci#include "map.h"
178c2ecf20Sopenharmony_ci#include "event.h"
188c2ecf20Sopenharmony_ci#include "thread-stack.h"
198c2ecf20Sopenharmony_ci#include "callchain.h"
208c2ecf20Sopenharmony_ci#include "call-path.h"
218c2ecf20Sopenharmony_ci#include "db-export.h"
228c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ciint db_export__init(struct db_export *dbe)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	memset(dbe, 0, sizeof(struct db_export));
278c2ecf20Sopenharmony_ci	return 0;
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_civoid db_export__exit(struct db_export *dbe)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	call_return_processor__free(dbe->crp);
338c2ecf20Sopenharmony_ci	dbe->crp = NULL;
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciint db_export__evsel(struct db_export *dbe, struct evsel *evsel)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	if (evsel->db_id)
398c2ecf20Sopenharmony_ci		return 0;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	evsel->db_id = ++dbe->evsel_last_db_id;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (dbe->export_evsel)
448c2ecf20Sopenharmony_ci		return dbe->export_evsel(dbe, evsel);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	return 0;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciint db_export__machine(struct db_export *dbe, struct machine *machine)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	if (machine->db_id)
528c2ecf20Sopenharmony_ci		return 0;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	machine->db_id = ++dbe->machine_last_db_id;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (dbe->export_machine)
578c2ecf20Sopenharmony_ci		return dbe->export_machine(dbe, machine);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	return 0;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ciint db_export__thread(struct db_export *dbe, struct thread *thread,
638c2ecf20Sopenharmony_ci		      struct machine *machine, struct thread *main_thread)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	u64 main_thread_db_id = 0;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (thread->db_id)
688c2ecf20Sopenharmony_ci		return 0;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	thread->db_id = ++dbe->thread_last_db_id;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (main_thread)
738c2ecf20Sopenharmony_ci		main_thread_db_id = main_thread->db_id;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (dbe->export_thread)
768c2ecf20Sopenharmony_ci		return dbe->export_thread(dbe, thread, main_thread_db_id,
778c2ecf20Sopenharmony_ci					  machine);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return 0;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int __db_export__comm(struct db_export *dbe, struct comm *comm,
838c2ecf20Sopenharmony_ci			     struct thread *thread)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	comm->db_id = ++dbe->comm_last_db_id;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if (dbe->export_comm)
888c2ecf20Sopenharmony_ci		return dbe->export_comm(dbe, comm, thread);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	return 0;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ciint db_export__comm(struct db_export *dbe, struct comm *comm,
948c2ecf20Sopenharmony_ci		    struct thread *thread)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	if (comm->db_id)
978c2ecf20Sopenharmony_ci		return 0;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return __db_export__comm(dbe, comm, thread);
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/*
1038c2ecf20Sopenharmony_ci * Export the "exec" comm. The "exec" comm is the program / application command
1048c2ecf20Sopenharmony_ci * name at the time it first executes. It is used to group threads for the same
1058c2ecf20Sopenharmony_ci * program. Note that the main thread pid (or thread group id tgid) cannot be
1068c2ecf20Sopenharmony_ci * used because it does not change when a new program is exec'ed.
1078c2ecf20Sopenharmony_ci */
1088c2ecf20Sopenharmony_ciint db_export__exec_comm(struct db_export *dbe, struct comm *comm,
1098c2ecf20Sopenharmony_ci			 struct thread *main_thread)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	int err;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (comm->db_id)
1148c2ecf20Sopenharmony_ci		return 0;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	err = __db_export__comm(dbe, comm, main_thread);
1178c2ecf20Sopenharmony_ci	if (err)
1188c2ecf20Sopenharmony_ci		return err;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	/*
1218c2ecf20Sopenharmony_ci	 * Record the main thread for this comm. Note that the main thread can
1228c2ecf20Sopenharmony_ci	 * have many "exec" comms because there will be a new one every time it
1238c2ecf20Sopenharmony_ci	 * exec's. An "exec" comm however will only ever have 1 main thread.
1248c2ecf20Sopenharmony_ci	 * That is different to any other threads for that same program because
1258c2ecf20Sopenharmony_ci	 * exec() will effectively kill them, so the relationship between the
1268c2ecf20Sopenharmony_ci	 * "exec" comm and non-main threads is 1-to-1. That is why
1278c2ecf20Sopenharmony_ci	 * db_export__comm_thread() is called here for the main thread, but it
1288c2ecf20Sopenharmony_ci	 * is called for non-main threads when they are exported.
1298c2ecf20Sopenharmony_ci	 */
1308c2ecf20Sopenharmony_ci	return db_export__comm_thread(dbe, comm, main_thread);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ciint db_export__comm_thread(struct db_export *dbe, struct comm *comm,
1348c2ecf20Sopenharmony_ci			   struct thread *thread)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	u64 db_id;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	db_id = ++dbe->comm_thread_last_db_id;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (dbe->export_comm_thread)
1418c2ecf20Sopenharmony_ci		return dbe->export_comm_thread(dbe, db_id, comm, thread);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	return 0;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ciint db_export__dso(struct db_export *dbe, struct dso *dso,
1478c2ecf20Sopenharmony_ci		   struct machine *machine)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	if (dso->db_id)
1508c2ecf20Sopenharmony_ci		return 0;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	dso->db_id = ++dbe->dso_last_db_id;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (dbe->export_dso)
1558c2ecf20Sopenharmony_ci		return dbe->export_dso(dbe, dso, machine);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	return 0;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ciint db_export__symbol(struct db_export *dbe, struct symbol *sym,
1618c2ecf20Sopenharmony_ci		      struct dso *dso)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	u64 *sym_db_id = symbol__priv(sym);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	if (*sym_db_id)
1668c2ecf20Sopenharmony_ci		return 0;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	*sym_db_id = ++dbe->symbol_last_db_id;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (dbe->export_symbol)
1718c2ecf20Sopenharmony_ci		return dbe->export_symbol(dbe, sym, dso);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	return 0;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
1778c2ecf20Sopenharmony_ci			  u64 *dso_db_id, u64 *sym_db_id, u64 *offset)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	int err;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (al->map) {
1828c2ecf20Sopenharmony_ci		struct dso *dso = al->map->dso;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci		err = db_export__dso(dbe, dso, al->maps->machine);
1858c2ecf20Sopenharmony_ci		if (err)
1868c2ecf20Sopenharmony_ci			return err;
1878c2ecf20Sopenharmony_ci		*dso_db_id = dso->db_id;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci		if (!al->sym) {
1908c2ecf20Sopenharmony_ci			al->sym = symbol__new(al->addr, 0, 0, 0, "unknown");
1918c2ecf20Sopenharmony_ci			if (al->sym)
1928c2ecf20Sopenharmony_ci				dso__insert_symbol(dso, al->sym);
1938c2ecf20Sopenharmony_ci		}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		if (al->sym) {
1968c2ecf20Sopenharmony_ci			u64 *db_id = symbol__priv(al->sym);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci			err = db_export__symbol(dbe, al->sym, dso);
1998c2ecf20Sopenharmony_ci			if (err)
2008c2ecf20Sopenharmony_ci				return err;
2018c2ecf20Sopenharmony_ci			*sym_db_id = *db_id;
2028c2ecf20Sopenharmony_ci			*offset = al->addr - al->sym->start;
2038c2ecf20Sopenharmony_ci		}
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	return 0;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic struct call_path *call_path_from_sample(struct db_export *dbe,
2108c2ecf20Sopenharmony_ci					       struct machine *machine,
2118c2ecf20Sopenharmony_ci					       struct thread *thread,
2128c2ecf20Sopenharmony_ci					       struct perf_sample *sample,
2138c2ecf20Sopenharmony_ci					       struct evsel *evsel)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	u64 kernel_start = machine__kernel_start(machine);
2168c2ecf20Sopenharmony_ci	struct call_path *current = &dbe->cpr->call_path;
2178c2ecf20Sopenharmony_ci	enum chain_order saved_order = callchain_param.order;
2188c2ecf20Sopenharmony_ci	int err;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (!symbol_conf.use_callchain || !sample->callchain)
2218c2ecf20Sopenharmony_ci		return NULL;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	/*
2248c2ecf20Sopenharmony_ci	 * Since the call path tree must be built starting with the root, we
2258c2ecf20Sopenharmony_ci	 * must use ORDER_CALL for call chain resolution, in order to process
2268c2ecf20Sopenharmony_ci	 * the callchain starting with the root node and ending with the leaf.
2278c2ecf20Sopenharmony_ci	 */
2288c2ecf20Sopenharmony_ci	callchain_param.order = ORDER_CALLER;
2298c2ecf20Sopenharmony_ci	err = thread__resolve_callchain(thread, &callchain_cursor, evsel,
2308c2ecf20Sopenharmony_ci					sample, NULL, NULL, PERF_MAX_STACK_DEPTH);
2318c2ecf20Sopenharmony_ci	if (err) {
2328c2ecf20Sopenharmony_ci		callchain_param.order = saved_order;
2338c2ecf20Sopenharmony_ci		return NULL;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci	callchain_cursor_commit(&callchain_cursor);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	while (1) {
2388c2ecf20Sopenharmony_ci		struct callchain_cursor_node *node;
2398c2ecf20Sopenharmony_ci		struct addr_location al;
2408c2ecf20Sopenharmony_ci		u64 dso_db_id = 0, sym_db_id = 0, offset = 0;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci		memset(&al, 0, sizeof(al));
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci		node = callchain_cursor_current(&callchain_cursor);
2458c2ecf20Sopenharmony_ci		if (!node)
2468c2ecf20Sopenharmony_ci			break;
2478c2ecf20Sopenharmony_ci		/*
2488c2ecf20Sopenharmony_ci		 * Handle export of symbol and dso for this node by
2498c2ecf20Sopenharmony_ci		 * constructing an addr_location struct and then passing it to
2508c2ecf20Sopenharmony_ci		 * db_ids_from_al() to perform the export.
2518c2ecf20Sopenharmony_ci		 */
2528c2ecf20Sopenharmony_ci		al.sym = node->ms.sym;
2538c2ecf20Sopenharmony_ci		al.map = node->ms.map;
2548c2ecf20Sopenharmony_ci		al.maps = thread->maps;
2558c2ecf20Sopenharmony_ci		al.addr = node->ip;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci		if (al.map && !al.sym)
2588c2ecf20Sopenharmony_ci			al.sym = dso__find_symbol(al.map->dso, al.addr);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci		db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		/* add node to the call path tree if it doesn't exist */
2638c2ecf20Sopenharmony_ci		current = call_path__findnew(dbe->cpr, current,
2648c2ecf20Sopenharmony_ci					     al.sym, node->ip,
2658c2ecf20Sopenharmony_ci					     kernel_start);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci		callchain_cursor_advance(&callchain_cursor);
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	/* Reset the callchain order to its prior value. */
2718c2ecf20Sopenharmony_ci	callchain_param.order = saved_order;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (current == &dbe->cpr->call_path) {
2748c2ecf20Sopenharmony_ci		/* Bail because the callchain was empty. */
2758c2ecf20Sopenharmony_ci		return NULL;
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	return current;
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ciint db_export__branch_type(struct db_export *dbe, u32 branch_type,
2828c2ecf20Sopenharmony_ci			   const char *name)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	if (dbe->export_branch_type)
2858c2ecf20Sopenharmony_ci		return dbe->export_branch_type(dbe, branch_type, name);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	return 0;
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic int db_export__threads(struct db_export *dbe, struct thread *thread,
2918c2ecf20Sopenharmony_ci			      struct thread *main_thread,
2928c2ecf20Sopenharmony_ci			      struct machine *machine, struct comm **comm_ptr)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct comm *comm = NULL;
2958c2ecf20Sopenharmony_ci	struct comm *curr_comm;
2968c2ecf20Sopenharmony_ci	int err;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (main_thread) {
2998c2ecf20Sopenharmony_ci		/*
3008c2ecf20Sopenharmony_ci		 * A thread has a reference to the main thread, so export the
3018c2ecf20Sopenharmony_ci		 * main thread first.
3028c2ecf20Sopenharmony_ci		 */
3038c2ecf20Sopenharmony_ci		err = db_export__thread(dbe, main_thread, machine, main_thread);
3048c2ecf20Sopenharmony_ci		if (err)
3058c2ecf20Sopenharmony_ci			return err;
3068c2ecf20Sopenharmony_ci		/*
3078c2ecf20Sopenharmony_ci		 * Export comm before exporting the non-main thread because
3088c2ecf20Sopenharmony_ci		 * db_export__comm_thread() can be called further below.
3098c2ecf20Sopenharmony_ci		 */
3108c2ecf20Sopenharmony_ci		comm = machine__thread_exec_comm(machine, main_thread);
3118c2ecf20Sopenharmony_ci		if (comm) {
3128c2ecf20Sopenharmony_ci			err = db_export__exec_comm(dbe, comm, main_thread);
3138c2ecf20Sopenharmony_ci			if (err)
3148c2ecf20Sopenharmony_ci				return err;
3158c2ecf20Sopenharmony_ci			*comm_ptr = comm;
3168c2ecf20Sopenharmony_ci		}
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (thread != main_thread) {
3208c2ecf20Sopenharmony_ci		/*
3218c2ecf20Sopenharmony_ci		 * For a non-main thread, db_export__comm_thread() must be
3228c2ecf20Sopenharmony_ci		 * called only if thread has not previously been exported.
3238c2ecf20Sopenharmony_ci		 */
3248c2ecf20Sopenharmony_ci		bool export_comm_thread = comm && !thread->db_id;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci		err = db_export__thread(dbe, thread, machine, main_thread);
3278c2ecf20Sopenharmony_ci		if (err)
3288c2ecf20Sopenharmony_ci			return err;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci		if (export_comm_thread) {
3318c2ecf20Sopenharmony_ci			err = db_export__comm_thread(dbe, comm, thread);
3328c2ecf20Sopenharmony_ci			if (err)
3338c2ecf20Sopenharmony_ci				return err;
3348c2ecf20Sopenharmony_ci		}
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	curr_comm = thread__comm(thread);
3388c2ecf20Sopenharmony_ci	if (curr_comm)
3398c2ecf20Sopenharmony_ci		return db_export__comm(dbe, curr_comm, thread);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	return 0;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ciint db_export__sample(struct db_export *dbe, union perf_event *event,
3458c2ecf20Sopenharmony_ci		      struct perf_sample *sample, struct evsel *evsel,
3468c2ecf20Sopenharmony_ci		      struct addr_location *al)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct thread *thread = al->thread;
3498c2ecf20Sopenharmony_ci	struct export_sample es = {
3508c2ecf20Sopenharmony_ci		.event = event,
3518c2ecf20Sopenharmony_ci		.sample = sample,
3528c2ecf20Sopenharmony_ci		.evsel = evsel,
3538c2ecf20Sopenharmony_ci		.al = al,
3548c2ecf20Sopenharmony_ci	};
3558c2ecf20Sopenharmony_ci	struct thread *main_thread;
3568c2ecf20Sopenharmony_ci	struct comm *comm = NULL;
3578c2ecf20Sopenharmony_ci	int err;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	err = db_export__evsel(dbe, evsel);
3608c2ecf20Sopenharmony_ci	if (err)
3618c2ecf20Sopenharmony_ci		return err;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	err = db_export__machine(dbe, al->maps->machine);
3648c2ecf20Sopenharmony_ci	if (err)
3658c2ecf20Sopenharmony_ci		return err;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	main_thread = thread__main_thread(al->maps->machine, thread);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	err = db_export__threads(dbe, thread, main_thread, al->maps->machine, &comm);
3708c2ecf20Sopenharmony_ci	if (err)
3718c2ecf20Sopenharmony_ci		goto out_put;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	if (comm)
3748c2ecf20Sopenharmony_ci		es.comm_db_id = comm->db_id;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	es.db_id = ++dbe->sample_last_db_id;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset);
3798c2ecf20Sopenharmony_ci	if (err)
3808c2ecf20Sopenharmony_ci		goto out_put;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (dbe->cpr) {
3838c2ecf20Sopenharmony_ci		struct call_path *cp = call_path_from_sample(dbe, al->maps->machine,
3848c2ecf20Sopenharmony_ci							     thread, sample,
3858c2ecf20Sopenharmony_ci							     evsel);
3868c2ecf20Sopenharmony_ci		if (cp) {
3878c2ecf20Sopenharmony_ci			db_export__call_path(dbe, cp);
3888c2ecf20Sopenharmony_ci			es.call_path_id = cp->db_id;
3898c2ecf20Sopenharmony_ci		}
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	if ((evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) &&
3938c2ecf20Sopenharmony_ci	    sample_addr_correlates_sym(&evsel->core.attr)) {
3948c2ecf20Sopenharmony_ci		struct addr_location addr_al;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci		thread__resolve(thread, &addr_al, sample);
3978c2ecf20Sopenharmony_ci		err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id,
3988c2ecf20Sopenharmony_ci				     &es.addr_sym_db_id, &es.addr_offset);
3998c2ecf20Sopenharmony_ci		if (err)
4008c2ecf20Sopenharmony_ci			goto out_put;
4018c2ecf20Sopenharmony_ci		if (dbe->crp) {
4028c2ecf20Sopenharmony_ci			err = thread_stack__process(thread, comm, sample, al,
4038c2ecf20Sopenharmony_ci						    &addr_al, es.db_id,
4048c2ecf20Sopenharmony_ci						    dbe->crp);
4058c2ecf20Sopenharmony_ci			if (err)
4068c2ecf20Sopenharmony_ci				goto out_put;
4078c2ecf20Sopenharmony_ci		}
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	if (dbe->export_sample)
4118c2ecf20Sopenharmony_ci		err = dbe->export_sample(dbe, &es);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ciout_put:
4148c2ecf20Sopenharmony_ci	thread__put(main_thread);
4158c2ecf20Sopenharmony_ci	return err;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic struct {
4198c2ecf20Sopenharmony_ci	u32 branch_type;
4208c2ecf20Sopenharmony_ci	const char *name;
4218c2ecf20Sopenharmony_ci} branch_types[] = {
4228c2ecf20Sopenharmony_ci	{0, "no branch"},
4238c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
4248c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
4258c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"},
4268c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH, "unconditional jump"},
4278c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT,
4288c2ecf20Sopenharmony_ci	 "software interrupt"},
4298c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT,
4308c2ecf20Sopenharmony_ci	 "return from interrupt"},
4318c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET,
4328c2ecf20Sopenharmony_ci	 "system call"},
4338c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET,
4348c2ecf20Sopenharmony_ci	 "return from system call"},
4358c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"},
4368c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
4378c2ecf20Sopenharmony_ci	 PERF_IP_FLAG_INTERRUPT, "hardware interrupt"},
4388c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"},
4398c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"},
4408c2ecf20Sopenharmony_ci	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"},
4418c2ecf20Sopenharmony_ci	{0, NULL}
4428c2ecf20Sopenharmony_ci};
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ciint db_export__branch_types(struct db_export *dbe)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	int i, err = 0;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	for (i = 0; branch_types[i].name ; i++) {
4498c2ecf20Sopenharmony_ci		err = db_export__branch_type(dbe, branch_types[i].branch_type,
4508c2ecf20Sopenharmony_ci					     branch_types[i].name);
4518c2ecf20Sopenharmony_ci		if (err)
4528c2ecf20Sopenharmony_ci			break;
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	/* Add trace begin / end variants */
4568c2ecf20Sopenharmony_ci	for (i = 0; branch_types[i].name ; i++) {
4578c2ecf20Sopenharmony_ci		const char *name = branch_types[i].name;
4588c2ecf20Sopenharmony_ci		u32 type = branch_types[i].branch_type;
4598c2ecf20Sopenharmony_ci		char buf[64];
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		if (type == PERF_IP_FLAG_BRANCH ||
4628c2ecf20Sopenharmony_ci		    (type & (PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END)))
4638c2ecf20Sopenharmony_ci			continue;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		snprintf(buf, sizeof(buf), "trace begin / %s", name);
4668c2ecf20Sopenharmony_ci		err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_BEGIN, buf);
4678c2ecf20Sopenharmony_ci		if (err)
4688c2ecf20Sopenharmony_ci			break;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci		snprintf(buf, sizeof(buf), "%s / trace end", name);
4718c2ecf20Sopenharmony_ci		err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_END, buf);
4728c2ecf20Sopenharmony_ci		if (err)
4738c2ecf20Sopenharmony_ci			break;
4748c2ecf20Sopenharmony_ci	}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	return err;
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ciint db_export__call_path(struct db_export *dbe, struct call_path *cp)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	int err;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (cp->db_id)
4848c2ecf20Sopenharmony_ci		return 0;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (cp->parent) {
4878c2ecf20Sopenharmony_ci		err = db_export__call_path(dbe, cp->parent);
4888c2ecf20Sopenharmony_ci		if (err)
4898c2ecf20Sopenharmony_ci			return err;
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	cp->db_id = ++dbe->call_path_last_db_id;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	if (dbe->export_call_path)
4958c2ecf20Sopenharmony_ci		return dbe->export_call_path(dbe, cp);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	return 0;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ciint db_export__call_return(struct db_export *dbe, struct call_return *cr,
5018c2ecf20Sopenharmony_ci			   u64 *parent_db_id)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	int err;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	err = db_export__call_path(dbe, cr->cp);
5068c2ecf20Sopenharmony_ci	if (err)
5078c2ecf20Sopenharmony_ci		return err;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	if (!cr->db_id)
5108c2ecf20Sopenharmony_ci		cr->db_id = ++dbe->call_return_last_db_id;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	if (parent_db_id) {
5138c2ecf20Sopenharmony_ci		if (!*parent_db_id)
5148c2ecf20Sopenharmony_ci			*parent_db_id = ++dbe->call_return_last_db_id;
5158c2ecf20Sopenharmony_ci		cr->parent_db_id = *parent_db_id;
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (dbe->export_call_return)
5198c2ecf20Sopenharmony_ci		return dbe->export_call_return(dbe, cr);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	return 0;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic int db_export__pid_tid(struct db_export *dbe, struct machine *machine,
5258c2ecf20Sopenharmony_ci			      pid_t pid, pid_t tid, u64 *db_id,
5268c2ecf20Sopenharmony_ci			      struct comm **comm_ptr, bool *is_idle)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	struct thread *thread = machine__find_thread(machine, pid, tid);
5298c2ecf20Sopenharmony_ci	struct thread *main_thread;
5308c2ecf20Sopenharmony_ci	int err = 0;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	if (!thread || !thread->comm_set)
5338c2ecf20Sopenharmony_ci		goto out_put;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	*is_idle = !thread->pid_ && !thread->tid;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	main_thread = thread__main_thread(machine, thread);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	err = db_export__threads(dbe, thread, main_thread, machine, comm_ptr);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	*db_id = thread->db_id;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	thread__put(main_thread);
5448c2ecf20Sopenharmony_ciout_put:
5458c2ecf20Sopenharmony_ci	thread__put(thread);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	return err;
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ciint db_export__switch(struct db_export *dbe, union perf_event *event,
5518c2ecf20Sopenharmony_ci		      struct perf_sample *sample, struct machine *machine)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
5548c2ecf20Sopenharmony_ci	bool out_preempt = out &&
5558c2ecf20Sopenharmony_ci		(event->header.misc & PERF_RECORD_MISC_SWITCH_OUT_PREEMPT);
5568c2ecf20Sopenharmony_ci	int flags = out | (out_preempt << 1);
5578c2ecf20Sopenharmony_ci	bool is_idle_a = false, is_idle_b = false;
5588c2ecf20Sopenharmony_ci	u64 th_a_id = 0, th_b_id = 0;
5598c2ecf20Sopenharmony_ci	u64 comm_out_id, comm_in_id;
5608c2ecf20Sopenharmony_ci	struct comm *comm_a = NULL;
5618c2ecf20Sopenharmony_ci	struct comm *comm_b = NULL;
5628c2ecf20Sopenharmony_ci	u64 th_out_id, th_in_id;
5638c2ecf20Sopenharmony_ci	u64 db_id;
5648c2ecf20Sopenharmony_ci	int err;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	err = db_export__machine(dbe, machine);
5678c2ecf20Sopenharmony_ci	if (err)
5688c2ecf20Sopenharmony_ci		return err;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	err = db_export__pid_tid(dbe, machine, sample->pid, sample->tid,
5718c2ecf20Sopenharmony_ci				 &th_a_id, &comm_a, &is_idle_a);
5728c2ecf20Sopenharmony_ci	if (err)
5738c2ecf20Sopenharmony_ci		return err;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) {
5768c2ecf20Sopenharmony_ci		pid_t pid = event->context_switch.next_prev_pid;
5778c2ecf20Sopenharmony_ci		pid_t tid = event->context_switch.next_prev_tid;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		err = db_export__pid_tid(dbe, machine, pid, tid, &th_b_id,
5808c2ecf20Sopenharmony_ci					 &comm_b, &is_idle_b);
5818c2ecf20Sopenharmony_ci		if (err)
5828c2ecf20Sopenharmony_ci			return err;
5838c2ecf20Sopenharmony_ci	}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/*
5868c2ecf20Sopenharmony_ci	 * Do not export if both threads are unknown (i.e. not being traced),
5878c2ecf20Sopenharmony_ci	 * or one is unknown and the other is the idle task.
5888c2ecf20Sopenharmony_ci	 */
5898c2ecf20Sopenharmony_ci	if ((!th_a_id || is_idle_a) && (!th_b_id || is_idle_b))
5908c2ecf20Sopenharmony_ci		return 0;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	db_id = ++dbe->context_switch_last_db_id;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	if (out) {
5958c2ecf20Sopenharmony_ci		th_out_id   = th_a_id;
5968c2ecf20Sopenharmony_ci		th_in_id    = th_b_id;
5978c2ecf20Sopenharmony_ci		comm_out_id = comm_a ? comm_a->db_id : 0;
5988c2ecf20Sopenharmony_ci		comm_in_id  = comm_b ? comm_b->db_id : 0;
5998c2ecf20Sopenharmony_ci	} else {
6008c2ecf20Sopenharmony_ci		th_out_id   = th_b_id;
6018c2ecf20Sopenharmony_ci		th_in_id    = th_a_id;
6028c2ecf20Sopenharmony_ci		comm_out_id = comm_b ? comm_b->db_id : 0;
6038c2ecf20Sopenharmony_ci		comm_in_id  = comm_a ? comm_a->db_id : 0;
6048c2ecf20Sopenharmony_ci	}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (dbe->export_context_switch)
6078c2ecf20Sopenharmony_ci		return dbe->export_context_switch(dbe, db_id, machine, sample,
6088c2ecf20Sopenharmony_ci						  th_out_id, comm_out_id,
6098c2ecf20Sopenharmony_ci						  th_in_id, comm_in_id, flags);
6108c2ecf20Sopenharmony_ci	return 0;
6118c2ecf20Sopenharmony_ci}
612