cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

db-export.c (14857B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * db-export.c: Support for exporting data suitable for import to a database
      4 * Copyright (c) 2014, Intel Corporation.
      5 */
      6
      7#include <errno.h>
      8#include <stdlib.h>
      9
     10#include "dso.h"
     11#include "evsel.h"
     12#include "machine.h"
     13#include "thread.h"
     14#include "comm.h"
     15#include "symbol.h"
     16#include "map.h"
     17#include "event.h"
     18#include "thread-stack.h"
     19#include "callchain.h"
     20#include "call-path.h"
     21#include "db-export.h"
     22#include <linux/zalloc.h>
     23
     24int db_export__init(struct db_export *dbe)
     25{
     26	memset(dbe, 0, sizeof(struct db_export));
     27	return 0;
     28}
     29
     30void db_export__exit(struct db_export *dbe)
     31{
     32	call_return_processor__free(dbe->crp);
     33	dbe->crp = NULL;
     34}
     35
     36int db_export__evsel(struct db_export *dbe, struct evsel *evsel)
     37{
     38	if (evsel->db_id)
     39		return 0;
     40
     41	evsel->db_id = ++dbe->evsel_last_db_id;
     42
     43	if (dbe->export_evsel)
     44		return dbe->export_evsel(dbe, evsel);
     45
     46	return 0;
     47}
     48
     49int db_export__machine(struct db_export *dbe, struct machine *machine)
     50{
     51	if (machine->db_id)
     52		return 0;
     53
     54	machine->db_id = ++dbe->machine_last_db_id;
     55
     56	if (dbe->export_machine)
     57		return dbe->export_machine(dbe, machine);
     58
     59	return 0;
     60}
     61
     62int db_export__thread(struct db_export *dbe, struct thread *thread,
     63		      struct machine *machine, struct thread *main_thread)
     64{
     65	u64 main_thread_db_id = 0;
     66
     67	if (thread->db_id)
     68		return 0;
     69
     70	thread->db_id = ++dbe->thread_last_db_id;
     71
     72	if (main_thread)
     73		main_thread_db_id = main_thread->db_id;
     74
     75	if (dbe->export_thread)
     76		return dbe->export_thread(dbe, thread, main_thread_db_id,
     77					  machine);
     78
     79	return 0;
     80}
     81
     82static int __db_export__comm(struct db_export *dbe, struct comm *comm,
     83			     struct thread *thread)
     84{
     85	comm->db_id = ++dbe->comm_last_db_id;
     86
     87	if (dbe->export_comm)
     88		return dbe->export_comm(dbe, comm, thread);
     89
     90	return 0;
     91}
     92
     93int db_export__comm(struct db_export *dbe, struct comm *comm,
     94		    struct thread *thread)
     95{
     96	if (comm->db_id)
     97		return 0;
     98
     99	return __db_export__comm(dbe, comm, thread);
    100}
    101
    102/*
    103 * Export the "exec" comm. The "exec" comm is the program / application command
    104 * name at the time it first executes. It is used to group threads for the same
    105 * program. Note that the main thread pid (or thread group id tgid) cannot be
    106 * used because it does not change when a new program is exec'ed.
    107 */
    108int db_export__exec_comm(struct db_export *dbe, struct comm *comm,
    109			 struct thread *main_thread)
    110{
    111	int err;
    112
    113	if (comm->db_id)
    114		return 0;
    115
    116	err = __db_export__comm(dbe, comm, main_thread);
    117	if (err)
    118		return err;
    119
    120	/*
    121	 * Record the main thread for this comm. Note that the main thread can
    122	 * have many "exec" comms because there will be a new one every time it
    123	 * exec's. An "exec" comm however will only ever have 1 main thread.
    124	 * That is different to any other threads for that same program because
    125	 * exec() will effectively kill them, so the relationship between the
    126	 * "exec" comm and non-main threads is 1-to-1. That is why
    127	 * db_export__comm_thread() is called here for the main thread, but it
    128	 * is called for non-main threads when they are exported.
    129	 */
    130	return db_export__comm_thread(dbe, comm, main_thread);
    131}
    132
    133int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
    134			   struct thread *thread)
    135{
    136	u64 db_id;
    137
    138	db_id = ++dbe->comm_thread_last_db_id;
    139
    140	if (dbe->export_comm_thread)
    141		return dbe->export_comm_thread(dbe, db_id, comm, thread);
    142
    143	return 0;
    144}
    145
    146int db_export__dso(struct db_export *dbe, struct dso *dso,
    147		   struct machine *machine)
    148{
    149	if (dso->db_id)
    150		return 0;
    151
    152	dso->db_id = ++dbe->dso_last_db_id;
    153
    154	if (dbe->export_dso)
    155		return dbe->export_dso(dbe, dso, machine);
    156
    157	return 0;
    158}
    159
    160int db_export__symbol(struct db_export *dbe, struct symbol *sym,
    161		      struct dso *dso)
    162{
    163	u64 *sym_db_id = symbol__priv(sym);
    164
    165	if (*sym_db_id)
    166		return 0;
    167
    168	*sym_db_id = ++dbe->symbol_last_db_id;
    169
    170	if (dbe->export_symbol)
    171		return dbe->export_symbol(dbe, sym, dso);
    172
    173	return 0;
    174}
    175
    176static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
    177			  u64 *dso_db_id, u64 *sym_db_id, u64 *offset)
    178{
    179	int err;
    180
    181	if (al->map) {
    182		struct dso *dso = al->map->dso;
    183
    184		err = db_export__dso(dbe, dso, al->maps->machine);
    185		if (err)
    186			return err;
    187		*dso_db_id = dso->db_id;
    188
    189		if (!al->sym) {
    190			al->sym = symbol__new(al->addr, 0, 0, 0, "unknown");
    191			if (al->sym)
    192				dso__insert_symbol(dso, al->sym);
    193		}
    194
    195		if (al->sym) {
    196			u64 *db_id = symbol__priv(al->sym);
    197
    198			err = db_export__symbol(dbe, al->sym, dso);
    199			if (err)
    200				return err;
    201			*sym_db_id = *db_id;
    202			*offset = al->addr - al->sym->start;
    203		}
    204	}
    205
    206	return 0;
    207}
    208
    209static struct call_path *call_path_from_sample(struct db_export *dbe,
    210					       struct machine *machine,
    211					       struct thread *thread,
    212					       struct perf_sample *sample,
    213					       struct evsel *evsel)
    214{
    215	u64 kernel_start = machine__kernel_start(machine);
    216	struct call_path *current = &dbe->cpr->call_path;
    217	enum chain_order saved_order = callchain_param.order;
    218	int err;
    219
    220	if (!symbol_conf.use_callchain || !sample->callchain)
    221		return NULL;
    222
    223	/*
    224	 * Since the call path tree must be built starting with the root, we
    225	 * must use ORDER_CALL for call chain resolution, in order to process
    226	 * the callchain starting with the root node and ending with the leaf.
    227	 */
    228	callchain_param.order = ORDER_CALLER;
    229	err = thread__resolve_callchain(thread, &callchain_cursor, evsel,
    230					sample, NULL, NULL, PERF_MAX_STACK_DEPTH);
    231	if (err) {
    232		callchain_param.order = saved_order;
    233		return NULL;
    234	}
    235	callchain_cursor_commit(&callchain_cursor);
    236
    237	while (1) {
    238		struct callchain_cursor_node *node;
    239		struct addr_location al;
    240		u64 dso_db_id = 0, sym_db_id = 0, offset = 0;
    241
    242		memset(&al, 0, sizeof(al));
    243
    244		node = callchain_cursor_current(&callchain_cursor);
    245		if (!node)
    246			break;
    247		/*
    248		 * Handle export of symbol and dso for this node by
    249		 * constructing an addr_location struct and then passing it to
    250		 * db_ids_from_al() to perform the export.
    251		 */
    252		al.sym = node->ms.sym;
    253		al.map = node->ms.map;
    254		al.maps = thread->maps;
    255		al.addr = node->ip;
    256
    257		if (al.map && !al.sym)
    258			al.sym = dso__find_symbol(al.map->dso, al.addr);
    259
    260		db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset);
    261
    262		/* add node to the call path tree if it doesn't exist */
    263		current = call_path__findnew(dbe->cpr, current,
    264					     al.sym, node->ip,
    265					     kernel_start);
    266
    267		callchain_cursor_advance(&callchain_cursor);
    268	}
    269
    270	/* Reset the callchain order to its prior value. */
    271	callchain_param.order = saved_order;
    272
    273	if (current == &dbe->cpr->call_path) {
    274		/* Bail because the callchain was empty. */
    275		return NULL;
    276	}
    277
    278	return current;
    279}
    280
    281int db_export__branch_type(struct db_export *dbe, u32 branch_type,
    282			   const char *name)
    283{
    284	if (dbe->export_branch_type)
    285		return dbe->export_branch_type(dbe, branch_type, name);
    286
    287	return 0;
    288}
    289
    290static int db_export__threads(struct db_export *dbe, struct thread *thread,
    291			      struct thread *main_thread,
    292			      struct machine *machine, struct comm **comm_ptr)
    293{
    294	struct comm *comm = NULL;
    295	struct comm *curr_comm;
    296	int err;
    297
    298	if (main_thread) {
    299		/*
    300		 * A thread has a reference to the main thread, so export the
    301		 * main thread first.
    302		 */
    303		err = db_export__thread(dbe, main_thread, machine, main_thread);
    304		if (err)
    305			return err;
    306		/*
    307		 * Export comm before exporting the non-main thread because
    308		 * db_export__comm_thread() can be called further below.
    309		 */
    310		comm = machine__thread_exec_comm(machine, main_thread);
    311		if (comm) {
    312			err = db_export__exec_comm(dbe, comm, main_thread);
    313			if (err)
    314				return err;
    315			*comm_ptr = comm;
    316		}
    317	}
    318
    319	if (thread != main_thread) {
    320		/*
    321		 * For a non-main thread, db_export__comm_thread() must be
    322		 * called only if thread has not previously been exported.
    323		 */
    324		bool export_comm_thread = comm && !thread->db_id;
    325
    326		err = db_export__thread(dbe, thread, machine, main_thread);
    327		if (err)
    328			return err;
    329
    330		if (export_comm_thread) {
    331			err = db_export__comm_thread(dbe, comm, thread);
    332			if (err)
    333				return err;
    334		}
    335	}
    336
    337	curr_comm = thread__comm(thread);
    338	if (curr_comm)
    339		return db_export__comm(dbe, curr_comm, thread);
    340
    341	return 0;
    342}
    343
    344int db_export__sample(struct db_export *dbe, union perf_event *event,
    345		      struct perf_sample *sample, struct evsel *evsel,
    346		      struct addr_location *al, struct addr_location *addr_al)
    347{
    348	struct thread *thread = al->thread;
    349	struct export_sample es = {
    350		.event = event,
    351		.sample = sample,
    352		.evsel = evsel,
    353		.al = al,
    354	};
    355	struct thread *main_thread;
    356	struct comm *comm = NULL;
    357	int err;
    358
    359	err = db_export__evsel(dbe, evsel);
    360	if (err)
    361		return err;
    362
    363	err = db_export__machine(dbe, al->maps->machine);
    364	if (err)
    365		return err;
    366
    367	main_thread = thread__main_thread(al->maps->machine, thread);
    368
    369	err = db_export__threads(dbe, thread, main_thread, al->maps->machine, &comm);
    370	if (err)
    371		goto out_put;
    372
    373	if (comm)
    374		es.comm_db_id = comm->db_id;
    375
    376	es.db_id = ++dbe->sample_last_db_id;
    377
    378	err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset);
    379	if (err)
    380		goto out_put;
    381
    382	if (dbe->cpr) {
    383		struct call_path *cp = call_path_from_sample(dbe, al->maps->machine,
    384							     thread, sample,
    385							     evsel);
    386		if (cp) {
    387			db_export__call_path(dbe, cp);
    388			es.call_path_id = cp->db_id;
    389		}
    390	}
    391
    392	if (addr_al) {
    393		err = db_ids_from_al(dbe, addr_al, &es.addr_dso_db_id,
    394				     &es.addr_sym_db_id, &es.addr_offset);
    395		if (err)
    396			goto out_put;
    397		if (dbe->crp) {
    398			err = thread_stack__process(thread, comm, sample, al,
    399						    addr_al, es.db_id,
    400						    dbe->crp);
    401			if (err)
    402				goto out_put;
    403		}
    404	}
    405
    406	if (dbe->export_sample)
    407		err = dbe->export_sample(dbe, &es);
    408
    409out_put:
    410	thread__put(main_thread);
    411	return err;
    412}
    413
    414static struct {
    415	u32 branch_type;
    416	const char *name;
    417} branch_types[] = {
    418	{0, "no branch"},
    419	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
    420	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
    421	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"},
    422	{PERF_IP_FLAG_BRANCH, "unconditional jump"},
    423	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT,
    424	 "software interrupt"},
    425	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT,
    426	 "return from interrupt"},
    427	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET,
    428	 "system call"},
    429	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET,
    430	 "return from system call"},
    431	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"},
    432	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
    433	 PERF_IP_FLAG_INTERRUPT, "hardware interrupt"},
    434	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"},
    435	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"},
    436	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"},
    437	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMENTRY, "vm entry"},
    438	{PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMEXIT, "vm exit"},
    439	{0, NULL}
    440};
    441
    442int db_export__branch_types(struct db_export *dbe)
    443{
    444	int i, err = 0;
    445
    446	for (i = 0; branch_types[i].name ; i++) {
    447		err = db_export__branch_type(dbe, branch_types[i].branch_type,
    448					     branch_types[i].name);
    449		if (err)
    450			break;
    451	}
    452
    453	/* Add trace begin / end variants */
    454	for (i = 0; branch_types[i].name ; i++) {
    455		const char *name = branch_types[i].name;
    456		u32 type = branch_types[i].branch_type;
    457		char buf[64];
    458
    459		if (type == PERF_IP_FLAG_BRANCH ||
    460		    (type & (PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END)))
    461			continue;
    462
    463		snprintf(buf, sizeof(buf), "trace begin / %s", name);
    464		err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_BEGIN, buf);
    465		if (err)
    466			break;
    467
    468		snprintf(buf, sizeof(buf), "%s / trace end", name);
    469		err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_END, buf);
    470		if (err)
    471			break;
    472	}
    473
    474	return err;
    475}
    476
    477int db_export__call_path(struct db_export *dbe, struct call_path *cp)
    478{
    479	int err;
    480
    481	if (cp->db_id)
    482		return 0;
    483
    484	if (cp->parent) {
    485		err = db_export__call_path(dbe, cp->parent);
    486		if (err)
    487			return err;
    488	}
    489
    490	cp->db_id = ++dbe->call_path_last_db_id;
    491
    492	if (dbe->export_call_path)
    493		return dbe->export_call_path(dbe, cp);
    494
    495	return 0;
    496}
    497
    498int db_export__call_return(struct db_export *dbe, struct call_return *cr,
    499			   u64 *parent_db_id)
    500{
    501	int err;
    502
    503	err = db_export__call_path(dbe, cr->cp);
    504	if (err)
    505		return err;
    506
    507	if (!cr->db_id)
    508		cr->db_id = ++dbe->call_return_last_db_id;
    509
    510	if (parent_db_id) {
    511		if (!*parent_db_id)
    512			*parent_db_id = ++dbe->call_return_last_db_id;
    513		cr->parent_db_id = *parent_db_id;
    514	}
    515
    516	if (dbe->export_call_return)
    517		return dbe->export_call_return(dbe, cr);
    518
    519	return 0;
    520}
    521
    522static int db_export__pid_tid(struct db_export *dbe, struct machine *machine,
    523			      pid_t pid, pid_t tid, u64 *db_id,
    524			      struct comm **comm_ptr, bool *is_idle)
    525{
    526	struct thread *thread = machine__find_thread(machine, pid, tid);
    527	struct thread *main_thread;
    528	int err = 0;
    529
    530	if (!thread || !thread->comm_set)
    531		goto out_put;
    532
    533	*is_idle = !thread->pid_ && !thread->tid;
    534
    535	main_thread = thread__main_thread(machine, thread);
    536
    537	err = db_export__threads(dbe, thread, main_thread, machine, comm_ptr);
    538
    539	*db_id = thread->db_id;
    540
    541	thread__put(main_thread);
    542out_put:
    543	thread__put(thread);
    544
    545	return err;
    546}
    547
    548int db_export__switch(struct db_export *dbe, union perf_event *event,
    549		      struct perf_sample *sample, struct machine *machine)
    550{
    551	bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
    552	bool out_preempt = out &&
    553		(event->header.misc & PERF_RECORD_MISC_SWITCH_OUT_PREEMPT);
    554	int flags = out | (out_preempt << 1);
    555	bool is_idle_a = false, is_idle_b = false;
    556	u64 th_a_id = 0, th_b_id = 0;
    557	u64 comm_out_id, comm_in_id;
    558	struct comm *comm_a = NULL;
    559	struct comm *comm_b = NULL;
    560	u64 th_out_id, th_in_id;
    561	u64 db_id;
    562	int err;
    563
    564	err = db_export__machine(dbe, machine);
    565	if (err)
    566		return err;
    567
    568	err = db_export__pid_tid(dbe, machine, sample->pid, sample->tid,
    569				 &th_a_id, &comm_a, &is_idle_a);
    570	if (err)
    571		return err;
    572
    573	if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) {
    574		pid_t pid = event->context_switch.next_prev_pid;
    575		pid_t tid = event->context_switch.next_prev_tid;
    576
    577		err = db_export__pid_tid(dbe, machine, pid, tid, &th_b_id,
    578					 &comm_b, &is_idle_b);
    579		if (err)
    580			return err;
    581	}
    582
    583	/*
    584	 * Do not export if both threads are unknown (i.e. not being traced),
    585	 * or one is unknown and the other is the idle task.
    586	 */
    587	if ((!th_a_id || is_idle_a) && (!th_b_id || is_idle_b))
    588		return 0;
    589
    590	db_id = ++dbe->context_switch_last_db_id;
    591
    592	if (out) {
    593		th_out_id   = th_a_id;
    594		th_in_id    = th_b_id;
    595		comm_out_id = comm_a ? comm_a->db_id : 0;
    596		comm_in_id  = comm_b ? comm_b->db_id : 0;
    597	} else {
    598		th_out_id   = th_b_id;
    599		th_in_id    = th_a_id;
    600		comm_out_id = comm_b ? comm_b->db_id : 0;
    601		comm_in_id  = comm_a ? comm_a->db_id : 0;
    602	}
    603
    604	if (dbe->export_context_switch)
    605		return dbe->export_context_switch(dbe, db_id, machine, sample,
    606						  th_out_id, comm_out_id,
    607						  th_in_id, comm_in_id, flags);
    608	return 0;
    609}