162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <dirent.h>
362306a36Sopenharmony_ci#include <errno.h>
462306a36Sopenharmony_ci#include <inttypes.h>
562306a36Sopenharmony_ci#include <regex.h>
662306a36Sopenharmony_ci#include <stdlib.h>
762306a36Sopenharmony_ci#include "callchain.h"
862306a36Sopenharmony_ci#include "debug.h"
962306a36Sopenharmony_ci#include "dso.h"
1062306a36Sopenharmony_ci#include "env.h"
1162306a36Sopenharmony_ci#include "event.h"
1262306a36Sopenharmony_ci#include "evsel.h"
1362306a36Sopenharmony_ci#include "hist.h"
1462306a36Sopenharmony_ci#include "machine.h"
1562306a36Sopenharmony_ci#include "map.h"
1662306a36Sopenharmony_ci#include "map_symbol.h"
1762306a36Sopenharmony_ci#include "branch.h"
1862306a36Sopenharmony_ci#include "mem-events.h"
1962306a36Sopenharmony_ci#include "path.h"
2062306a36Sopenharmony_ci#include "srcline.h"
2162306a36Sopenharmony_ci#include "symbol.h"
2262306a36Sopenharmony_ci#include "sort.h"
2362306a36Sopenharmony_ci#include "strlist.h"
2462306a36Sopenharmony_ci#include "target.h"
2562306a36Sopenharmony_ci#include "thread.h"
2662306a36Sopenharmony_ci#include "util.h"
2762306a36Sopenharmony_ci#include "vdso.h"
2862306a36Sopenharmony_ci#include <stdbool.h>
2962306a36Sopenharmony_ci#include <sys/types.h>
3062306a36Sopenharmony_ci#include <sys/stat.h>
3162306a36Sopenharmony_ci#include <unistd.h>
3262306a36Sopenharmony_ci#include "unwind.h"
3362306a36Sopenharmony_ci#include "linux/hash.h"
3462306a36Sopenharmony_ci#include "asm/bug.h"
3562306a36Sopenharmony_ci#include "bpf-event.h"
3662306a36Sopenharmony_ci#include <internal/lib.h> // page_size
3762306a36Sopenharmony_ci#include "cgroup.h"
3862306a36Sopenharmony_ci#include "arm64-frame-pointer-unwind-support.h"
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include <linux/ctype.h>
4162306a36Sopenharmony_ci#include <symbol/kallsyms.h>
4262306a36Sopenharmony_ci#include <linux/mman.h>
4362306a36Sopenharmony_ci#include <linux/string.h>
4462306a36Sopenharmony_ci#include <linux/zalloc.h>
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic void __machine__remove_thread(struct machine *machine, struct thread_rb_node *nd,
4762306a36Sopenharmony_ci				     struct thread *th, bool lock);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic struct dso *machine__kernel_dso(struct machine *machine)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	return map__dso(machine->vmlinux_map);
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic void dsos__init(struct dsos *dsos)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	INIT_LIST_HEAD(&dsos->head);
5762306a36Sopenharmony_ci	dsos->root = RB_ROOT;
5862306a36Sopenharmony_ci	init_rwsem(&dsos->lock);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic void machine__threads_init(struct machine *machine)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	int i;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	for (i = 0; i < THREADS__TABLE_SIZE; i++) {
6662306a36Sopenharmony_ci		struct threads *threads = &machine->threads[i];
6762306a36Sopenharmony_ci		threads->entries = RB_ROOT_CACHED;
6862306a36Sopenharmony_ci		init_rwsem(&threads->lock);
6962306a36Sopenharmony_ci		threads->nr = 0;
7062306a36Sopenharmony_ci		INIT_LIST_HEAD(&threads->dead);
7162306a36Sopenharmony_ci		threads->last_match = NULL;
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic int thread_rb_node__cmp_tid(const void *key, const struct rb_node *nd)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	int to_find = (int) *((pid_t *)key);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return to_find - (int)thread__tid(rb_entry(nd, struct thread_rb_node, rb_node)->thread);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic struct thread_rb_node *thread_rb_node__find(const struct thread *th,
8362306a36Sopenharmony_ci						   struct rb_root *tree)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	pid_t to_find = thread__tid(th);
8662306a36Sopenharmony_ci	struct rb_node *nd = rb_find(&to_find, tree, thread_rb_node__cmp_tid);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return rb_entry(nd, struct thread_rb_node, rb_node);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic int machine__set_mmap_name(struct machine *machine)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	if (machine__is_host(machine))
9462306a36Sopenharmony_ci		machine->mmap_name = strdup("[kernel.kallsyms]");
9562306a36Sopenharmony_ci	else if (machine__is_default_guest(machine))
9662306a36Sopenharmony_ci		machine->mmap_name = strdup("[guest.kernel.kallsyms]");
9762306a36Sopenharmony_ci	else if (asprintf(&machine->mmap_name, "[guest.kernel.kallsyms.%d]",
9862306a36Sopenharmony_ci			  machine->pid) < 0)
9962306a36Sopenharmony_ci		machine->mmap_name = NULL;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	return machine->mmap_name ? 0 : -ENOMEM;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic void thread__set_guest_comm(struct thread *thread, pid_t pid)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	char comm[64];
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	snprintf(comm, sizeof(comm), "[guest/%d]", pid);
10962306a36Sopenharmony_ci	thread__set_comm(thread, comm, 0);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ciint machine__init(struct machine *machine, const char *root_dir, pid_t pid)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	int err = -ENOMEM;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	memset(machine, 0, sizeof(*machine));
11762306a36Sopenharmony_ci	machine->kmaps = maps__new(machine);
11862306a36Sopenharmony_ci	if (machine->kmaps == NULL)
11962306a36Sopenharmony_ci		return -ENOMEM;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	RB_CLEAR_NODE(&machine->rb_node);
12262306a36Sopenharmony_ci	dsos__init(&machine->dsos);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	machine__threads_init(machine);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	machine->vdso_info = NULL;
12762306a36Sopenharmony_ci	machine->env = NULL;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	machine->pid = pid;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	machine->id_hdr_size = 0;
13262306a36Sopenharmony_ci	machine->kptr_restrict_warned = false;
13362306a36Sopenharmony_ci	machine->comm_exec = false;
13462306a36Sopenharmony_ci	machine->kernel_start = 0;
13562306a36Sopenharmony_ci	machine->vmlinux_map = NULL;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	machine->root_dir = strdup(root_dir);
13862306a36Sopenharmony_ci	if (machine->root_dir == NULL)
13962306a36Sopenharmony_ci		goto out;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (machine__set_mmap_name(machine))
14262306a36Sopenharmony_ci		goto out;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (pid != HOST_KERNEL_ID) {
14562306a36Sopenharmony_ci		struct thread *thread = machine__findnew_thread(machine, -1,
14662306a36Sopenharmony_ci								pid);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		if (thread == NULL)
14962306a36Sopenharmony_ci			goto out;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		thread__set_guest_comm(thread, pid);
15262306a36Sopenharmony_ci		thread__put(thread);
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	machine->current_tid = NULL;
15662306a36Sopenharmony_ci	err = 0;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ciout:
15962306a36Sopenharmony_ci	if (err) {
16062306a36Sopenharmony_ci		zfree(&machine->kmaps);
16162306a36Sopenharmony_ci		zfree(&machine->root_dir);
16262306a36Sopenharmony_ci		zfree(&machine->mmap_name);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci	return 0;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistruct machine *machine__new_host(void)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct machine *machine = malloc(sizeof(*machine));
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (machine != NULL) {
17262306a36Sopenharmony_ci		machine__init(machine, "", HOST_KERNEL_ID);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci		if (machine__create_kernel_maps(machine) < 0)
17562306a36Sopenharmony_ci			goto out_delete;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return machine;
17962306a36Sopenharmony_ciout_delete:
18062306a36Sopenharmony_ci	free(machine);
18162306a36Sopenharmony_ci	return NULL;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistruct machine *machine__new_kallsyms(void)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	struct machine *machine = machine__new_host();
18762306a36Sopenharmony_ci	/*
18862306a36Sopenharmony_ci	 * FIXME:
18962306a36Sopenharmony_ci	 * 1) We should switch to machine__load_kallsyms(), i.e. not explicitly
19062306a36Sopenharmony_ci	 *    ask for not using the kcore parsing code, once this one is fixed
19162306a36Sopenharmony_ci	 *    to create a map per module.
19262306a36Sopenharmony_ci	 */
19362306a36Sopenharmony_ci	if (machine && machine__load_kallsyms(machine, "/proc/kallsyms") <= 0) {
19462306a36Sopenharmony_ci		machine__delete(machine);
19562306a36Sopenharmony_ci		machine = NULL;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	return machine;
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic void dsos__purge(struct dsos *dsos)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct dso *pos, *n;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	down_write(&dsos->lock);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	list_for_each_entry_safe(pos, n, &dsos->head, node) {
20862306a36Sopenharmony_ci		RB_CLEAR_NODE(&pos->rb_node);
20962306a36Sopenharmony_ci		pos->root = NULL;
21062306a36Sopenharmony_ci		list_del_init(&pos->node);
21162306a36Sopenharmony_ci		dso__put(pos);
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	up_write(&dsos->lock);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic void dsos__exit(struct dsos *dsos)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	dsos__purge(dsos);
22062306a36Sopenharmony_ci	exit_rwsem(&dsos->lock);
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_civoid machine__delete_threads(struct machine *machine)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct rb_node *nd;
22662306a36Sopenharmony_ci	int i;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	for (i = 0; i < THREADS__TABLE_SIZE; i++) {
22962306a36Sopenharmony_ci		struct threads *threads = &machine->threads[i];
23062306a36Sopenharmony_ci		down_write(&threads->lock);
23162306a36Sopenharmony_ci		nd = rb_first_cached(&threads->entries);
23262306a36Sopenharmony_ci		while (nd) {
23362306a36Sopenharmony_ci			struct thread_rb_node *trb = rb_entry(nd, struct thread_rb_node, rb_node);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci			nd = rb_next(nd);
23662306a36Sopenharmony_ci			__machine__remove_thread(machine, trb, trb->thread, false);
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci		up_write(&threads->lock);
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_civoid machine__exit(struct machine *machine)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	int i;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (machine == NULL)
24762306a36Sopenharmony_ci		return;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	machine__destroy_kernel_maps(machine);
25062306a36Sopenharmony_ci	maps__zput(machine->kmaps);
25162306a36Sopenharmony_ci	dsos__exit(&machine->dsos);
25262306a36Sopenharmony_ci	machine__exit_vdso(machine);
25362306a36Sopenharmony_ci	zfree(&machine->root_dir);
25462306a36Sopenharmony_ci	zfree(&machine->mmap_name);
25562306a36Sopenharmony_ci	zfree(&machine->current_tid);
25662306a36Sopenharmony_ci	zfree(&machine->kallsyms_filename);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	machine__delete_threads(machine);
25962306a36Sopenharmony_ci	for (i = 0; i < THREADS__TABLE_SIZE; i++) {
26062306a36Sopenharmony_ci		struct threads *threads = &machine->threads[i];
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		exit_rwsem(&threads->lock);
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_civoid machine__delete(struct machine *machine)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	if (machine) {
26962306a36Sopenharmony_ci		machine__exit(machine);
27062306a36Sopenharmony_ci		free(machine);
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_civoid machines__init(struct machines *machines)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	machine__init(&machines->host, "", HOST_KERNEL_ID);
27762306a36Sopenharmony_ci	machines->guests = RB_ROOT_CACHED;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_civoid machines__exit(struct machines *machines)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	machine__exit(&machines->host);
28362306a36Sopenharmony_ci	/* XXX exit guest */
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistruct machine *machines__add(struct machines *machines, pid_t pid,
28762306a36Sopenharmony_ci			      const char *root_dir)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	struct rb_node **p = &machines->guests.rb_root.rb_node;
29062306a36Sopenharmony_ci	struct rb_node *parent = NULL;
29162306a36Sopenharmony_ci	struct machine *pos, *machine = malloc(sizeof(*machine));
29262306a36Sopenharmony_ci	bool leftmost = true;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (machine == NULL)
29562306a36Sopenharmony_ci		return NULL;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (machine__init(machine, root_dir, pid) != 0) {
29862306a36Sopenharmony_ci		free(machine);
29962306a36Sopenharmony_ci		return NULL;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	while (*p != NULL) {
30362306a36Sopenharmony_ci		parent = *p;
30462306a36Sopenharmony_ci		pos = rb_entry(parent, struct machine, rb_node);
30562306a36Sopenharmony_ci		if (pid < pos->pid)
30662306a36Sopenharmony_ci			p = &(*p)->rb_left;
30762306a36Sopenharmony_ci		else {
30862306a36Sopenharmony_ci			p = &(*p)->rb_right;
30962306a36Sopenharmony_ci			leftmost = false;
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	rb_link_node(&machine->rb_node, parent, p);
31462306a36Sopenharmony_ci	rb_insert_color_cached(&machine->rb_node, &machines->guests, leftmost);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	machine->machines = machines;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return machine;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_civoid machines__set_comm_exec(struct machines *machines, bool comm_exec)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct rb_node *nd;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	machines->host.comm_exec = comm_exec;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) {
32862306a36Sopenharmony_ci		struct machine *machine = rb_entry(nd, struct machine, rb_node);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci		machine->comm_exec = comm_exec;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistruct machine *machines__find(struct machines *machines, pid_t pid)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct rb_node **p = &machines->guests.rb_root.rb_node;
33762306a36Sopenharmony_ci	struct rb_node *parent = NULL;
33862306a36Sopenharmony_ci	struct machine *machine;
33962306a36Sopenharmony_ci	struct machine *default_machine = NULL;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (pid == HOST_KERNEL_ID)
34262306a36Sopenharmony_ci		return &machines->host;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	while (*p != NULL) {
34562306a36Sopenharmony_ci		parent = *p;
34662306a36Sopenharmony_ci		machine = rb_entry(parent, struct machine, rb_node);
34762306a36Sopenharmony_ci		if (pid < machine->pid)
34862306a36Sopenharmony_ci			p = &(*p)->rb_left;
34962306a36Sopenharmony_ci		else if (pid > machine->pid)
35062306a36Sopenharmony_ci			p = &(*p)->rb_right;
35162306a36Sopenharmony_ci		else
35262306a36Sopenharmony_ci			return machine;
35362306a36Sopenharmony_ci		if (!machine->pid)
35462306a36Sopenharmony_ci			default_machine = machine;
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	return default_machine;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistruct machine *machines__findnew(struct machines *machines, pid_t pid)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	char path[PATH_MAX];
36362306a36Sopenharmony_ci	const char *root_dir = "";
36462306a36Sopenharmony_ci	struct machine *machine = machines__find(machines, pid);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (machine && (machine->pid == pid))
36762306a36Sopenharmony_ci		goto out;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if ((pid != HOST_KERNEL_ID) &&
37062306a36Sopenharmony_ci	    (pid != DEFAULT_GUEST_KERNEL_ID) &&
37162306a36Sopenharmony_ci	    (symbol_conf.guestmount)) {
37262306a36Sopenharmony_ci		sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
37362306a36Sopenharmony_ci		if (access(path, R_OK)) {
37462306a36Sopenharmony_ci			static struct strlist *seen;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci			if (!seen)
37762306a36Sopenharmony_ci				seen = strlist__new(NULL, NULL);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci			if (!strlist__has_entry(seen, path)) {
38062306a36Sopenharmony_ci				pr_err("Can't access file %s\n", path);
38162306a36Sopenharmony_ci				strlist__add(seen, path);
38262306a36Sopenharmony_ci			}
38362306a36Sopenharmony_ci			machine = NULL;
38462306a36Sopenharmony_ci			goto out;
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci		root_dir = path;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	machine = machines__add(machines, pid, root_dir);
39062306a36Sopenharmony_ciout:
39162306a36Sopenharmony_ci	return machine;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistruct machine *machines__find_guest(struct machines *machines, pid_t pid)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	struct machine *machine = machines__find(machines, pid);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (!machine)
39962306a36Sopenharmony_ci		machine = machines__findnew(machines, DEFAULT_GUEST_KERNEL_ID);
40062306a36Sopenharmony_ci	return machine;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci/*
40462306a36Sopenharmony_ci * A common case for KVM test programs is that the test program acts as the
40562306a36Sopenharmony_ci * hypervisor, creating, running and destroying the virtual machine, and
40662306a36Sopenharmony_ci * providing the guest object code from its own object code. In this case,
40762306a36Sopenharmony_ci * the VM is not running an OS, but only the functions loaded into it by the
40862306a36Sopenharmony_ci * hypervisor test program, and conveniently, loaded at the same virtual
40962306a36Sopenharmony_ci * addresses.
41062306a36Sopenharmony_ci *
41162306a36Sopenharmony_ci * Normally to resolve addresses, MMAP events are needed to map addresses
41262306a36Sopenharmony_ci * back to the object code and debug symbols for that object code.
41362306a36Sopenharmony_ci *
41462306a36Sopenharmony_ci * Currently, there is no way to get such mapping information from guests
41562306a36Sopenharmony_ci * but, in the scenario described above, the guest has the same mappings
41662306a36Sopenharmony_ci * as the hypervisor, so support for that scenario can be achieved.
41762306a36Sopenharmony_ci *
41862306a36Sopenharmony_ci * To support that, copy the host thread's maps to the guest thread's maps.
41962306a36Sopenharmony_ci * Note, we do not discover the guest until we encounter a guest event,
42062306a36Sopenharmony_ci * which works well because it is not until then that we know that the host
42162306a36Sopenharmony_ci * thread's maps have been set up.
42262306a36Sopenharmony_ci *
42362306a36Sopenharmony_ci * This function returns the guest thread. Apart from keeping the data
42462306a36Sopenharmony_ci * structures sane, using a thread belonging to the guest machine, instead
42562306a36Sopenharmony_ci * of the host thread, allows it to have its own comm (refer
42662306a36Sopenharmony_ci * thread__set_guest_comm()).
42762306a36Sopenharmony_ci */
42862306a36Sopenharmony_cistatic struct thread *findnew_guest_code(struct machine *machine,
42962306a36Sopenharmony_ci					 struct machine *host_machine,
43062306a36Sopenharmony_ci					 pid_t pid)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct thread *host_thread;
43362306a36Sopenharmony_ci	struct thread *thread;
43462306a36Sopenharmony_ci	int err;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (!machine)
43762306a36Sopenharmony_ci		return NULL;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	thread = machine__findnew_thread(machine, -1, pid);
44062306a36Sopenharmony_ci	if (!thread)
44162306a36Sopenharmony_ci		return NULL;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	/* Assume maps are set up if there are any */
44462306a36Sopenharmony_ci	if (maps__nr_maps(thread__maps(thread)))
44562306a36Sopenharmony_ci		return thread;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	host_thread = machine__find_thread(host_machine, -1, pid);
44862306a36Sopenharmony_ci	if (!host_thread)
44962306a36Sopenharmony_ci		goto out_err;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	thread__set_guest_comm(thread, pid);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	/*
45462306a36Sopenharmony_ci	 * Guest code can be found in hypervisor process at the same address
45562306a36Sopenharmony_ci	 * so copy host maps.
45662306a36Sopenharmony_ci	 */
45762306a36Sopenharmony_ci	err = maps__clone(thread, thread__maps(host_thread));
45862306a36Sopenharmony_ci	thread__put(host_thread);
45962306a36Sopenharmony_ci	if (err)
46062306a36Sopenharmony_ci		goto out_err;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	return thread;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ciout_err:
46562306a36Sopenharmony_ci	thread__zput(thread);
46662306a36Sopenharmony_ci	return NULL;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistruct thread *machines__findnew_guest_code(struct machines *machines, pid_t pid)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct machine *host_machine = machines__find(machines, HOST_KERNEL_ID);
47262306a36Sopenharmony_ci	struct machine *machine = machines__findnew(machines, pid);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	return findnew_guest_code(machine, host_machine, pid);
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistruct thread *machine__findnew_guest_code(struct machine *machine, pid_t pid)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct machines *machines = machine->machines;
48062306a36Sopenharmony_ci	struct machine *host_machine;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if (!machines)
48362306a36Sopenharmony_ci		return NULL;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	host_machine = machines__find(machines, HOST_KERNEL_ID);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return findnew_guest_code(machine, host_machine, pid);
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_civoid machines__process_guests(struct machines *machines,
49162306a36Sopenharmony_ci			      machine__process_t process, void *data)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	struct rb_node *nd;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) {
49662306a36Sopenharmony_ci		struct machine *pos = rb_entry(nd, struct machine, rb_node);
49762306a36Sopenharmony_ci		process(pos, data);
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_civoid machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct rb_node *node;
50462306a36Sopenharmony_ci	struct machine *machine;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	machines->host.id_hdr_size = id_hdr_size;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	for (node = rb_first_cached(&machines->guests); node;
50962306a36Sopenharmony_ci	     node = rb_next(node)) {
51062306a36Sopenharmony_ci		machine = rb_entry(node, struct machine, rb_node);
51162306a36Sopenharmony_ci		machine->id_hdr_size = id_hdr_size;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic void machine__update_thread_pid(struct machine *machine,
51862306a36Sopenharmony_ci				       struct thread *th, pid_t pid)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	struct thread *leader;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (pid == thread__pid(th) || pid == -1 || thread__pid(th) != -1)
52362306a36Sopenharmony_ci		return;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	thread__set_pid(th, pid);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	if (thread__pid(th) == thread__tid(th))
52862306a36Sopenharmony_ci		return;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	leader = __machine__findnew_thread(machine, thread__pid(th), thread__pid(th));
53162306a36Sopenharmony_ci	if (!leader)
53262306a36Sopenharmony_ci		goto out_err;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	if (!thread__maps(leader))
53562306a36Sopenharmony_ci		thread__set_maps(leader, maps__new(machine));
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (!thread__maps(leader))
53862306a36Sopenharmony_ci		goto out_err;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (thread__maps(th) == thread__maps(leader))
54162306a36Sopenharmony_ci		goto out_put;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (thread__maps(th)) {
54462306a36Sopenharmony_ci		/*
54562306a36Sopenharmony_ci		 * Maps are created from MMAP events which provide the pid and
54662306a36Sopenharmony_ci		 * tid.  Consequently there never should be any maps on a thread
54762306a36Sopenharmony_ci		 * with an unknown pid.  Just print an error if there are.
54862306a36Sopenharmony_ci		 */
54962306a36Sopenharmony_ci		if (!maps__empty(thread__maps(th)))
55062306a36Sopenharmony_ci			pr_err("Discarding thread maps for %d:%d\n",
55162306a36Sopenharmony_ci				thread__pid(th), thread__tid(th));
55262306a36Sopenharmony_ci		maps__put(thread__maps(th));
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	thread__set_maps(th, maps__get(thread__maps(leader)));
55662306a36Sopenharmony_ciout_put:
55762306a36Sopenharmony_ci	thread__put(leader);
55862306a36Sopenharmony_ci	return;
55962306a36Sopenharmony_ciout_err:
56062306a36Sopenharmony_ci	pr_err("Failed to join map groups for %d:%d\n", thread__pid(th), thread__tid(th));
56162306a36Sopenharmony_ci	goto out_put;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci/*
56562306a36Sopenharmony_ci * Front-end cache - TID lookups come in blocks,
56662306a36Sopenharmony_ci * so most of the time we dont have to look up
56762306a36Sopenharmony_ci * the full rbtree:
56862306a36Sopenharmony_ci */
56962306a36Sopenharmony_cistatic struct thread*
57062306a36Sopenharmony_ci__threads__get_last_match(struct threads *threads, struct machine *machine,
57162306a36Sopenharmony_ci			  int pid, int tid)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	struct thread *th;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	th = threads->last_match;
57662306a36Sopenharmony_ci	if (th != NULL) {
57762306a36Sopenharmony_ci		if (thread__tid(th) == tid) {
57862306a36Sopenharmony_ci			machine__update_thread_pid(machine, th, pid);
57962306a36Sopenharmony_ci			return thread__get(th);
58062306a36Sopenharmony_ci		}
58162306a36Sopenharmony_ci		thread__put(threads->last_match);
58262306a36Sopenharmony_ci		threads->last_match = NULL;
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	return NULL;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic struct thread*
58962306a36Sopenharmony_cithreads__get_last_match(struct threads *threads, struct machine *machine,
59062306a36Sopenharmony_ci			int pid, int tid)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct thread *th = NULL;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	if (perf_singlethreaded)
59562306a36Sopenharmony_ci		th = __threads__get_last_match(threads, machine, pid, tid);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	return th;
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic void
60162306a36Sopenharmony_ci__threads__set_last_match(struct threads *threads, struct thread *th)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	thread__put(threads->last_match);
60462306a36Sopenharmony_ci	threads->last_match = thread__get(th);
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic void
60862306a36Sopenharmony_cithreads__set_last_match(struct threads *threads, struct thread *th)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	if (perf_singlethreaded)
61162306a36Sopenharmony_ci		__threads__set_last_match(threads, th);
61262306a36Sopenharmony_ci}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci/*
61562306a36Sopenharmony_ci * Caller must eventually drop thread->refcnt returned with a successful
61662306a36Sopenharmony_ci * lookup/new thread inserted.
61762306a36Sopenharmony_ci */
61862306a36Sopenharmony_cistatic struct thread *____machine__findnew_thread(struct machine *machine,
61962306a36Sopenharmony_ci						  struct threads *threads,
62062306a36Sopenharmony_ci						  pid_t pid, pid_t tid,
62162306a36Sopenharmony_ci						  bool create)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	struct rb_node **p = &threads->entries.rb_root.rb_node;
62462306a36Sopenharmony_ci	struct rb_node *parent = NULL;
62562306a36Sopenharmony_ci	struct thread *th;
62662306a36Sopenharmony_ci	struct thread_rb_node *nd;
62762306a36Sopenharmony_ci	bool leftmost = true;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	th = threads__get_last_match(threads, machine, pid, tid);
63062306a36Sopenharmony_ci	if (th)
63162306a36Sopenharmony_ci		return th;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	while (*p != NULL) {
63462306a36Sopenharmony_ci		parent = *p;
63562306a36Sopenharmony_ci		th = rb_entry(parent, struct thread_rb_node, rb_node)->thread;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		if (thread__tid(th) == tid) {
63862306a36Sopenharmony_ci			threads__set_last_match(threads, th);
63962306a36Sopenharmony_ci			machine__update_thread_pid(machine, th, pid);
64062306a36Sopenharmony_ci			return thread__get(th);
64162306a36Sopenharmony_ci		}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci		if (tid < thread__tid(th))
64462306a36Sopenharmony_ci			p = &(*p)->rb_left;
64562306a36Sopenharmony_ci		else {
64662306a36Sopenharmony_ci			p = &(*p)->rb_right;
64762306a36Sopenharmony_ci			leftmost = false;
64862306a36Sopenharmony_ci		}
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	if (!create)
65262306a36Sopenharmony_ci		return NULL;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	th = thread__new(pid, tid);
65562306a36Sopenharmony_ci	if (th == NULL)
65662306a36Sopenharmony_ci		return NULL;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	nd = malloc(sizeof(*nd));
65962306a36Sopenharmony_ci	if (nd == NULL) {
66062306a36Sopenharmony_ci		thread__put(th);
66162306a36Sopenharmony_ci		return NULL;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci	nd->thread = th;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	rb_link_node(&nd->rb_node, parent, p);
66662306a36Sopenharmony_ci	rb_insert_color_cached(&nd->rb_node, &threads->entries, leftmost);
66762306a36Sopenharmony_ci	/*
66862306a36Sopenharmony_ci	 * We have to initialize maps separately after rb tree is updated.
66962306a36Sopenharmony_ci	 *
67062306a36Sopenharmony_ci	 * The reason is that we call machine__findnew_thread within
67162306a36Sopenharmony_ci	 * thread__init_maps to find the thread leader and that would screwed
67262306a36Sopenharmony_ci	 * the rb tree.
67362306a36Sopenharmony_ci	 */
67462306a36Sopenharmony_ci	if (thread__init_maps(th, machine)) {
67562306a36Sopenharmony_ci		pr_err("Thread init failed thread %d\n", pid);
67662306a36Sopenharmony_ci		rb_erase_cached(&nd->rb_node, &threads->entries);
67762306a36Sopenharmony_ci		RB_CLEAR_NODE(&nd->rb_node);
67862306a36Sopenharmony_ci		free(nd);
67962306a36Sopenharmony_ci		thread__put(th);
68062306a36Sopenharmony_ci		return NULL;
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci	/*
68362306a36Sopenharmony_ci	 * It is now in the rbtree, get a ref
68462306a36Sopenharmony_ci	 */
68562306a36Sopenharmony_ci	threads__set_last_match(threads, th);
68662306a36Sopenharmony_ci	++threads->nr;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	return thread__get(th);
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistruct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	return ____machine__findnew_thread(machine, machine__threads(machine, tid), pid, tid, true);
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistruct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
69762306a36Sopenharmony_ci				       pid_t tid)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct threads *threads = machine__threads(machine, tid);
70062306a36Sopenharmony_ci	struct thread *th;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	down_write(&threads->lock);
70362306a36Sopenharmony_ci	th = __machine__findnew_thread(machine, pid, tid);
70462306a36Sopenharmony_ci	up_write(&threads->lock);
70562306a36Sopenharmony_ci	return th;
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistruct thread *machine__find_thread(struct machine *machine, pid_t pid,
70962306a36Sopenharmony_ci				    pid_t tid)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	struct threads *threads = machine__threads(machine, tid);
71262306a36Sopenharmony_ci	struct thread *th;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	down_read(&threads->lock);
71562306a36Sopenharmony_ci	th =  ____machine__findnew_thread(machine, threads, pid, tid, false);
71662306a36Sopenharmony_ci	up_read(&threads->lock);
71762306a36Sopenharmony_ci	return th;
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci/*
72162306a36Sopenharmony_ci * Threads are identified by pid and tid, and the idle task has pid == tid == 0.
72262306a36Sopenharmony_ci * So here a single thread is created for that, but actually there is a separate
72362306a36Sopenharmony_ci * idle task per cpu, so there should be one 'struct thread' per cpu, but there
72462306a36Sopenharmony_ci * is only 1. That causes problems for some tools, requiring workarounds. For
72562306a36Sopenharmony_ci * example get_idle_thread() in builtin-sched.c, or thread_stack__per_cpu().
72662306a36Sopenharmony_ci */
72762306a36Sopenharmony_cistruct thread *machine__idle_thread(struct machine *machine)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	struct thread *thread = machine__findnew_thread(machine, 0, 0);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if (!thread || thread__set_comm(thread, "swapper", 0) ||
73262306a36Sopenharmony_ci	    thread__set_namespaces(thread, 0, NULL))
73362306a36Sopenharmony_ci		pr_err("problem inserting idle task for machine pid %d\n", machine->pid);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	return thread;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistruct comm *machine__thread_exec_comm(struct machine *machine,
73962306a36Sopenharmony_ci				       struct thread *thread)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	if (machine->comm_exec)
74262306a36Sopenharmony_ci		return thread__exec_comm(thread);
74362306a36Sopenharmony_ci	else
74462306a36Sopenharmony_ci		return thread__comm(thread);
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ciint machine__process_comm_event(struct machine *machine, union perf_event *event,
74862306a36Sopenharmony_ci				struct perf_sample *sample)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	struct thread *thread = machine__findnew_thread(machine,
75162306a36Sopenharmony_ci							event->comm.pid,
75262306a36Sopenharmony_ci							event->comm.tid);
75362306a36Sopenharmony_ci	bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC;
75462306a36Sopenharmony_ci	int err = 0;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (exec)
75762306a36Sopenharmony_ci		machine->comm_exec = true;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	if (dump_trace)
76062306a36Sopenharmony_ci		perf_event__fprintf_comm(event, stdout);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (thread == NULL ||
76362306a36Sopenharmony_ci	    __thread__set_comm(thread, event->comm.comm, sample->time, exec)) {
76462306a36Sopenharmony_ci		dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
76562306a36Sopenharmony_ci		err = -1;
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	thread__put(thread);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	return err;
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ciint machine__process_namespaces_event(struct machine *machine __maybe_unused,
77462306a36Sopenharmony_ci				      union perf_event *event,
77562306a36Sopenharmony_ci				      struct perf_sample *sample __maybe_unused)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	struct thread *thread = machine__findnew_thread(machine,
77862306a36Sopenharmony_ci							event->namespaces.pid,
77962306a36Sopenharmony_ci							event->namespaces.tid);
78062306a36Sopenharmony_ci	int err = 0;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	WARN_ONCE(event->namespaces.nr_namespaces > NR_NAMESPACES,
78362306a36Sopenharmony_ci		  "\nWARNING: kernel seems to support more namespaces than perf"
78462306a36Sopenharmony_ci		  " tool.\nTry updating the perf tool..\n\n");
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	WARN_ONCE(event->namespaces.nr_namespaces < NR_NAMESPACES,
78762306a36Sopenharmony_ci		  "\nWARNING: perf tool seems to support more namespaces than"
78862306a36Sopenharmony_ci		  " the kernel.\nTry updating the kernel..\n\n");
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	if (dump_trace)
79162306a36Sopenharmony_ci		perf_event__fprintf_namespaces(event, stdout);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	if (thread == NULL ||
79462306a36Sopenharmony_ci	    thread__set_namespaces(thread, sample->time, &event->namespaces)) {
79562306a36Sopenharmony_ci		dump_printf("problem processing PERF_RECORD_NAMESPACES, skipping event.\n");
79662306a36Sopenharmony_ci		err = -1;
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	thread__put(thread);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	return err;
80262306a36Sopenharmony_ci}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ciint machine__process_cgroup_event(struct machine *machine,
80562306a36Sopenharmony_ci				  union perf_event *event,
80662306a36Sopenharmony_ci				  struct perf_sample *sample __maybe_unused)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	struct cgroup *cgrp;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	if (dump_trace)
81162306a36Sopenharmony_ci		perf_event__fprintf_cgroup(event, stdout);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	cgrp = cgroup__findnew(machine->env, event->cgroup.id, event->cgroup.path);
81462306a36Sopenharmony_ci	if (cgrp == NULL)
81562306a36Sopenharmony_ci		return -ENOMEM;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	return 0;
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ciint machine__process_lost_event(struct machine *machine __maybe_unused,
82162306a36Sopenharmony_ci				union perf_event *event, struct perf_sample *sample __maybe_unused)
82262306a36Sopenharmony_ci{
82362306a36Sopenharmony_ci	dump_printf(": id:%" PRI_lu64 ": lost:%" PRI_lu64 "\n",
82462306a36Sopenharmony_ci		    event->lost.id, event->lost.lost);
82562306a36Sopenharmony_ci	return 0;
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ciint machine__process_lost_samples_event(struct machine *machine __maybe_unused,
82962306a36Sopenharmony_ci					union perf_event *event, struct perf_sample *sample)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	dump_printf(": id:%" PRIu64 ": lost samples :%" PRI_lu64 "\n",
83262306a36Sopenharmony_ci		    sample->id, event->lost_samples.lost);
83362306a36Sopenharmony_ci	return 0;
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic struct dso *machine__findnew_module_dso(struct machine *machine,
83762306a36Sopenharmony_ci					       struct kmod_path *m,
83862306a36Sopenharmony_ci					       const char *filename)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	struct dso *dso;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	down_write(&machine->dsos.lock);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	dso = __dsos__find(&machine->dsos, m->name, true);
84562306a36Sopenharmony_ci	if (!dso) {
84662306a36Sopenharmony_ci		dso = __dsos__addnew(&machine->dsos, m->name);
84762306a36Sopenharmony_ci		if (dso == NULL)
84862306a36Sopenharmony_ci			goto out_unlock;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci		dso__set_module_info(dso, m, machine);
85162306a36Sopenharmony_ci		dso__set_long_name(dso, strdup(filename), true);
85262306a36Sopenharmony_ci		dso->kernel = DSO_SPACE__KERNEL;
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	dso__get(dso);
85662306a36Sopenharmony_ciout_unlock:
85762306a36Sopenharmony_ci	up_write(&machine->dsos.lock);
85862306a36Sopenharmony_ci	return dso;
85962306a36Sopenharmony_ci}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ciint machine__process_aux_event(struct machine *machine __maybe_unused,
86262306a36Sopenharmony_ci			       union perf_event *event)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	if (dump_trace)
86562306a36Sopenharmony_ci		perf_event__fprintf_aux(event, stdout);
86662306a36Sopenharmony_ci	return 0;
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ciint machine__process_itrace_start_event(struct machine *machine __maybe_unused,
87062306a36Sopenharmony_ci					union perf_event *event)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	if (dump_trace)
87362306a36Sopenharmony_ci		perf_event__fprintf_itrace_start(event, stdout);
87462306a36Sopenharmony_ci	return 0;
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ciint machine__process_aux_output_hw_id_event(struct machine *machine __maybe_unused,
87862306a36Sopenharmony_ci					    union perf_event *event)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	if (dump_trace)
88162306a36Sopenharmony_ci		perf_event__fprintf_aux_output_hw_id(event, stdout);
88262306a36Sopenharmony_ci	return 0;
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ciint machine__process_switch_event(struct machine *machine __maybe_unused,
88662306a36Sopenharmony_ci				  union perf_event *event)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	if (dump_trace)
88962306a36Sopenharmony_ci		perf_event__fprintf_switch(event, stdout);
89062306a36Sopenharmony_ci	return 0;
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cistatic int machine__process_ksymbol_register(struct machine *machine,
89462306a36Sopenharmony_ci					     union perf_event *event,
89562306a36Sopenharmony_ci					     struct perf_sample *sample __maybe_unused)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	struct symbol *sym;
89862306a36Sopenharmony_ci	struct dso *dso;
89962306a36Sopenharmony_ci	struct map *map = maps__find(machine__kernel_maps(machine), event->ksymbol.addr);
90062306a36Sopenharmony_ci	bool put_map = false;
90162306a36Sopenharmony_ci	int err = 0;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	if (!map) {
90462306a36Sopenharmony_ci		dso = dso__new(event->ksymbol.name);
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci		if (!dso) {
90762306a36Sopenharmony_ci			err = -ENOMEM;
90862306a36Sopenharmony_ci			goto out;
90962306a36Sopenharmony_ci		}
91062306a36Sopenharmony_ci		dso->kernel = DSO_SPACE__KERNEL;
91162306a36Sopenharmony_ci		map = map__new2(0, dso);
91262306a36Sopenharmony_ci		dso__put(dso);
91362306a36Sopenharmony_ci		if (!map) {
91462306a36Sopenharmony_ci			err = -ENOMEM;
91562306a36Sopenharmony_ci			goto out;
91662306a36Sopenharmony_ci		}
91762306a36Sopenharmony_ci		/*
91862306a36Sopenharmony_ci		 * The inserted map has a get on it, we need to put to release
91962306a36Sopenharmony_ci		 * the reference count here, but do it after all accesses are
92062306a36Sopenharmony_ci		 * done.
92162306a36Sopenharmony_ci		 */
92262306a36Sopenharmony_ci		put_map = true;
92362306a36Sopenharmony_ci		if (event->ksymbol.ksym_type == PERF_RECORD_KSYMBOL_TYPE_OOL) {
92462306a36Sopenharmony_ci			dso->binary_type = DSO_BINARY_TYPE__OOL;
92562306a36Sopenharmony_ci			dso->data.file_size = event->ksymbol.len;
92662306a36Sopenharmony_ci			dso__set_loaded(dso);
92762306a36Sopenharmony_ci		}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		map__set_start(map, event->ksymbol.addr);
93062306a36Sopenharmony_ci		map__set_end(map, map__start(map) + event->ksymbol.len);
93162306a36Sopenharmony_ci		err = maps__insert(machine__kernel_maps(machine), map);
93262306a36Sopenharmony_ci		if (err) {
93362306a36Sopenharmony_ci			err = -ENOMEM;
93462306a36Sopenharmony_ci			goto out;
93562306a36Sopenharmony_ci		}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci		dso__set_loaded(dso);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		if (is_bpf_image(event->ksymbol.name)) {
94062306a36Sopenharmony_ci			dso->binary_type = DSO_BINARY_TYPE__BPF_IMAGE;
94162306a36Sopenharmony_ci			dso__set_long_name(dso, "", false);
94262306a36Sopenharmony_ci		}
94362306a36Sopenharmony_ci	} else {
94462306a36Sopenharmony_ci		dso = map__dso(map);
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	sym = symbol__new(map__map_ip(map, map__start(map)),
94862306a36Sopenharmony_ci			  event->ksymbol.len,
94962306a36Sopenharmony_ci			  0, 0, event->ksymbol.name);
95062306a36Sopenharmony_ci	if (!sym) {
95162306a36Sopenharmony_ci		err = -ENOMEM;
95262306a36Sopenharmony_ci		goto out;
95362306a36Sopenharmony_ci	}
95462306a36Sopenharmony_ci	dso__insert_symbol(dso, sym);
95562306a36Sopenharmony_ciout:
95662306a36Sopenharmony_ci	if (put_map)
95762306a36Sopenharmony_ci		map__put(map);
95862306a36Sopenharmony_ci	return err;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic int machine__process_ksymbol_unregister(struct machine *machine,
96262306a36Sopenharmony_ci					       union perf_event *event,
96362306a36Sopenharmony_ci					       struct perf_sample *sample __maybe_unused)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct symbol *sym;
96662306a36Sopenharmony_ci	struct map *map;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	map = maps__find(machine__kernel_maps(machine), event->ksymbol.addr);
96962306a36Sopenharmony_ci	if (!map)
97062306a36Sopenharmony_ci		return 0;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	if (RC_CHK_ACCESS(map) != RC_CHK_ACCESS(machine->vmlinux_map))
97362306a36Sopenharmony_ci		maps__remove(machine__kernel_maps(machine), map);
97462306a36Sopenharmony_ci	else {
97562306a36Sopenharmony_ci		struct dso *dso = map__dso(map);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci		sym = dso__find_symbol(dso, map__map_ip(map, map__start(map)));
97862306a36Sopenharmony_ci		if (sym)
97962306a36Sopenharmony_ci			dso__delete_symbol(dso, sym);
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	return 0;
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ciint machine__process_ksymbol(struct machine *machine __maybe_unused,
98662306a36Sopenharmony_ci			     union perf_event *event,
98762306a36Sopenharmony_ci			     struct perf_sample *sample)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	if (dump_trace)
99062306a36Sopenharmony_ci		perf_event__fprintf_ksymbol(event, stdout);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	if (event->ksymbol.flags & PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER)
99362306a36Sopenharmony_ci		return machine__process_ksymbol_unregister(machine, event,
99462306a36Sopenharmony_ci							   sample);
99562306a36Sopenharmony_ci	return machine__process_ksymbol_register(machine, event, sample);
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ciint machine__process_text_poke(struct machine *machine, union perf_event *event,
99962306a36Sopenharmony_ci			       struct perf_sample *sample __maybe_unused)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	struct map *map = maps__find(machine__kernel_maps(machine), event->text_poke.addr);
100262306a36Sopenharmony_ci	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
100362306a36Sopenharmony_ci	struct dso *dso = map ? map__dso(map) : NULL;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	if (dump_trace)
100662306a36Sopenharmony_ci		perf_event__fprintf_text_poke(event, machine, stdout);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (!event->text_poke.new_len)
100962306a36Sopenharmony_ci		return 0;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	if (cpumode != PERF_RECORD_MISC_KERNEL) {
101262306a36Sopenharmony_ci		pr_debug("%s: unsupported cpumode - ignoring\n", __func__);
101362306a36Sopenharmony_ci		return 0;
101462306a36Sopenharmony_ci	}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	if (dso) {
101762306a36Sopenharmony_ci		u8 *new_bytes = event->text_poke.bytes + event->text_poke.old_len;
101862306a36Sopenharmony_ci		int ret;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci		/*
102162306a36Sopenharmony_ci		 * Kernel maps might be changed when loading symbols so loading
102262306a36Sopenharmony_ci		 * must be done prior to using kernel maps.
102362306a36Sopenharmony_ci		 */
102462306a36Sopenharmony_ci		map__load(map);
102562306a36Sopenharmony_ci		ret = dso__data_write_cache_addr(dso, map, machine,
102662306a36Sopenharmony_ci						 event->text_poke.addr,
102762306a36Sopenharmony_ci						 new_bytes,
102862306a36Sopenharmony_ci						 event->text_poke.new_len);
102962306a36Sopenharmony_ci		if (ret != event->text_poke.new_len)
103062306a36Sopenharmony_ci			pr_debug("Failed to write kernel text poke at %#" PRI_lx64 "\n",
103162306a36Sopenharmony_ci				 event->text_poke.addr);
103262306a36Sopenharmony_ci	} else {
103362306a36Sopenharmony_ci		pr_debug("Failed to find kernel text poke address map for %#" PRI_lx64 "\n",
103462306a36Sopenharmony_ci			 event->text_poke.addr);
103562306a36Sopenharmony_ci	}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	return 0;
103862306a36Sopenharmony_ci}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_cistatic struct map *machine__addnew_module_map(struct machine *machine, u64 start,
104162306a36Sopenharmony_ci					      const char *filename)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	struct map *map = NULL;
104462306a36Sopenharmony_ci	struct kmod_path m;
104562306a36Sopenharmony_ci	struct dso *dso;
104662306a36Sopenharmony_ci	int err;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	if (kmod_path__parse_name(&m, filename))
104962306a36Sopenharmony_ci		return NULL;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	dso = machine__findnew_module_dso(machine, &m, filename);
105262306a36Sopenharmony_ci	if (dso == NULL)
105362306a36Sopenharmony_ci		goto out;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	map = map__new2(start, dso);
105662306a36Sopenharmony_ci	if (map == NULL)
105762306a36Sopenharmony_ci		goto out;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	err = maps__insert(machine__kernel_maps(machine), map);
106062306a36Sopenharmony_ci	/* If maps__insert failed, return NULL. */
106162306a36Sopenharmony_ci	if (err) {
106262306a36Sopenharmony_ci		map__put(map);
106362306a36Sopenharmony_ci		map = NULL;
106462306a36Sopenharmony_ci	}
106562306a36Sopenharmony_ciout:
106662306a36Sopenharmony_ci	/* put the dso here, corresponding to  machine__findnew_module_dso */
106762306a36Sopenharmony_ci	dso__put(dso);
106862306a36Sopenharmony_ci	zfree(&m.name);
106962306a36Sopenharmony_ci	return map;
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cisize_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	struct rb_node *nd;
107562306a36Sopenharmony_ci	size_t ret = __dsos__fprintf(&machines->host.dsos.head, fp);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) {
107862306a36Sopenharmony_ci		struct machine *pos = rb_entry(nd, struct machine, rb_node);
107962306a36Sopenharmony_ci		ret += __dsos__fprintf(&pos->dsos.head, fp);
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	return ret;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cisize_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp,
108662306a36Sopenharmony_ci				     bool (skip)(struct dso *dso, int parm), int parm)
108762306a36Sopenharmony_ci{
108862306a36Sopenharmony_ci	return __dsos__fprintf_buildid(&m->dsos.head, fp, skip, parm);
108962306a36Sopenharmony_ci}
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_cisize_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
109262306a36Sopenharmony_ci				     bool (skip)(struct dso *dso, int parm), int parm)
109362306a36Sopenharmony_ci{
109462306a36Sopenharmony_ci	struct rb_node *nd;
109562306a36Sopenharmony_ci	size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) {
109862306a36Sopenharmony_ci		struct machine *pos = rb_entry(nd, struct machine, rb_node);
109962306a36Sopenharmony_ci		ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm);
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci	return ret;
110262306a36Sopenharmony_ci}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_cisize_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
110562306a36Sopenharmony_ci{
110662306a36Sopenharmony_ci	int i;
110762306a36Sopenharmony_ci	size_t printed = 0;
110862306a36Sopenharmony_ci	struct dso *kdso = machine__kernel_dso(machine);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	if (kdso->has_build_id) {
111162306a36Sopenharmony_ci		char filename[PATH_MAX];
111262306a36Sopenharmony_ci		if (dso__build_id_filename(kdso, filename, sizeof(filename),
111362306a36Sopenharmony_ci					   false))
111462306a36Sopenharmony_ci			printed += fprintf(fp, "[0] %s\n", filename);
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	for (i = 0; i < vmlinux_path__nr_entries; ++i)
111862306a36Sopenharmony_ci		printed += fprintf(fp, "[%d] %s\n",
111962306a36Sopenharmony_ci				   i + kdso->has_build_id, vmlinux_path[i]);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	return printed;
112262306a36Sopenharmony_ci}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_cisize_t machine__fprintf(struct machine *machine, FILE *fp)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	struct rb_node *nd;
112762306a36Sopenharmony_ci	size_t ret;
112862306a36Sopenharmony_ci	int i;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	for (i = 0; i < THREADS__TABLE_SIZE; i++) {
113162306a36Sopenharmony_ci		struct threads *threads = &machine->threads[i];
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci		down_read(&threads->lock);
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci		ret = fprintf(fp, "Threads: %u\n", threads->nr);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci		for (nd = rb_first_cached(&threads->entries); nd;
113862306a36Sopenharmony_ci		     nd = rb_next(nd)) {
113962306a36Sopenharmony_ci			struct thread *pos = rb_entry(nd, struct thread_rb_node, rb_node)->thread;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci			ret += thread__fprintf(pos, fp);
114262306a36Sopenharmony_ci		}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci		up_read(&threads->lock);
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci	return ret;
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_cistatic struct dso *machine__get_kernel(struct machine *machine)
115062306a36Sopenharmony_ci{
115162306a36Sopenharmony_ci	const char *vmlinux_name = machine->mmap_name;
115262306a36Sopenharmony_ci	struct dso *kernel;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	if (machine__is_host(machine)) {
115562306a36Sopenharmony_ci		if (symbol_conf.vmlinux_name)
115662306a36Sopenharmony_ci			vmlinux_name = symbol_conf.vmlinux_name;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci		kernel = machine__findnew_kernel(machine, vmlinux_name,
115962306a36Sopenharmony_ci						 "[kernel]", DSO_SPACE__KERNEL);
116062306a36Sopenharmony_ci	} else {
116162306a36Sopenharmony_ci		if (symbol_conf.default_guest_vmlinux_name)
116262306a36Sopenharmony_ci			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci		kernel = machine__findnew_kernel(machine, vmlinux_name,
116562306a36Sopenharmony_ci						 "[guest.kernel]",
116662306a36Sopenharmony_ci						 DSO_SPACE__KERNEL_GUEST);
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	if (kernel != NULL && (!kernel->has_build_id))
117062306a36Sopenharmony_ci		dso__read_running_kernel_build_id(kernel, machine);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	return kernel;
117362306a36Sopenharmony_ci}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_civoid machine__get_kallsyms_filename(struct machine *machine, char *buf,
117662306a36Sopenharmony_ci				    size_t bufsz)
117762306a36Sopenharmony_ci{
117862306a36Sopenharmony_ci	if (machine__is_default_guest(machine))
117962306a36Sopenharmony_ci		scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms);
118062306a36Sopenharmony_ci	else
118162306a36Sopenharmony_ci		scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir);
118262306a36Sopenharmony_ci}
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ciconst char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci/* Figure out the start address of kernel map from /proc/kallsyms.
118762306a36Sopenharmony_ci * Returns the name of the start symbol in *symbol_name. Pass in NULL as
118862306a36Sopenharmony_ci * symbol_name if it's not that important.
118962306a36Sopenharmony_ci */
119062306a36Sopenharmony_cistatic int machine__get_running_kernel_start(struct machine *machine,
119162306a36Sopenharmony_ci					     const char **symbol_name,
119262306a36Sopenharmony_ci					     u64 *start, u64 *end)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	char filename[PATH_MAX];
119562306a36Sopenharmony_ci	int i, err = -1;
119662306a36Sopenharmony_ci	const char *name;
119762306a36Sopenharmony_ci	u64 addr = 0;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	machine__get_kallsyms_filename(machine, filename, PATH_MAX);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
120262306a36Sopenharmony_ci		return 0;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
120562306a36Sopenharmony_ci		err = kallsyms__get_function_start(filename, name, &addr);
120662306a36Sopenharmony_ci		if (!err)
120762306a36Sopenharmony_ci			break;
120862306a36Sopenharmony_ci	}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	if (err)
121162306a36Sopenharmony_ci		return -1;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	if (symbol_name)
121462306a36Sopenharmony_ci		*symbol_name = name;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	*start = addr;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	err = kallsyms__get_symbol_start(filename, "_edata", &addr);
121962306a36Sopenharmony_ci	if (err)
122062306a36Sopenharmony_ci		err = kallsyms__get_function_start(filename, "_etext", &addr);
122162306a36Sopenharmony_ci	if (!err)
122262306a36Sopenharmony_ci		*end = addr;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	return 0;
122562306a36Sopenharmony_ci}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ciint machine__create_extra_kernel_map(struct machine *machine,
122862306a36Sopenharmony_ci				     struct dso *kernel,
122962306a36Sopenharmony_ci				     struct extra_kernel_map *xm)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	struct kmap *kmap;
123262306a36Sopenharmony_ci	struct map *map;
123362306a36Sopenharmony_ci	int err;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	map = map__new2(xm->start, kernel);
123662306a36Sopenharmony_ci	if (!map)
123762306a36Sopenharmony_ci		return -ENOMEM;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	map__set_end(map, xm->end);
124062306a36Sopenharmony_ci	map__set_pgoff(map, xm->pgoff);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	kmap = map__kmap(map);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	strlcpy(kmap->name, xm->name, KMAP_NAME_LEN);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	err = maps__insert(machine__kernel_maps(machine), map);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	if (!err) {
124962306a36Sopenharmony_ci		pr_debug2("Added extra kernel map %s %" PRIx64 "-%" PRIx64 "\n",
125062306a36Sopenharmony_ci			kmap->name, map__start(map), map__end(map));
125162306a36Sopenharmony_ci	}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	map__put(map);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	return err;
125662306a36Sopenharmony_ci}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_cistatic u64 find_entry_trampoline(struct dso *dso)
125962306a36Sopenharmony_ci{
126062306a36Sopenharmony_ci	/* Duplicates are removed so lookup all aliases */
126162306a36Sopenharmony_ci	const char *syms[] = {
126262306a36Sopenharmony_ci		"_entry_trampoline",
126362306a36Sopenharmony_ci		"__entry_trampoline_start",
126462306a36Sopenharmony_ci		"entry_SYSCALL_64_trampoline",
126562306a36Sopenharmony_ci	};
126662306a36Sopenharmony_ci	struct symbol *sym = dso__first_symbol(dso);
126762306a36Sopenharmony_ci	unsigned int i;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	for (; sym; sym = dso__next_symbol(sym)) {
127062306a36Sopenharmony_ci		if (sym->binding != STB_GLOBAL)
127162306a36Sopenharmony_ci			continue;
127262306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(syms); i++) {
127362306a36Sopenharmony_ci			if (!strcmp(sym->name, syms[i]))
127462306a36Sopenharmony_ci				return sym->start;
127562306a36Sopenharmony_ci		}
127662306a36Sopenharmony_ci	}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	return 0;
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci/*
128262306a36Sopenharmony_ci * These values can be used for kernels that do not have symbols for the entry
128362306a36Sopenharmony_ci * trampolines in kallsyms.
128462306a36Sopenharmony_ci */
128562306a36Sopenharmony_ci#define X86_64_CPU_ENTRY_AREA_PER_CPU	0xfffffe0000000000ULL
128662306a36Sopenharmony_ci#define X86_64_CPU_ENTRY_AREA_SIZE	0x2c000
128762306a36Sopenharmony_ci#define X86_64_ENTRY_TRAMPOLINE		0x6000
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci/* Map x86_64 PTI entry trampolines */
129062306a36Sopenharmony_ciint machine__map_x86_64_entry_trampolines(struct machine *machine,
129162306a36Sopenharmony_ci					  struct dso *kernel)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	struct maps *kmaps = machine__kernel_maps(machine);
129462306a36Sopenharmony_ci	int nr_cpus_avail, cpu;
129562306a36Sopenharmony_ci	bool found = false;
129662306a36Sopenharmony_ci	struct map_rb_node *rb_node;
129762306a36Sopenharmony_ci	u64 pgoff;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	/*
130062306a36Sopenharmony_ci	 * In the vmlinux case, pgoff is a virtual address which must now be
130162306a36Sopenharmony_ci	 * mapped to a vmlinux offset.
130262306a36Sopenharmony_ci	 */
130362306a36Sopenharmony_ci	maps__for_each_entry(kmaps, rb_node) {
130462306a36Sopenharmony_ci		struct map *dest_map, *map = rb_node->map;
130562306a36Sopenharmony_ci		struct kmap *kmap = __map__kmap(map);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci		if (!kmap || !is_entry_trampoline(kmap->name))
130862306a36Sopenharmony_ci			continue;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci		dest_map = maps__find(kmaps, map__pgoff(map));
131162306a36Sopenharmony_ci		if (dest_map != map)
131262306a36Sopenharmony_ci			map__set_pgoff(map, map__map_ip(dest_map, map__pgoff(map)));
131362306a36Sopenharmony_ci		found = true;
131462306a36Sopenharmony_ci	}
131562306a36Sopenharmony_ci	if (found || machine->trampolines_mapped)
131662306a36Sopenharmony_ci		return 0;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	pgoff = find_entry_trampoline(kernel);
131962306a36Sopenharmony_ci	if (!pgoff)
132062306a36Sopenharmony_ci		return 0;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	nr_cpus_avail = machine__nr_cpus_avail(machine);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	/* Add a 1 page map for each CPU's entry trampoline */
132562306a36Sopenharmony_ci	for (cpu = 0; cpu < nr_cpus_avail; cpu++) {
132662306a36Sopenharmony_ci		u64 va = X86_64_CPU_ENTRY_AREA_PER_CPU +
132762306a36Sopenharmony_ci			 cpu * X86_64_CPU_ENTRY_AREA_SIZE +
132862306a36Sopenharmony_ci			 X86_64_ENTRY_TRAMPOLINE;
132962306a36Sopenharmony_ci		struct extra_kernel_map xm = {
133062306a36Sopenharmony_ci			.start = va,
133162306a36Sopenharmony_ci			.end   = va + page_size,
133262306a36Sopenharmony_ci			.pgoff = pgoff,
133362306a36Sopenharmony_ci		};
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci		strlcpy(xm.name, ENTRY_TRAMPOLINE_NAME, KMAP_NAME_LEN);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci		if (machine__create_extra_kernel_map(machine, kernel, &xm) < 0)
133862306a36Sopenharmony_ci			return -1;
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	machine->trampolines_mapped = nr_cpus_avail;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	return 0;
134462306a36Sopenharmony_ci}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ciint __weak machine__create_extra_kernel_maps(struct machine *machine __maybe_unused,
134762306a36Sopenharmony_ci					     struct dso *kernel __maybe_unused)
134862306a36Sopenharmony_ci{
134962306a36Sopenharmony_ci	return 0;
135062306a36Sopenharmony_ci}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_cistatic int
135362306a36Sopenharmony_ci__machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
135462306a36Sopenharmony_ci{
135562306a36Sopenharmony_ci	/* In case of renewal the kernel map, destroy previous one */
135662306a36Sopenharmony_ci	machine__destroy_kernel_maps(machine);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	map__put(machine->vmlinux_map);
135962306a36Sopenharmony_ci	machine->vmlinux_map = map__new2(0, kernel);
136062306a36Sopenharmony_ci	if (machine->vmlinux_map == NULL)
136162306a36Sopenharmony_ci		return -ENOMEM;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	map__set_map_ip(machine->vmlinux_map, identity__map_ip);
136462306a36Sopenharmony_ci	map__set_unmap_ip(machine->vmlinux_map, identity__map_ip);
136562306a36Sopenharmony_ci	return maps__insert(machine__kernel_maps(machine), machine->vmlinux_map);
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_civoid machine__destroy_kernel_maps(struct machine *machine)
136962306a36Sopenharmony_ci{
137062306a36Sopenharmony_ci	struct kmap *kmap;
137162306a36Sopenharmony_ci	struct map *map = machine__kernel_map(machine);
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	if (map == NULL)
137462306a36Sopenharmony_ci		return;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	kmap = map__kmap(map);
137762306a36Sopenharmony_ci	maps__remove(machine__kernel_maps(machine), map);
137862306a36Sopenharmony_ci	if (kmap && kmap->ref_reloc_sym) {
137962306a36Sopenharmony_ci		zfree((char **)&kmap->ref_reloc_sym->name);
138062306a36Sopenharmony_ci		zfree(&kmap->ref_reloc_sym);
138162306a36Sopenharmony_ci	}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	map__zput(machine->vmlinux_map);
138462306a36Sopenharmony_ci}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ciint machines__create_guest_kernel_maps(struct machines *machines)
138762306a36Sopenharmony_ci{
138862306a36Sopenharmony_ci	int ret = 0;
138962306a36Sopenharmony_ci	struct dirent **namelist = NULL;
139062306a36Sopenharmony_ci	int i, items = 0;
139162306a36Sopenharmony_ci	char path[PATH_MAX];
139262306a36Sopenharmony_ci	pid_t pid;
139362306a36Sopenharmony_ci	char *endp;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	if (symbol_conf.default_guest_vmlinux_name ||
139662306a36Sopenharmony_ci	    symbol_conf.default_guest_modules ||
139762306a36Sopenharmony_ci	    symbol_conf.default_guest_kallsyms) {
139862306a36Sopenharmony_ci		machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
139962306a36Sopenharmony_ci	}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	if (symbol_conf.guestmount) {
140262306a36Sopenharmony_ci		items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
140362306a36Sopenharmony_ci		if (items <= 0)
140462306a36Sopenharmony_ci			return -ENOENT;
140562306a36Sopenharmony_ci		for (i = 0; i < items; i++) {
140662306a36Sopenharmony_ci			if (!isdigit(namelist[i]->d_name[0])) {
140762306a36Sopenharmony_ci				/* Filter out . and .. */
140862306a36Sopenharmony_ci				continue;
140962306a36Sopenharmony_ci			}
141062306a36Sopenharmony_ci			pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
141162306a36Sopenharmony_ci			if ((*endp != '\0') ||
141262306a36Sopenharmony_ci			    (endp == namelist[i]->d_name) ||
141362306a36Sopenharmony_ci			    (errno == ERANGE)) {
141462306a36Sopenharmony_ci				pr_debug("invalid directory (%s). Skipping.\n",
141562306a36Sopenharmony_ci					 namelist[i]->d_name);
141662306a36Sopenharmony_ci				continue;
141762306a36Sopenharmony_ci			}
141862306a36Sopenharmony_ci			sprintf(path, "%s/%s/proc/kallsyms",
141962306a36Sopenharmony_ci				symbol_conf.guestmount,
142062306a36Sopenharmony_ci				namelist[i]->d_name);
142162306a36Sopenharmony_ci			ret = access(path, R_OK);
142262306a36Sopenharmony_ci			if (ret) {
142362306a36Sopenharmony_ci				pr_debug("Can't access file %s\n", path);
142462306a36Sopenharmony_ci				goto failure;
142562306a36Sopenharmony_ci			}
142662306a36Sopenharmony_ci			machines__create_kernel_maps(machines, pid);
142762306a36Sopenharmony_ci		}
142862306a36Sopenharmony_cifailure:
142962306a36Sopenharmony_ci		free(namelist);
143062306a36Sopenharmony_ci	}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	return ret;
143362306a36Sopenharmony_ci}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_civoid machines__destroy_kernel_maps(struct machines *machines)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct rb_node *next = rb_first_cached(&machines->guests);
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	machine__destroy_kernel_maps(&machines->host);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	while (next) {
144262306a36Sopenharmony_ci		struct machine *pos = rb_entry(next, struct machine, rb_node);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci		next = rb_next(&pos->rb_node);
144562306a36Sopenharmony_ci		rb_erase_cached(&pos->rb_node, &machines->guests);
144662306a36Sopenharmony_ci		machine__delete(pos);
144762306a36Sopenharmony_ci	}
144862306a36Sopenharmony_ci}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ciint machines__create_kernel_maps(struct machines *machines, pid_t pid)
145162306a36Sopenharmony_ci{
145262306a36Sopenharmony_ci	struct machine *machine = machines__findnew(machines, pid);
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	if (machine == NULL)
145562306a36Sopenharmony_ci		return -1;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	return machine__create_kernel_maps(machine);
145862306a36Sopenharmony_ci}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ciint machine__load_kallsyms(struct machine *machine, const char *filename)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	struct map *map = machine__kernel_map(machine);
146362306a36Sopenharmony_ci	struct dso *dso = map__dso(map);
146462306a36Sopenharmony_ci	int ret = __dso__load_kallsyms(dso, filename, map, true);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	if (ret > 0) {
146762306a36Sopenharmony_ci		dso__set_loaded(dso);
146862306a36Sopenharmony_ci		/*
146962306a36Sopenharmony_ci		 * Since /proc/kallsyms will have multiple sessions for the
147062306a36Sopenharmony_ci		 * kernel, with modules between them, fixup the end of all
147162306a36Sopenharmony_ci		 * sections.
147262306a36Sopenharmony_ci		 */
147362306a36Sopenharmony_ci		maps__fixup_end(machine__kernel_maps(machine));
147462306a36Sopenharmony_ci	}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	return ret;
147762306a36Sopenharmony_ci}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ciint machine__load_vmlinux_path(struct machine *machine)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	struct map *map = machine__kernel_map(machine);
148262306a36Sopenharmony_ci	struct dso *dso = map__dso(map);
148362306a36Sopenharmony_ci	int ret = dso__load_vmlinux_path(dso, map);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	if (ret > 0)
148662306a36Sopenharmony_ci		dso__set_loaded(dso);
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	return ret;
148962306a36Sopenharmony_ci}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_cistatic char *get_kernel_version(const char *root_dir)
149262306a36Sopenharmony_ci{
149362306a36Sopenharmony_ci	char version[PATH_MAX];
149462306a36Sopenharmony_ci	FILE *file;
149562306a36Sopenharmony_ci	char *name, *tmp;
149662306a36Sopenharmony_ci	const char *prefix = "Linux version ";
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	sprintf(version, "%s/proc/version", root_dir);
149962306a36Sopenharmony_ci	file = fopen(version, "r");
150062306a36Sopenharmony_ci	if (!file)
150162306a36Sopenharmony_ci		return NULL;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	tmp = fgets(version, sizeof(version), file);
150462306a36Sopenharmony_ci	fclose(file);
150562306a36Sopenharmony_ci	if (!tmp)
150662306a36Sopenharmony_ci		return NULL;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	name = strstr(version, prefix);
150962306a36Sopenharmony_ci	if (!name)
151062306a36Sopenharmony_ci		return NULL;
151162306a36Sopenharmony_ci	name += strlen(prefix);
151262306a36Sopenharmony_ci	tmp = strchr(name, ' ');
151362306a36Sopenharmony_ci	if (tmp)
151462306a36Sopenharmony_ci		*tmp = '\0';
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	return strdup(name);
151762306a36Sopenharmony_ci}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_cistatic bool is_kmod_dso(struct dso *dso)
152062306a36Sopenharmony_ci{
152162306a36Sopenharmony_ci	return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
152262306a36Sopenharmony_ci	       dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
152362306a36Sopenharmony_ci}
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_cistatic int maps__set_module_path(struct maps *maps, const char *path, struct kmod_path *m)
152662306a36Sopenharmony_ci{
152762306a36Sopenharmony_ci	char *long_name;
152862306a36Sopenharmony_ci	struct dso *dso;
152962306a36Sopenharmony_ci	struct map *map = maps__find_by_name(maps, m->name);
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	if (map == NULL)
153262306a36Sopenharmony_ci		return 0;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	long_name = strdup(path);
153562306a36Sopenharmony_ci	if (long_name == NULL)
153662306a36Sopenharmony_ci		return -ENOMEM;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	dso = map__dso(map);
153962306a36Sopenharmony_ci	dso__set_long_name(dso, long_name, true);
154062306a36Sopenharmony_ci	dso__kernel_module_get_build_id(dso, "");
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	/*
154362306a36Sopenharmony_ci	 * Full name could reveal us kmod compression, so
154462306a36Sopenharmony_ci	 * we need to update the symtab_type if needed.
154562306a36Sopenharmony_ci	 */
154662306a36Sopenharmony_ci	if (m->comp && is_kmod_dso(dso)) {
154762306a36Sopenharmony_ci		dso->symtab_type++;
154862306a36Sopenharmony_ci		dso->comp = m->comp;
154962306a36Sopenharmony_ci	}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	return 0;
155262306a36Sopenharmony_ci}
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_cistatic int maps__set_modules_path_dir(struct maps *maps, const char *dir_name, int depth)
155562306a36Sopenharmony_ci{
155662306a36Sopenharmony_ci	struct dirent *dent;
155762306a36Sopenharmony_ci	DIR *dir = opendir(dir_name);
155862306a36Sopenharmony_ci	int ret = 0;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	if (!dir) {
156162306a36Sopenharmony_ci		pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
156262306a36Sopenharmony_ci		return -1;
156362306a36Sopenharmony_ci	}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	while ((dent = readdir(dir)) != NULL) {
156662306a36Sopenharmony_ci		char path[PATH_MAX];
156762306a36Sopenharmony_ci		struct stat st;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci		/*sshfs might return bad dent->d_type, so we have to stat*/
157062306a36Sopenharmony_ci		path__join(path, sizeof(path), dir_name, dent->d_name);
157162306a36Sopenharmony_ci		if (stat(path, &st))
157262306a36Sopenharmony_ci			continue;
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci		if (S_ISDIR(st.st_mode)) {
157562306a36Sopenharmony_ci			if (!strcmp(dent->d_name, ".") ||
157662306a36Sopenharmony_ci			    !strcmp(dent->d_name, ".."))
157762306a36Sopenharmony_ci				continue;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci			/* Do not follow top-level source and build symlinks */
158062306a36Sopenharmony_ci			if (depth == 0) {
158162306a36Sopenharmony_ci				if (!strcmp(dent->d_name, "source") ||
158262306a36Sopenharmony_ci				    !strcmp(dent->d_name, "build"))
158362306a36Sopenharmony_ci					continue;
158462306a36Sopenharmony_ci			}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci			ret = maps__set_modules_path_dir(maps, path, depth + 1);
158762306a36Sopenharmony_ci			if (ret < 0)
158862306a36Sopenharmony_ci				goto out;
158962306a36Sopenharmony_ci		} else {
159062306a36Sopenharmony_ci			struct kmod_path m;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci			ret = kmod_path__parse_name(&m, dent->d_name);
159362306a36Sopenharmony_ci			if (ret)
159462306a36Sopenharmony_ci				goto out;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci			if (m.kmod)
159762306a36Sopenharmony_ci				ret = maps__set_module_path(maps, path, &m);
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci			zfree(&m.name);
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci			if (ret)
160262306a36Sopenharmony_ci				goto out;
160362306a36Sopenharmony_ci		}
160462306a36Sopenharmony_ci	}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ciout:
160762306a36Sopenharmony_ci	closedir(dir);
160862306a36Sopenharmony_ci	return ret;
160962306a36Sopenharmony_ci}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_cistatic int machine__set_modules_path(struct machine *machine)
161262306a36Sopenharmony_ci{
161362306a36Sopenharmony_ci	char *version;
161462306a36Sopenharmony_ci	char modules_path[PATH_MAX];
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	version = get_kernel_version(machine->root_dir);
161762306a36Sopenharmony_ci	if (!version)
161862306a36Sopenharmony_ci		return -1;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s",
162162306a36Sopenharmony_ci		 machine->root_dir, version);
162262306a36Sopenharmony_ci	free(version);
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	return maps__set_modules_path_dir(machine__kernel_maps(machine), modules_path, 0);
162562306a36Sopenharmony_ci}
162662306a36Sopenharmony_ciint __weak arch__fix_module_text_start(u64 *start __maybe_unused,
162762306a36Sopenharmony_ci				u64 *size __maybe_unused,
162862306a36Sopenharmony_ci				const char *name __maybe_unused)
162962306a36Sopenharmony_ci{
163062306a36Sopenharmony_ci	return 0;
163162306a36Sopenharmony_ci}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_cistatic int machine__create_module(void *arg, const char *name, u64 start,
163462306a36Sopenharmony_ci				  u64 size)
163562306a36Sopenharmony_ci{
163662306a36Sopenharmony_ci	struct machine *machine = arg;
163762306a36Sopenharmony_ci	struct map *map;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	if (arch__fix_module_text_start(&start, &size, name) < 0)
164062306a36Sopenharmony_ci		return -1;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	map = machine__addnew_module_map(machine, start, name);
164362306a36Sopenharmony_ci	if (map == NULL)
164462306a36Sopenharmony_ci		return -1;
164562306a36Sopenharmony_ci	map__set_end(map, start + size);
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	dso__kernel_module_get_build_id(map__dso(map), machine->root_dir);
164862306a36Sopenharmony_ci	map__put(map);
164962306a36Sopenharmony_ci	return 0;
165062306a36Sopenharmony_ci}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_cistatic int machine__create_modules(struct machine *machine)
165362306a36Sopenharmony_ci{
165462306a36Sopenharmony_ci	const char *modules;
165562306a36Sopenharmony_ci	char path[PATH_MAX];
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	if (machine__is_default_guest(machine)) {
165862306a36Sopenharmony_ci		modules = symbol_conf.default_guest_modules;
165962306a36Sopenharmony_ci	} else {
166062306a36Sopenharmony_ci		snprintf(path, PATH_MAX, "%s/proc/modules", machine->root_dir);
166162306a36Sopenharmony_ci		modules = path;
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	if (symbol__restricted_filename(modules, "/proc/modules"))
166562306a36Sopenharmony_ci		return -1;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	if (modules__parse(modules, machine, machine__create_module))
166862306a36Sopenharmony_ci		return -1;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	if (!machine__set_modules_path(machine))
167162306a36Sopenharmony_ci		return 0;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	pr_debug("Problems setting modules path maps, continuing anyway...\n");
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	return 0;
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_cistatic void machine__set_kernel_mmap(struct machine *machine,
167962306a36Sopenharmony_ci				     u64 start, u64 end)
168062306a36Sopenharmony_ci{
168162306a36Sopenharmony_ci	map__set_start(machine->vmlinux_map, start);
168262306a36Sopenharmony_ci	map__set_end(machine->vmlinux_map, end);
168362306a36Sopenharmony_ci	/*
168462306a36Sopenharmony_ci	 * Be a bit paranoid here, some perf.data file came with
168562306a36Sopenharmony_ci	 * a zero sized synthesized MMAP event for the kernel.
168662306a36Sopenharmony_ci	 */
168762306a36Sopenharmony_ci	if (start == 0 && end == 0)
168862306a36Sopenharmony_ci		map__set_end(machine->vmlinux_map, ~0ULL);
168962306a36Sopenharmony_ci}
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_cistatic int machine__update_kernel_mmap(struct machine *machine,
169262306a36Sopenharmony_ci				     u64 start, u64 end)
169362306a36Sopenharmony_ci{
169462306a36Sopenharmony_ci	struct map *orig, *updated;
169562306a36Sopenharmony_ci	int err;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	orig = machine->vmlinux_map;
169862306a36Sopenharmony_ci	updated = map__get(orig);
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	machine->vmlinux_map = updated;
170162306a36Sopenharmony_ci	machine__set_kernel_mmap(machine, start, end);
170262306a36Sopenharmony_ci	maps__remove(machine__kernel_maps(machine), orig);
170362306a36Sopenharmony_ci	err = maps__insert(machine__kernel_maps(machine), updated);
170462306a36Sopenharmony_ci	map__put(orig);
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	return err;
170762306a36Sopenharmony_ci}
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ciint machine__create_kernel_maps(struct machine *machine)
171062306a36Sopenharmony_ci{
171162306a36Sopenharmony_ci	struct dso *kernel = machine__get_kernel(machine);
171262306a36Sopenharmony_ci	const char *name = NULL;
171362306a36Sopenharmony_ci	u64 start = 0, end = ~0ULL;
171462306a36Sopenharmony_ci	int ret;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	if (kernel == NULL)
171762306a36Sopenharmony_ci		return -1;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	ret = __machine__create_kernel_maps(machine, kernel);
172062306a36Sopenharmony_ci	if (ret < 0)
172162306a36Sopenharmony_ci		goto out_put;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
172462306a36Sopenharmony_ci		if (machine__is_host(machine))
172562306a36Sopenharmony_ci			pr_debug("Problems creating module maps, "
172662306a36Sopenharmony_ci				 "continuing anyway...\n");
172762306a36Sopenharmony_ci		else
172862306a36Sopenharmony_ci			pr_debug("Problems creating module maps for guest %d, "
172962306a36Sopenharmony_ci				 "continuing anyway...\n", machine->pid);
173062306a36Sopenharmony_ci	}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	if (!machine__get_running_kernel_start(machine, &name, &start, &end)) {
173362306a36Sopenharmony_ci		if (name &&
173462306a36Sopenharmony_ci		    map__set_kallsyms_ref_reloc_sym(machine->vmlinux_map, name, start)) {
173562306a36Sopenharmony_ci			machine__destroy_kernel_maps(machine);
173662306a36Sopenharmony_ci			ret = -1;
173762306a36Sopenharmony_ci			goto out_put;
173862306a36Sopenharmony_ci		}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci		/*
174162306a36Sopenharmony_ci		 * we have a real start address now, so re-order the kmaps
174262306a36Sopenharmony_ci		 * assume it's the last in the kmaps
174362306a36Sopenharmony_ci		 */
174462306a36Sopenharmony_ci		ret = machine__update_kernel_mmap(machine, start, end);
174562306a36Sopenharmony_ci		if (ret < 0)
174662306a36Sopenharmony_ci			goto out_put;
174762306a36Sopenharmony_ci	}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	if (machine__create_extra_kernel_maps(machine, kernel))
175062306a36Sopenharmony_ci		pr_debug("Problems creating extra kernel maps, continuing anyway...\n");
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	if (end == ~0ULL) {
175362306a36Sopenharmony_ci		/* update end address of the kernel map using adjacent module address */
175462306a36Sopenharmony_ci		struct map_rb_node *rb_node = maps__find_node(machine__kernel_maps(machine),
175562306a36Sopenharmony_ci							machine__kernel_map(machine));
175662306a36Sopenharmony_ci		struct map_rb_node *next = map_rb_node__next(rb_node);
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci		if (next)
175962306a36Sopenharmony_ci			machine__set_kernel_mmap(machine, start, map__start(next->map));
176062306a36Sopenharmony_ci	}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ciout_put:
176362306a36Sopenharmony_ci	dso__put(kernel);
176462306a36Sopenharmony_ci	return ret;
176562306a36Sopenharmony_ci}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_cistatic bool machine__uses_kcore(struct machine *machine)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	struct dso *dso;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	list_for_each_entry(dso, &machine->dsos.head, node) {
177262306a36Sopenharmony_ci		if (dso__is_kcore(dso))
177362306a36Sopenharmony_ci			return true;
177462306a36Sopenharmony_ci	}
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	return false;
177762306a36Sopenharmony_ci}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_cistatic bool perf_event__is_extra_kernel_mmap(struct machine *machine,
178062306a36Sopenharmony_ci					     struct extra_kernel_map *xm)
178162306a36Sopenharmony_ci{
178262306a36Sopenharmony_ci	return machine__is(machine, "x86_64") &&
178362306a36Sopenharmony_ci	       is_entry_trampoline(xm->name);
178462306a36Sopenharmony_ci}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_cistatic int machine__process_extra_kernel_map(struct machine *machine,
178762306a36Sopenharmony_ci					     struct extra_kernel_map *xm)
178862306a36Sopenharmony_ci{
178962306a36Sopenharmony_ci	struct dso *kernel = machine__kernel_dso(machine);
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	if (kernel == NULL)
179262306a36Sopenharmony_ci		return -1;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	return machine__create_extra_kernel_map(machine, kernel, xm);
179562306a36Sopenharmony_ci}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_cistatic int machine__process_kernel_mmap_event(struct machine *machine,
179862306a36Sopenharmony_ci					      struct extra_kernel_map *xm,
179962306a36Sopenharmony_ci					      struct build_id *bid)
180062306a36Sopenharmony_ci{
180162306a36Sopenharmony_ci	enum dso_space_type dso_space;
180262306a36Sopenharmony_ci	bool is_kernel_mmap;
180362306a36Sopenharmony_ci	const char *mmap_name = machine->mmap_name;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	/* If we have maps from kcore then we do not need or want any others */
180662306a36Sopenharmony_ci	if (machine__uses_kcore(machine))
180762306a36Sopenharmony_ci		return 0;
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	if (machine__is_host(machine))
181062306a36Sopenharmony_ci		dso_space = DSO_SPACE__KERNEL;
181162306a36Sopenharmony_ci	else
181262306a36Sopenharmony_ci		dso_space = DSO_SPACE__KERNEL_GUEST;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	is_kernel_mmap = memcmp(xm->name, mmap_name, strlen(mmap_name) - 1) == 0;
181562306a36Sopenharmony_ci	if (!is_kernel_mmap && !machine__is_host(machine)) {
181662306a36Sopenharmony_ci		/*
181762306a36Sopenharmony_ci		 * If the event was recorded inside the guest and injected into
181862306a36Sopenharmony_ci		 * the host perf.data file, then it will match a host mmap_name,
181962306a36Sopenharmony_ci		 * so try that - see machine__set_mmap_name().
182062306a36Sopenharmony_ci		 */
182162306a36Sopenharmony_ci		mmap_name = "[kernel.kallsyms]";
182262306a36Sopenharmony_ci		is_kernel_mmap = memcmp(xm->name, mmap_name, strlen(mmap_name) - 1) == 0;
182362306a36Sopenharmony_ci	}
182462306a36Sopenharmony_ci	if (xm->name[0] == '/' ||
182562306a36Sopenharmony_ci	    (!is_kernel_mmap && xm->name[0] == '[')) {
182662306a36Sopenharmony_ci		struct map *map = machine__addnew_module_map(machine, xm->start, xm->name);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci		if (map == NULL)
182962306a36Sopenharmony_ci			goto out_problem;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci		map__set_end(map, map__start(map) + xm->end - xm->start);
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci		if (build_id__is_defined(bid))
183462306a36Sopenharmony_ci			dso__set_build_id(map__dso(map), bid);
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci		map__put(map);
183762306a36Sopenharmony_ci	} else if (is_kernel_mmap) {
183862306a36Sopenharmony_ci		const char *symbol_name = xm->name + strlen(mmap_name);
183962306a36Sopenharmony_ci		/*
184062306a36Sopenharmony_ci		 * Should be there already, from the build-id table in
184162306a36Sopenharmony_ci		 * the header.
184262306a36Sopenharmony_ci		 */
184362306a36Sopenharmony_ci		struct dso *kernel = NULL;
184462306a36Sopenharmony_ci		struct dso *dso;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci		down_read(&machine->dsos.lock);
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci		list_for_each_entry(dso, &machine->dsos.head, node) {
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci			/*
185162306a36Sopenharmony_ci			 * The cpumode passed to is_kernel_module is not the
185262306a36Sopenharmony_ci			 * cpumode of *this* event. If we insist on passing
185362306a36Sopenharmony_ci			 * correct cpumode to is_kernel_module, we should
185462306a36Sopenharmony_ci			 * record the cpumode when we adding this dso to the
185562306a36Sopenharmony_ci			 * linked list.
185662306a36Sopenharmony_ci			 *
185762306a36Sopenharmony_ci			 * However we don't really need passing correct
185862306a36Sopenharmony_ci			 * cpumode.  We know the correct cpumode must be kernel
185962306a36Sopenharmony_ci			 * mode (if not, we should not link it onto kernel_dsos
186062306a36Sopenharmony_ci			 * list).
186162306a36Sopenharmony_ci			 *
186262306a36Sopenharmony_ci			 * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN.
186362306a36Sopenharmony_ci			 * is_kernel_module() treats it as a kernel cpumode.
186462306a36Sopenharmony_ci			 */
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci			if (!dso->kernel ||
186762306a36Sopenharmony_ci			    is_kernel_module(dso->long_name,
186862306a36Sopenharmony_ci					     PERF_RECORD_MISC_CPUMODE_UNKNOWN))
186962306a36Sopenharmony_ci				continue;
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci			kernel = dso__get(dso);
187362306a36Sopenharmony_ci			break;
187462306a36Sopenharmony_ci		}
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci		up_read(&machine->dsos.lock);
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci		if (kernel == NULL)
187962306a36Sopenharmony_ci			kernel = machine__findnew_dso(machine, machine->mmap_name);
188062306a36Sopenharmony_ci		if (kernel == NULL)
188162306a36Sopenharmony_ci			goto out_problem;
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci		kernel->kernel = dso_space;
188462306a36Sopenharmony_ci		if (__machine__create_kernel_maps(machine, kernel) < 0) {
188562306a36Sopenharmony_ci			dso__put(kernel);
188662306a36Sopenharmony_ci			goto out_problem;
188762306a36Sopenharmony_ci		}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci		if (strstr(kernel->long_name, "vmlinux"))
189062306a36Sopenharmony_ci			dso__set_short_name(kernel, "[kernel.vmlinux]", false);
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci		if (machine__update_kernel_mmap(machine, xm->start, xm->end) < 0) {
189362306a36Sopenharmony_ci			dso__put(kernel);
189462306a36Sopenharmony_ci			goto out_problem;
189562306a36Sopenharmony_ci		}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci		if (build_id__is_defined(bid))
189862306a36Sopenharmony_ci			dso__set_build_id(kernel, bid);
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci		/*
190162306a36Sopenharmony_ci		 * Avoid using a zero address (kptr_restrict) for the ref reloc
190262306a36Sopenharmony_ci		 * symbol. Effectively having zero here means that at record
190362306a36Sopenharmony_ci		 * time /proc/sys/kernel/kptr_restrict was non zero.
190462306a36Sopenharmony_ci		 */
190562306a36Sopenharmony_ci		if (xm->pgoff != 0) {
190662306a36Sopenharmony_ci			map__set_kallsyms_ref_reloc_sym(machine->vmlinux_map,
190762306a36Sopenharmony_ci							symbol_name,
190862306a36Sopenharmony_ci							xm->pgoff);
190962306a36Sopenharmony_ci		}
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci		if (machine__is_default_guest(machine)) {
191262306a36Sopenharmony_ci			/*
191362306a36Sopenharmony_ci			 * preload dso of guest kernel and modules
191462306a36Sopenharmony_ci			 */
191562306a36Sopenharmony_ci			dso__load(kernel, machine__kernel_map(machine));
191662306a36Sopenharmony_ci		}
191762306a36Sopenharmony_ci		dso__put(kernel);
191862306a36Sopenharmony_ci	} else if (perf_event__is_extra_kernel_mmap(machine, xm)) {
191962306a36Sopenharmony_ci		return machine__process_extra_kernel_map(machine, xm);
192062306a36Sopenharmony_ci	}
192162306a36Sopenharmony_ci	return 0;
192262306a36Sopenharmony_ciout_problem:
192362306a36Sopenharmony_ci	return -1;
192462306a36Sopenharmony_ci}
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ciint machine__process_mmap2_event(struct machine *machine,
192762306a36Sopenharmony_ci				 union perf_event *event,
192862306a36Sopenharmony_ci				 struct perf_sample *sample)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	struct thread *thread;
193162306a36Sopenharmony_ci	struct map *map;
193262306a36Sopenharmony_ci	struct dso_id dso_id = {
193362306a36Sopenharmony_ci		.maj = event->mmap2.maj,
193462306a36Sopenharmony_ci		.min = event->mmap2.min,
193562306a36Sopenharmony_ci		.ino = event->mmap2.ino,
193662306a36Sopenharmony_ci		.ino_generation = event->mmap2.ino_generation,
193762306a36Sopenharmony_ci	};
193862306a36Sopenharmony_ci	struct build_id __bid, *bid = NULL;
193962306a36Sopenharmony_ci	int ret = 0;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	if (dump_trace)
194262306a36Sopenharmony_ci		perf_event__fprintf_mmap2(event, stdout);
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
194562306a36Sopenharmony_ci		bid = &__bid;
194662306a36Sopenharmony_ci		build_id__init(bid, event->mmap2.build_id, event->mmap2.build_id_size);
194762306a36Sopenharmony_ci	}
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
195062306a36Sopenharmony_ci	    sample->cpumode == PERF_RECORD_MISC_KERNEL) {
195162306a36Sopenharmony_ci		struct extra_kernel_map xm = {
195262306a36Sopenharmony_ci			.start = event->mmap2.start,
195362306a36Sopenharmony_ci			.end   = event->mmap2.start + event->mmap2.len,
195462306a36Sopenharmony_ci			.pgoff = event->mmap2.pgoff,
195562306a36Sopenharmony_ci		};
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci		strlcpy(xm.name, event->mmap2.filename, KMAP_NAME_LEN);
195862306a36Sopenharmony_ci		ret = machine__process_kernel_mmap_event(machine, &xm, bid);
195962306a36Sopenharmony_ci		if (ret < 0)
196062306a36Sopenharmony_ci			goto out_problem;
196162306a36Sopenharmony_ci		return 0;
196262306a36Sopenharmony_ci	}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	thread = machine__findnew_thread(machine, event->mmap2.pid,
196562306a36Sopenharmony_ci					event->mmap2.tid);
196662306a36Sopenharmony_ci	if (thread == NULL)
196762306a36Sopenharmony_ci		goto out_problem;
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	map = map__new(machine, event->mmap2.start,
197062306a36Sopenharmony_ci			event->mmap2.len, event->mmap2.pgoff,
197162306a36Sopenharmony_ci			&dso_id, event->mmap2.prot,
197262306a36Sopenharmony_ci			event->mmap2.flags, bid,
197362306a36Sopenharmony_ci			event->mmap2.filename, thread);
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	if (map == NULL)
197662306a36Sopenharmony_ci		goto out_problem_map;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	ret = thread__insert_map(thread, map);
197962306a36Sopenharmony_ci	if (ret)
198062306a36Sopenharmony_ci		goto out_problem_insert;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	thread__put(thread);
198362306a36Sopenharmony_ci	map__put(map);
198462306a36Sopenharmony_ci	return 0;
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ciout_problem_insert:
198762306a36Sopenharmony_ci	map__put(map);
198862306a36Sopenharmony_ciout_problem_map:
198962306a36Sopenharmony_ci	thread__put(thread);
199062306a36Sopenharmony_ciout_problem:
199162306a36Sopenharmony_ci	dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n");
199262306a36Sopenharmony_ci	return 0;
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ciint machine__process_mmap_event(struct machine *machine, union perf_event *event,
199662306a36Sopenharmony_ci				struct perf_sample *sample)
199762306a36Sopenharmony_ci{
199862306a36Sopenharmony_ci	struct thread *thread;
199962306a36Sopenharmony_ci	struct map *map;
200062306a36Sopenharmony_ci	u32 prot = 0;
200162306a36Sopenharmony_ci	int ret = 0;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	if (dump_trace)
200462306a36Sopenharmony_ci		perf_event__fprintf_mmap(event, stdout);
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
200762306a36Sopenharmony_ci	    sample->cpumode == PERF_RECORD_MISC_KERNEL) {
200862306a36Sopenharmony_ci		struct extra_kernel_map xm = {
200962306a36Sopenharmony_ci			.start = event->mmap.start,
201062306a36Sopenharmony_ci			.end   = event->mmap.start + event->mmap.len,
201162306a36Sopenharmony_ci			.pgoff = event->mmap.pgoff,
201262306a36Sopenharmony_ci		};
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci		strlcpy(xm.name, event->mmap.filename, KMAP_NAME_LEN);
201562306a36Sopenharmony_ci		ret = machine__process_kernel_mmap_event(machine, &xm, NULL);
201662306a36Sopenharmony_ci		if (ret < 0)
201762306a36Sopenharmony_ci			goto out_problem;
201862306a36Sopenharmony_ci		return 0;
201962306a36Sopenharmony_ci	}
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	thread = machine__findnew_thread(machine, event->mmap.pid,
202262306a36Sopenharmony_ci					 event->mmap.tid);
202362306a36Sopenharmony_ci	if (thread == NULL)
202462306a36Sopenharmony_ci		goto out_problem;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	if (!(event->header.misc & PERF_RECORD_MISC_MMAP_DATA))
202762306a36Sopenharmony_ci		prot = PROT_EXEC;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	map = map__new(machine, event->mmap.start,
203062306a36Sopenharmony_ci			event->mmap.len, event->mmap.pgoff,
203162306a36Sopenharmony_ci			NULL, prot, 0, NULL, event->mmap.filename, thread);
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	if (map == NULL)
203462306a36Sopenharmony_ci		goto out_problem_map;
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci	ret = thread__insert_map(thread, map);
203762306a36Sopenharmony_ci	if (ret)
203862306a36Sopenharmony_ci		goto out_problem_insert;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	thread__put(thread);
204162306a36Sopenharmony_ci	map__put(map);
204262306a36Sopenharmony_ci	return 0;
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ciout_problem_insert:
204562306a36Sopenharmony_ci	map__put(map);
204662306a36Sopenharmony_ciout_problem_map:
204762306a36Sopenharmony_ci	thread__put(thread);
204862306a36Sopenharmony_ciout_problem:
204962306a36Sopenharmony_ci	dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
205062306a36Sopenharmony_ci	return 0;
205162306a36Sopenharmony_ci}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_cistatic void __machine__remove_thread(struct machine *machine, struct thread_rb_node *nd,
205462306a36Sopenharmony_ci				     struct thread *th, bool lock)
205562306a36Sopenharmony_ci{
205662306a36Sopenharmony_ci	struct threads *threads = machine__threads(machine, thread__tid(th));
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	if (!nd)
205962306a36Sopenharmony_ci		nd = thread_rb_node__find(th, &threads->entries.rb_root);
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	if (threads->last_match && RC_CHK_ACCESS(threads->last_match) == RC_CHK_ACCESS(th))
206262306a36Sopenharmony_ci		threads__set_last_match(threads, NULL);
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	if (lock)
206562306a36Sopenharmony_ci		down_write(&threads->lock);
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	BUG_ON(refcount_read(thread__refcnt(th)) == 0);
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	thread__put(nd->thread);
207062306a36Sopenharmony_ci	rb_erase_cached(&nd->rb_node, &threads->entries);
207162306a36Sopenharmony_ci	RB_CLEAR_NODE(&nd->rb_node);
207262306a36Sopenharmony_ci	--threads->nr;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	free(nd);
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci	if (lock)
207762306a36Sopenharmony_ci		up_write(&threads->lock);
207862306a36Sopenharmony_ci}
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_civoid machine__remove_thread(struct machine *machine, struct thread *th)
208162306a36Sopenharmony_ci{
208262306a36Sopenharmony_ci	return __machine__remove_thread(machine, NULL, th, true);
208362306a36Sopenharmony_ci}
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ciint machine__process_fork_event(struct machine *machine, union perf_event *event,
208662306a36Sopenharmony_ci				struct perf_sample *sample)
208762306a36Sopenharmony_ci{
208862306a36Sopenharmony_ci	struct thread *thread = machine__find_thread(machine,
208962306a36Sopenharmony_ci						     event->fork.pid,
209062306a36Sopenharmony_ci						     event->fork.tid);
209162306a36Sopenharmony_ci	struct thread *parent = machine__findnew_thread(machine,
209262306a36Sopenharmony_ci							event->fork.ppid,
209362306a36Sopenharmony_ci							event->fork.ptid);
209462306a36Sopenharmony_ci	bool do_maps_clone = true;
209562306a36Sopenharmony_ci	int err = 0;
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	if (dump_trace)
209862306a36Sopenharmony_ci		perf_event__fprintf_task(event, stdout);
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	/*
210162306a36Sopenharmony_ci	 * There may be an existing thread that is not actually the parent,
210262306a36Sopenharmony_ci	 * either because we are processing events out of order, or because the
210362306a36Sopenharmony_ci	 * (fork) event that would have removed the thread was lost. Assume the
210462306a36Sopenharmony_ci	 * latter case and continue on as best we can.
210562306a36Sopenharmony_ci	 */
210662306a36Sopenharmony_ci	if (thread__pid(parent) != (pid_t)event->fork.ppid) {
210762306a36Sopenharmony_ci		dump_printf("removing erroneous parent thread %d/%d\n",
210862306a36Sopenharmony_ci			    thread__pid(parent), thread__tid(parent));
210962306a36Sopenharmony_ci		machine__remove_thread(machine, parent);
211062306a36Sopenharmony_ci		thread__put(parent);
211162306a36Sopenharmony_ci		parent = machine__findnew_thread(machine, event->fork.ppid,
211262306a36Sopenharmony_ci						 event->fork.ptid);
211362306a36Sopenharmony_ci	}
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	/* if a thread currently exists for the thread id remove it */
211662306a36Sopenharmony_ci	if (thread != NULL) {
211762306a36Sopenharmony_ci		machine__remove_thread(machine, thread);
211862306a36Sopenharmony_ci		thread__put(thread);
211962306a36Sopenharmony_ci	}
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	thread = machine__findnew_thread(machine, event->fork.pid,
212262306a36Sopenharmony_ci					 event->fork.tid);
212362306a36Sopenharmony_ci	/*
212462306a36Sopenharmony_ci	 * When synthesizing FORK events, we are trying to create thread
212562306a36Sopenharmony_ci	 * objects for the already running tasks on the machine.
212662306a36Sopenharmony_ci	 *
212762306a36Sopenharmony_ci	 * Normally, for a kernel FORK event, we want to clone the parent's
212862306a36Sopenharmony_ci	 * maps because that is what the kernel just did.
212962306a36Sopenharmony_ci	 *
213062306a36Sopenharmony_ci	 * But when synthesizing, this should not be done.  If we do, we end up
213162306a36Sopenharmony_ci	 * with overlapping maps as we process the synthesized MMAP2 events that
213262306a36Sopenharmony_ci	 * get delivered shortly thereafter.
213362306a36Sopenharmony_ci	 *
213462306a36Sopenharmony_ci	 * Use the FORK event misc flags in an internal way to signal this
213562306a36Sopenharmony_ci	 * situation, so we can elide the map clone when appropriate.
213662306a36Sopenharmony_ci	 */
213762306a36Sopenharmony_ci	if (event->fork.header.misc & PERF_RECORD_MISC_FORK_EXEC)
213862306a36Sopenharmony_ci		do_maps_clone = false;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	if (thread == NULL || parent == NULL ||
214162306a36Sopenharmony_ci	    thread__fork(thread, parent, sample->time, do_maps_clone) < 0) {
214262306a36Sopenharmony_ci		dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
214362306a36Sopenharmony_ci		err = -1;
214462306a36Sopenharmony_ci	}
214562306a36Sopenharmony_ci	thread__put(thread);
214662306a36Sopenharmony_ci	thread__put(parent);
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	return err;
214962306a36Sopenharmony_ci}
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ciint machine__process_exit_event(struct machine *machine, union perf_event *event,
215262306a36Sopenharmony_ci				struct perf_sample *sample __maybe_unused)
215362306a36Sopenharmony_ci{
215462306a36Sopenharmony_ci	struct thread *thread = machine__find_thread(machine,
215562306a36Sopenharmony_ci						     event->fork.pid,
215662306a36Sopenharmony_ci						     event->fork.tid);
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	if (dump_trace)
215962306a36Sopenharmony_ci		perf_event__fprintf_task(event, stdout);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	if (thread != NULL)
216262306a36Sopenharmony_ci		thread__put(thread);
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	return 0;
216562306a36Sopenharmony_ci}
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ciint machine__process_event(struct machine *machine, union perf_event *event,
216862306a36Sopenharmony_ci			   struct perf_sample *sample)
216962306a36Sopenharmony_ci{
217062306a36Sopenharmony_ci	int ret;
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	switch (event->header.type) {
217362306a36Sopenharmony_ci	case PERF_RECORD_COMM:
217462306a36Sopenharmony_ci		ret = machine__process_comm_event(machine, event, sample); break;
217562306a36Sopenharmony_ci	case PERF_RECORD_MMAP:
217662306a36Sopenharmony_ci		ret = machine__process_mmap_event(machine, event, sample); break;
217762306a36Sopenharmony_ci	case PERF_RECORD_NAMESPACES:
217862306a36Sopenharmony_ci		ret = machine__process_namespaces_event(machine, event, sample); break;
217962306a36Sopenharmony_ci	case PERF_RECORD_CGROUP:
218062306a36Sopenharmony_ci		ret = machine__process_cgroup_event(machine, event, sample); break;
218162306a36Sopenharmony_ci	case PERF_RECORD_MMAP2:
218262306a36Sopenharmony_ci		ret = machine__process_mmap2_event(machine, event, sample); break;
218362306a36Sopenharmony_ci	case PERF_RECORD_FORK:
218462306a36Sopenharmony_ci		ret = machine__process_fork_event(machine, event, sample); break;
218562306a36Sopenharmony_ci	case PERF_RECORD_EXIT:
218662306a36Sopenharmony_ci		ret = machine__process_exit_event(machine, event, sample); break;
218762306a36Sopenharmony_ci	case PERF_RECORD_LOST:
218862306a36Sopenharmony_ci		ret = machine__process_lost_event(machine, event, sample); break;
218962306a36Sopenharmony_ci	case PERF_RECORD_AUX:
219062306a36Sopenharmony_ci		ret = machine__process_aux_event(machine, event); break;
219162306a36Sopenharmony_ci	case PERF_RECORD_ITRACE_START:
219262306a36Sopenharmony_ci		ret = machine__process_itrace_start_event(machine, event); break;
219362306a36Sopenharmony_ci	case PERF_RECORD_LOST_SAMPLES:
219462306a36Sopenharmony_ci		ret = machine__process_lost_samples_event(machine, event, sample); break;
219562306a36Sopenharmony_ci	case PERF_RECORD_SWITCH:
219662306a36Sopenharmony_ci	case PERF_RECORD_SWITCH_CPU_WIDE:
219762306a36Sopenharmony_ci		ret = machine__process_switch_event(machine, event); break;
219862306a36Sopenharmony_ci	case PERF_RECORD_KSYMBOL:
219962306a36Sopenharmony_ci		ret = machine__process_ksymbol(machine, event, sample); break;
220062306a36Sopenharmony_ci	case PERF_RECORD_BPF_EVENT:
220162306a36Sopenharmony_ci		ret = machine__process_bpf(machine, event, sample); break;
220262306a36Sopenharmony_ci	case PERF_RECORD_TEXT_POKE:
220362306a36Sopenharmony_ci		ret = machine__process_text_poke(machine, event, sample); break;
220462306a36Sopenharmony_ci	case PERF_RECORD_AUX_OUTPUT_HW_ID:
220562306a36Sopenharmony_ci		ret = machine__process_aux_output_hw_id_event(machine, event); break;
220662306a36Sopenharmony_ci	default:
220762306a36Sopenharmony_ci		ret = -1;
220862306a36Sopenharmony_ci		break;
220962306a36Sopenharmony_ci	}
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	return ret;
221262306a36Sopenharmony_ci}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_cistatic bool symbol__match_regex(struct symbol *sym, regex_t *regex)
221562306a36Sopenharmony_ci{
221662306a36Sopenharmony_ci	if (!regexec(regex, sym->name, 0, NULL, 0))
221762306a36Sopenharmony_ci		return true;
221862306a36Sopenharmony_ci	return false;
221962306a36Sopenharmony_ci}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_cistatic void ip__resolve_ams(struct thread *thread,
222262306a36Sopenharmony_ci			    struct addr_map_symbol *ams,
222362306a36Sopenharmony_ci			    u64 ip)
222462306a36Sopenharmony_ci{
222562306a36Sopenharmony_ci	struct addr_location al;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	addr_location__init(&al);
222862306a36Sopenharmony_ci	/*
222962306a36Sopenharmony_ci	 * We cannot use the header.misc hint to determine whether a
223062306a36Sopenharmony_ci	 * branch stack address is user, kernel, guest, hypervisor.
223162306a36Sopenharmony_ci	 * Branches may straddle the kernel/user/hypervisor boundaries.
223262306a36Sopenharmony_ci	 * Thus, we have to try consecutively until we find a match
223362306a36Sopenharmony_ci	 * or else, the symbol is unknown
223462306a36Sopenharmony_ci	 */
223562306a36Sopenharmony_ci	thread__find_cpumode_addr_location(thread, ip, &al);
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	ams->addr = ip;
223862306a36Sopenharmony_ci	ams->al_addr = al.addr;
223962306a36Sopenharmony_ci	ams->al_level = al.level;
224062306a36Sopenharmony_ci	ams->ms.maps = maps__get(al.maps);
224162306a36Sopenharmony_ci	ams->ms.sym = al.sym;
224262306a36Sopenharmony_ci	ams->ms.map = map__get(al.map);
224362306a36Sopenharmony_ci	ams->phys_addr = 0;
224462306a36Sopenharmony_ci	ams->data_page_size = 0;
224562306a36Sopenharmony_ci	addr_location__exit(&al);
224662306a36Sopenharmony_ci}
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_cistatic void ip__resolve_data(struct thread *thread,
224962306a36Sopenharmony_ci			     u8 m, struct addr_map_symbol *ams,
225062306a36Sopenharmony_ci			     u64 addr, u64 phys_addr, u64 daddr_page_size)
225162306a36Sopenharmony_ci{
225262306a36Sopenharmony_ci	struct addr_location al;
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	addr_location__init(&al);
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	thread__find_symbol(thread, m, addr, &al);
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	ams->addr = addr;
225962306a36Sopenharmony_ci	ams->al_addr = al.addr;
226062306a36Sopenharmony_ci	ams->al_level = al.level;
226162306a36Sopenharmony_ci	ams->ms.maps = maps__get(al.maps);
226262306a36Sopenharmony_ci	ams->ms.sym = al.sym;
226362306a36Sopenharmony_ci	ams->ms.map = map__get(al.map);
226462306a36Sopenharmony_ci	ams->phys_addr = phys_addr;
226562306a36Sopenharmony_ci	ams->data_page_size = daddr_page_size;
226662306a36Sopenharmony_ci	addr_location__exit(&al);
226762306a36Sopenharmony_ci}
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_cistruct mem_info *sample__resolve_mem(struct perf_sample *sample,
227062306a36Sopenharmony_ci				     struct addr_location *al)
227162306a36Sopenharmony_ci{
227262306a36Sopenharmony_ci	struct mem_info *mi = mem_info__new();
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	if (!mi)
227562306a36Sopenharmony_ci		return NULL;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	ip__resolve_ams(al->thread, &mi->iaddr, sample->ip);
227862306a36Sopenharmony_ci	ip__resolve_data(al->thread, al->cpumode, &mi->daddr,
227962306a36Sopenharmony_ci			 sample->addr, sample->phys_addr,
228062306a36Sopenharmony_ci			 sample->data_page_size);
228162306a36Sopenharmony_ci	mi->data_src.val = sample->data_src;
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	return mi;
228462306a36Sopenharmony_ci}
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_cistatic char *callchain_srcline(struct map_symbol *ms, u64 ip)
228762306a36Sopenharmony_ci{
228862306a36Sopenharmony_ci	struct map *map = ms->map;
228962306a36Sopenharmony_ci	char *srcline = NULL;
229062306a36Sopenharmony_ci	struct dso *dso;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	if (!map || callchain_param.key == CCKEY_FUNCTION)
229362306a36Sopenharmony_ci		return srcline;
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	dso = map__dso(map);
229662306a36Sopenharmony_ci	srcline = srcline__tree_find(&dso->srclines, ip);
229762306a36Sopenharmony_ci	if (!srcline) {
229862306a36Sopenharmony_ci		bool show_sym = false;
229962306a36Sopenharmony_ci		bool show_addr = callchain_param.key == CCKEY_ADDRESS;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci		srcline = get_srcline(dso, map__rip_2objdump(map, ip),
230262306a36Sopenharmony_ci				      ms->sym, show_sym, show_addr, ip);
230362306a36Sopenharmony_ci		srcline__tree_insert(&dso->srclines, ip, srcline);
230462306a36Sopenharmony_ci	}
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	return srcline;
230762306a36Sopenharmony_ci}
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_cistruct iterations {
231062306a36Sopenharmony_ci	int nr_loop_iter;
231162306a36Sopenharmony_ci	u64 cycles;
231262306a36Sopenharmony_ci};
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_cistatic int add_callchain_ip(struct thread *thread,
231562306a36Sopenharmony_ci			    struct callchain_cursor *cursor,
231662306a36Sopenharmony_ci			    struct symbol **parent,
231762306a36Sopenharmony_ci			    struct addr_location *root_al,
231862306a36Sopenharmony_ci			    u8 *cpumode,
231962306a36Sopenharmony_ci			    u64 ip,
232062306a36Sopenharmony_ci			    bool branch,
232162306a36Sopenharmony_ci			    struct branch_flags *flags,
232262306a36Sopenharmony_ci			    struct iterations *iter,
232362306a36Sopenharmony_ci			    u64 branch_from)
232462306a36Sopenharmony_ci{
232562306a36Sopenharmony_ci	struct map_symbol ms = {};
232662306a36Sopenharmony_ci	struct addr_location al;
232762306a36Sopenharmony_ci	int nr_loop_iter = 0, err = 0;
232862306a36Sopenharmony_ci	u64 iter_cycles = 0;
232962306a36Sopenharmony_ci	const char *srcline = NULL;
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci	addr_location__init(&al);
233262306a36Sopenharmony_ci	al.filtered = 0;
233362306a36Sopenharmony_ci	al.sym = NULL;
233462306a36Sopenharmony_ci	al.srcline = NULL;
233562306a36Sopenharmony_ci	if (!cpumode) {
233662306a36Sopenharmony_ci		thread__find_cpumode_addr_location(thread, ip, &al);
233762306a36Sopenharmony_ci	} else {
233862306a36Sopenharmony_ci		if (ip >= PERF_CONTEXT_MAX) {
233962306a36Sopenharmony_ci			switch (ip) {
234062306a36Sopenharmony_ci			case PERF_CONTEXT_HV:
234162306a36Sopenharmony_ci				*cpumode = PERF_RECORD_MISC_HYPERVISOR;
234262306a36Sopenharmony_ci				break;
234362306a36Sopenharmony_ci			case PERF_CONTEXT_KERNEL:
234462306a36Sopenharmony_ci				*cpumode = PERF_RECORD_MISC_KERNEL;
234562306a36Sopenharmony_ci				break;
234662306a36Sopenharmony_ci			case PERF_CONTEXT_USER:
234762306a36Sopenharmony_ci				*cpumode = PERF_RECORD_MISC_USER;
234862306a36Sopenharmony_ci				break;
234962306a36Sopenharmony_ci			default:
235062306a36Sopenharmony_ci				pr_debug("invalid callchain context: "
235162306a36Sopenharmony_ci					 "%"PRId64"\n", (s64) ip);
235262306a36Sopenharmony_ci				/*
235362306a36Sopenharmony_ci				 * It seems the callchain is corrupted.
235462306a36Sopenharmony_ci				 * Discard all.
235562306a36Sopenharmony_ci				 */
235662306a36Sopenharmony_ci				callchain_cursor_reset(cursor);
235762306a36Sopenharmony_ci				err = 1;
235862306a36Sopenharmony_ci				goto out;
235962306a36Sopenharmony_ci			}
236062306a36Sopenharmony_ci			goto out;
236162306a36Sopenharmony_ci		}
236262306a36Sopenharmony_ci		thread__find_symbol(thread, *cpumode, ip, &al);
236362306a36Sopenharmony_ci	}
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci	if (al.sym != NULL) {
236662306a36Sopenharmony_ci		if (perf_hpp_list.parent && !*parent &&
236762306a36Sopenharmony_ci		    symbol__match_regex(al.sym, &parent_regex))
236862306a36Sopenharmony_ci			*parent = al.sym;
236962306a36Sopenharmony_ci		else if (have_ignore_callees && root_al &&
237062306a36Sopenharmony_ci		  symbol__match_regex(al.sym, &ignore_callees_regex)) {
237162306a36Sopenharmony_ci			/* Treat this symbol as the root,
237262306a36Sopenharmony_ci			   forgetting its callees. */
237362306a36Sopenharmony_ci			addr_location__copy(root_al, &al);
237462306a36Sopenharmony_ci			callchain_cursor_reset(cursor);
237562306a36Sopenharmony_ci		}
237662306a36Sopenharmony_ci	}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	if (symbol_conf.hide_unresolved && al.sym == NULL)
237962306a36Sopenharmony_ci		goto out;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	if (iter) {
238262306a36Sopenharmony_ci		nr_loop_iter = iter->nr_loop_iter;
238362306a36Sopenharmony_ci		iter_cycles = iter->cycles;
238462306a36Sopenharmony_ci	}
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	ms.maps = maps__get(al.maps);
238762306a36Sopenharmony_ci	ms.map = map__get(al.map);
238862306a36Sopenharmony_ci	ms.sym = al.sym;
238962306a36Sopenharmony_ci	srcline = callchain_srcline(&ms, al.addr);
239062306a36Sopenharmony_ci	err = callchain_cursor_append(cursor, ip, &ms,
239162306a36Sopenharmony_ci				      branch, flags, nr_loop_iter,
239262306a36Sopenharmony_ci				      iter_cycles, branch_from, srcline);
239362306a36Sopenharmony_ciout:
239462306a36Sopenharmony_ci	addr_location__exit(&al);
239562306a36Sopenharmony_ci	maps__put(ms.maps);
239662306a36Sopenharmony_ci	map__put(ms.map);
239762306a36Sopenharmony_ci	return err;
239862306a36Sopenharmony_ci}
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_cistruct branch_info *sample__resolve_bstack(struct perf_sample *sample,
240162306a36Sopenharmony_ci					   struct addr_location *al)
240262306a36Sopenharmony_ci{
240362306a36Sopenharmony_ci	unsigned int i;
240462306a36Sopenharmony_ci	const struct branch_stack *bs = sample->branch_stack;
240562306a36Sopenharmony_ci	struct branch_entry *entries = perf_sample__branch_entries(sample);
240662306a36Sopenharmony_ci	struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info));
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	if (!bi)
240962306a36Sopenharmony_ci		return NULL;
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci	for (i = 0; i < bs->nr; i++) {
241262306a36Sopenharmony_ci		ip__resolve_ams(al->thread, &bi[i].to, entries[i].to);
241362306a36Sopenharmony_ci		ip__resolve_ams(al->thread, &bi[i].from, entries[i].from);
241462306a36Sopenharmony_ci		bi[i].flags = entries[i].flags;
241562306a36Sopenharmony_ci	}
241662306a36Sopenharmony_ci	return bi;
241762306a36Sopenharmony_ci}
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_cistatic void save_iterations(struct iterations *iter,
242062306a36Sopenharmony_ci			    struct branch_entry *be, int nr)
242162306a36Sopenharmony_ci{
242262306a36Sopenharmony_ci	int i;
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	iter->nr_loop_iter++;
242562306a36Sopenharmony_ci	iter->cycles = 0;
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	for (i = 0; i < nr; i++)
242862306a36Sopenharmony_ci		iter->cycles += be[i].flags.cycles;
242962306a36Sopenharmony_ci}
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci#define CHASHSZ 127
243262306a36Sopenharmony_ci#define CHASHBITS 7
243362306a36Sopenharmony_ci#define NO_ENTRY 0xff
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci#define PERF_MAX_BRANCH_DEPTH 127
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci/* Remove loops. */
243862306a36Sopenharmony_cistatic int remove_loops(struct branch_entry *l, int nr,
243962306a36Sopenharmony_ci			struct iterations *iter)
244062306a36Sopenharmony_ci{
244162306a36Sopenharmony_ci	int i, j, off;
244262306a36Sopenharmony_ci	unsigned char chash[CHASHSZ];
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	memset(chash, NO_ENTRY, sizeof(chash));
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	BUG_ON(PERF_MAX_BRANCH_DEPTH > 255);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
244962306a36Sopenharmony_ci		int h = hash_64(l[i].from, CHASHBITS) % CHASHSZ;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci		/* no collision handling for now */
245262306a36Sopenharmony_ci		if (chash[h] == NO_ENTRY) {
245362306a36Sopenharmony_ci			chash[h] = i;
245462306a36Sopenharmony_ci		} else if (l[chash[h]].from == l[i].from) {
245562306a36Sopenharmony_ci			bool is_loop = true;
245662306a36Sopenharmony_ci			/* check if it is a real loop */
245762306a36Sopenharmony_ci			off = 0;
245862306a36Sopenharmony_ci			for (j = chash[h]; j < i && i + off < nr; j++, off++)
245962306a36Sopenharmony_ci				if (l[j].from != l[i + off].from) {
246062306a36Sopenharmony_ci					is_loop = false;
246162306a36Sopenharmony_ci					break;
246262306a36Sopenharmony_ci				}
246362306a36Sopenharmony_ci			if (is_loop) {
246462306a36Sopenharmony_ci				j = nr - (i + off);
246562306a36Sopenharmony_ci				if (j > 0) {
246662306a36Sopenharmony_ci					save_iterations(iter + i + off,
246762306a36Sopenharmony_ci						l + i, off);
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci					memmove(iter + i, iter + i + off,
247062306a36Sopenharmony_ci						j * sizeof(*iter));
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci					memmove(l + i, l + i + off,
247362306a36Sopenharmony_ci						j * sizeof(*l));
247462306a36Sopenharmony_ci				}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci				nr -= off;
247762306a36Sopenharmony_ci			}
247862306a36Sopenharmony_ci		}
247962306a36Sopenharmony_ci	}
248062306a36Sopenharmony_ci	return nr;
248162306a36Sopenharmony_ci}
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_cistatic int lbr_callchain_add_kernel_ip(struct thread *thread,
248462306a36Sopenharmony_ci				       struct callchain_cursor *cursor,
248562306a36Sopenharmony_ci				       struct perf_sample *sample,
248662306a36Sopenharmony_ci				       struct symbol **parent,
248762306a36Sopenharmony_ci				       struct addr_location *root_al,
248862306a36Sopenharmony_ci				       u64 branch_from,
248962306a36Sopenharmony_ci				       bool callee, int end)
249062306a36Sopenharmony_ci{
249162306a36Sopenharmony_ci	struct ip_callchain *chain = sample->callchain;
249262306a36Sopenharmony_ci	u8 cpumode = PERF_RECORD_MISC_USER;
249362306a36Sopenharmony_ci	int err, i;
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	if (callee) {
249662306a36Sopenharmony_ci		for (i = 0; i < end + 1; i++) {
249762306a36Sopenharmony_ci			err = add_callchain_ip(thread, cursor, parent,
249862306a36Sopenharmony_ci					       root_al, &cpumode, chain->ips[i],
249962306a36Sopenharmony_ci					       false, NULL, NULL, branch_from);
250062306a36Sopenharmony_ci			if (err)
250162306a36Sopenharmony_ci				return err;
250262306a36Sopenharmony_ci		}
250362306a36Sopenharmony_ci		return 0;
250462306a36Sopenharmony_ci	}
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	for (i = end; i >= 0; i--) {
250762306a36Sopenharmony_ci		err = add_callchain_ip(thread, cursor, parent,
250862306a36Sopenharmony_ci				       root_al, &cpumode, chain->ips[i],
250962306a36Sopenharmony_ci				       false, NULL, NULL, branch_from);
251062306a36Sopenharmony_ci		if (err)
251162306a36Sopenharmony_ci			return err;
251262306a36Sopenharmony_ci	}
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	return 0;
251562306a36Sopenharmony_ci}
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_cistatic void save_lbr_cursor_node(struct thread *thread,
251862306a36Sopenharmony_ci				 struct callchain_cursor *cursor,
251962306a36Sopenharmony_ci				 int idx)
252062306a36Sopenharmony_ci{
252162306a36Sopenharmony_ci	struct lbr_stitch *lbr_stitch = thread__lbr_stitch(thread);
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	if (!lbr_stitch)
252462306a36Sopenharmony_ci		return;
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	if (cursor->pos == cursor->nr) {
252762306a36Sopenharmony_ci		lbr_stitch->prev_lbr_cursor[idx].valid = false;
252862306a36Sopenharmony_ci		return;
252962306a36Sopenharmony_ci	}
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	if (!cursor->curr)
253262306a36Sopenharmony_ci		cursor->curr = cursor->first;
253362306a36Sopenharmony_ci	else
253462306a36Sopenharmony_ci		cursor->curr = cursor->curr->next;
253562306a36Sopenharmony_ci	memcpy(&lbr_stitch->prev_lbr_cursor[idx], cursor->curr,
253662306a36Sopenharmony_ci	       sizeof(struct callchain_cursor_node));
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci	lbr_stitch->prev_lbr_cursor[idx].valid = true;
253962306a36Sopenharmony_ci	cursor->pos++;
254062306a36Sopenharmony_ci}
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_cistatic int lbr_callchain_add_lbr_ip(struct thread *thread,
254362306a36Sopenharmony_ci				    struct callchain_cursor *cursor,
254462306a36Sopenharmony_ci				    struct perf_sample *sample,
254562306a36Sopenharmony_ci				    struct symbol **parent,
254662306a36Sopenharmony_ci				    struct addr_location *root_al,
254762306a36Sopenharmony_ci				    u64 *branch_from,
254862306a36Sopenharmony_ci				    bool callee)
254962306a36Sopenharmony_ci{
255062306a36Sopenharmony_ci	struct branch_stack *lbr_stack = sample->branch_stack;
255162306a36Sopenharmony_ci	struct branch_entry *entries = perf_sample__branch_entries(sample);
255262306a36Sopenharmony_ci	u8 cpumode = PERF_RECORD_MISC_USER;
255362306a36Sopenharmony_ci	int lbr_nr = lbr_stack->nr;
255462306a36Sopenharmony_ci	struct branch_flags *flags;
255562306a36Sopenharmony_ci	int err, i;
255662306a36Sopenharmony_ci	u64 ip;
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	/*
255962306a36Sopenharmony_ci	 * The curr and pos are not used in writing session. They are cleared
256062306a36Sopenharmony_ci	 * in callchain_cursor_commit() when the writing session is closed.
256162306a36Sopenharmony_ci	 * Using curr and pos to track the current cursor node.
256262306a36Sopenharmony_ci	 */
256362306a36Sopenharmony_ci	if (thread__lbr_stitch(thread)) {
256462306a36Sopenharmony_ci		cursor->curr = NULL;
256562306a36Sopenharmony_ci		cursor->pos = cursor->nr;
256662306a36Sopenharmony_ci		if (cursor->nr) {
256762306a36Sopenharmony_ci			cursor->curr = cursor->first;
256862306a36Sopenharmony_ci			for (i = 0; i < (int)(cursor->nr - 1); i++)
256962306a36Sopenharmony_ci				cursor->curr = cursor->curr->next;
257062306a36Sopenharmony_ci		}
257162306a36Sopenharmony_ci	}
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	if (callee) {
257462306a36Sopenharmony_ci		/* Add LBR ip from first entries.to */
257562306a36Sopenharmony_ci		ip = entries[0].to;
257662306a36Sopenharmony_ci		flags = &entries[0].flags;
257762306a36Sopenharmony_ci		*branch_from = entries[0].from;
257862306a36Sopenharmony_ci		err = add_callchain_ip(thread, cursor, parent,
257962306a36Sopenharmony_ci				       root_al, &cpumode, ip,
258062306a36Sopenharmony_ci				       true, flags, NULL,
258162306a36Sopenharmony_ci				       *branch_from);
258262306a36Sopenharmony_ci		if (err)
258362306a36Sopenharmony_ci			return err;
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci		/*
258662306a36Sopenharmony_ci		 * The number of cursor node increases.
258762306a36Sopenharmony_ci		 * Move the current cursor node.
258862306a36Sopenharmony_ci		 * But does not need to save current cursor node for entry 0.
258962306a36Sopenharmony_ci		 * It's impossible to stitch the whole LBRs of previous sample.
259062306a36Sopenharmony_ci		 */
259162306a36Sopenharmony_ci		if (thread__lbr_stitch(thread) && (cursor->pos != cursor->nr)) {
259262306a36Sopenharmony_ci			if (!cursor->curr)
259362306a36Sopenharmony_ci				cursor->curr = cursor->first;
259462306a36Sopenharmony_ci			else
259562306a36Sopenharmony_ci				cursor->curr = cursor->curr->next;
259662306a36Sopenharmony_ci			cursor->pos++;
259762306a36Sopenharmony_ci		}
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci		/* Add LBR ip from entries.from one by one. */
260062306a36Sopenharmony_ci		for (i = 0; i < lbr_nr; i++) {
260162306a36Sopenharmony_ci			ip = entries[i].from;
260262306a36Sopenharmony_ci			flags = &entries[i].flags;
260362306a36Sopenharmony_ci			err = add_callchain_ip(thread, cursor, parent,
260462306a36Sopenharmony_ci					       root_al, &cpumode, ip,
260562306a36Sopenharmony_ci					       true, flags, NULL,
260662306a36Sopenharmony_ci					       *branch_from);
260762306a36Sopenharmony_ci			if (err)
260862306a36Sopenharmony_ci				return err;
260962306a36Sopenharmony_ci			save_lbr_cursor_node(thread, cursor, i);
261062306a36Sopenharmony_ci		}
261162306a36Sopenharmony_ci		return 0;
261262306a36Sopenharmony_ci	}
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	/* Add LBR ip from entries.from one by one. */
261562306a36Sopenharmony_ci	for (i = lbr_nr - 1; i >= 0; i--) {
261662306a36Sopenharmony_ci		ip = entries[i].from;
261762306a36Sopenharmony_ci		flags = &entries[i].flags;
261862306a36Sopenharmony_ci		err = add_callchain_ip(thread, cursor, parent,
261962306a36Sopenharmony_ci				       root_al, &cpumode, ip,
262062306a36Sopenharmony_ci				       true, flags, NULL,
262162306a36Sopenharmony_ci				       *branch_from);
262262306a36Sopenharmony_ci		if (err)
262362306a36Sopenharmony_ci			return err;
262462306a36Sopenharmony_ci		save_lbr_cursor_node(thread, cursor, i);
262562306a36Sopenharmony_ci	}
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	if (lbr_nr > 0) {
262862306a36Sopenharmony_ci		/* Add LBR ip from first entries.to */
262962306a36Sopenharmony_ci		ip = entries[0].to;
263062306a36Sopenharmony_ci		flags = &entries[0].flags;
263162306a36Sopenharmony_ci		*branch_from = entries[0].from;
263262306a36Sopenharmony_ci		err = add_callchain_ip(thread, cursor, parent,
263362306a36Sopenharmony_ci				root_al, &cpumode, ip,
263462306a36Sopenharmony_ci				true, flags, NULL,
263562306a36Sopenharmony_ci				*branch_from);
263662306a36Sopenharmony_ci		if (err)
263762306a36Sopenharmony_ci			return err;
263862306a36Sopenharmony_ci	}
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	return 0;
264162306a36Sopenharmony_ci}
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_cistatic int lbr_callchain_add_stitched_lbr_ip(struct thread *thread,
264462306a36Sopenharmony_ci					     struct callchain_cursor *cursor)
264562306a36Sopenharmony_ci{
264662306a36Sopenharmony_ci	struct lbr_stitch *lbr_stitch = thread__lbr_stitch(thread);
264762306a36Sopenharmony_ci	struct callchain_cursor_node *cnode;
264862306a36Sopenharmony_ci	struct stitch_list *stitch_node;
264962306a36Sopenharmony_ci	int err;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	list_for_each_entry(stitch_node, &lbr_stitch->lists, node) {
265262306a36Sopenharmony_ci		cnode = &stitch_node->cursor;
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci		err = callchain_cursor_append(cursor, cnode->ip,
265562306a36Sopenharmony_ci					      &cnode->ms,
265662306a36Sopenharmony_ci					      cnode->branch,
265762306a36Sopenharmony_ci					      &cnode->branch_flags,
265862306a36Sopenharmony_ci					      cnode->nr_loop_iter,
265962306a36Sopenharmony_ci					      cnode->iter_cycles,
266062306a36Sopenharmony_ci					      cnode->branch_from,
266162306a36Sopenharmony_ci					      cnode->srcline);
266262306a36Sopenharmony_ci		if (err)
266362306a36Sopenharmony_ci			return err;
266462306a36Sopenharmony_ci	}
266562306a36Sopenharmony_ci	return 0;
266662306a36Sopenharmony_ci}
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_cistatic struct stitch_list *get_stitch_node(struct thread *thread)
266962306a36Sopenharmony_ci{
267062306a36Sopenharmony_ci	struct lbr_stitch *lbr_stitch = thread__lbr_stitch(thread);
267162306a36Sopenharmony_ci	struct stitch_list *stitch_node;
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci	if (!list_empty(&lbr_stitch->free_lists)) {
267462306a36Sopenharmony_ci		stitch_node = list_first_entry(&lbr_stitch->free_lists,
267562306a36Sopenharmony_ci					       struct stitch_list, node);
267662306a36Sopenharmony_ci		list_del(&stitch_node->node);
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_ci		return stitch_node;
267962306a36Sopenharmony_ci	}
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	return malloc(sizeof(struct stitch_list));
268262306a36Sopenharmony_ci}
268362306a36Sopenharmony_ci
268462306a36Sopenharmony_cistatic bool has_stitched_lbr(struct thread *thread,
268562306a36Sopenharmony_ci			     struct perf_sample *cur,
268662306a36Sopenharmony_ci			     struct perf_sample *prev,
268762306a36Sopenharmony_ci			     unsigned int max_lbr,
268862306a36Sopenharmony_ci			     bool callee)
268962306a36Sopenharmony_ci{
269062306a36Sopenharmony_ci	struct branch_stack *cur_stack = cur->branch_stack;
269162306a36Sopenharmony_ci	struct branch_entry *cur_entries = perf_sample__branch_entries(cur);
269262306a36Sopenharmony_ci	struct branch_stack *prev_stack = prev->branch_stack;
269362306a36Sopenharmony_ci	struct branch_entry *prev_entries = perf_sample__branch_entries(prev);
269462306a36Sopenharmony_ci	struct lbr_stitch *lbr_stitch = thread__lbr_stitch(thread);
269562306a36Sopenharmony_ci	int i, j, nr_identical_branches = 0;
269662306a36Sopenharmony_ci	struct stitch_list *stitch_node;
269762306a36Sopenharmony_ci	u64 cur_base, distance;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	if (!cur_stack || !prev_stack)
270062306a36Sopenharmony_ci		return false;
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci	/* Find the physical index of the base-of-stack for current sample. */
270362306a36Sopenharmony_ci	cur_base = max_lbr - cur_stack->nr + cur_stack->hw_idx + 1;
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci	distance = (prev_stack->hw_idx > cur_base) ? (prev_stack->hw_idx - cur_base) :
270662306a36Sopenharmony_ci						     (max_lbr + prev_stack->hw_idx - cur_base);
270762306a36Sopenharmony_ci	/* Previous sample has shorter stack. Nothing can be stitched. */
270862306a36Sopenharmony_ci	if (distance + 1 > prev_stack->nr)
270962306a36Sopenharmony_ci		return false;
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci	/*
271262306a36Sopenharmony_ci	 * Check if there are identical LBRs between two samples.
271362306a36Sopenharmony_ci	 * Identical LBRs must have same from, to and flags values. Also,
271462306a36Sopenharmony_ci	 * they have to be saved in the same LBR registers (same physical
271562306a36Sopenharmony_ci	 * index).
271662306a36Sopenharmony_ci	 *
271762306a36Sopenharmony_ci	 * Starts from the base-of-stack of current sample.
271862306a36Sopenharmony_ci	 */
271962306a36Sopenharmony_ci	for (i = distance, j = cur_stack->nr - 1; (i >= 0) && (j >= 0); i--, j--) {
272062306a36Sopenharmony_ci		if ((prev_entries[i].from != cur_entries[j].from) ||
272162306a36Sopenharmony_ci		    (prev_entries[i].to != cur_entries[j].to) ||
272262306a36Sopenharmony_ci		    (prev_entries[i].flags.value != cur_entries[j].flags.value))
272362306a36Sopenharmony_ci			break;
272462306a36Sopenharmony_ci		nr_identical_branches++;
272562306a36Sopenharmony_ci	}
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	if (!nr_identical_branches)
272862306a36Sopenharmony_ci		return false;
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci	/*
273162306a36Sopenharmony_ci	 * Save the LBRs between the base-of-stack of previous sample
273262306a36Sopenharmony_ci	 * and the base-of-stack of current sample into lbr_stitch->lists.
273362306a36Sopenharmony_ci	 * These LBRs will be stitched later.
273462306a36Sopenharmony_ci	 */
273562306a36Sopenharmony_ci	for (i = prev_stack->nr - 1; i > (int)distance; i--) {
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci		if (!lbr_stitch->prev_lbr_cursor[i].valid)
273862306a36Sopenharmony_ci			continue;
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci		stitch_node = get_stitch_node(thread);
274162306a36Sopenharmony_ci		if (!stitch_node)
274262306a36Sopenharmony_ci			return false;
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci		memcpy(&stitch_node->cursor, &lbr_stitch->prev_lbr_cursor[i],
274562306a36Sopenharmony_ci		       sizeof(struct callchain_cursor_node));
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci		if (callee)
274862306a36Sopenharmony_ci			list_add(&stitch_node->node, &lbr_stitch->lists);
274962306a36Sopenharmony_ci		else
275062306a36Sopenharmony_ci			list_add_tail(&stitch_node->node, &lbr_stitch->lists);
275162306a36Sopenharmony_ci	}
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci	return true;
275462306a36Sopenharmony_ci}
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_cistatic bool alloc_lbr_stitch(struct thread *thread, unsigned int max_lbr)
275762306a36Sopenharmony_ci{
275862306a36Sopenharmony_ci	if (thread__lbr_stitch(thread))
275962306a36Sopenharmony_ci		return true;
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	thread__set_lbr_stitch(thread, zalloc(sizeof(struct lbr_stitch)));
276262306a36Sopenharmony_ci	if (!thread__lbr_stitch(thread))
276362306a36Sopenharmony_ci		goto err;
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	thread__lbr_stitch(thread)->prev_lbr_cursor =
276662306a36Sopenharmony_ci		calloc(max_lbr + 1, sizeof(struct callchain_cursor_node));
276762306a36Sopenharmony_ci	if (!thread__lbr_stitch(thread)->prev_lbr_cursor)
276862306a36Sopenharmony_ci		goto free_lbr_stitch;
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	INIT_LIST_HEAD(&thread__lbr_stitch(thread)->lists);
277162306a36Sopenharmony_ci	INIT_LIST_HEAD(&thread__lbr_stitch(thread)->free_lists);
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci	return true;
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_cifree_lbr_stitch:
277662306a36Sopenharmony_ci	free(thread__lbr_stitch(thread));
277762306a36Sopenharmony_ci	thread__set_lbr_stitch(thread, NULL);
277862306a36Sopenharmony_cierr:
277962306a36Sopenharmony_ci	pr_warning("Failed to allocate space for stitched LBRs. Disable LBR stitch\n");
278062306a36Sopenharmony_ci	thread__set_lbr_stitch_enable(thread, false);
278162306a36Sopenharmony_ci	return false;
278262306a36Sopenharmony_ci}
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci/*
278562306a36Sopenharmony_ci * Resolve LBR callstack chain sample
278662306a36Sopenharmony_ci * Return:
278762306a36Sopenharmony_ci * 1 on success get LBR callchain information
278862306a36Sopenharmony_ci * 0 no available LBR callchain information, should try fp
278962306a36Sopenharmony_ci * negative error code on other errors.
279062306a36Sopenharmony_ci */
279162306a36Sopenharmony_cistatic int resolve_lbr_callchain_sample(struct thread *thread,
279262306a36Sopenharmony_ci					struct callchain_cursor *cursor,
279362306a36Sopenharmony_ci					struct perf_sample *sample,
279462306a36Sopenharmony_ci					struct symbol **parent,
279562306a36Sopenharmony_ci					struct addr_location *root_al,
279662306a36Sopenharmony_ci					int max_stack,
279762306a36Sopenharmony_ci					unsigned int max_lbr)
279862306a36Sopenharmony_ci{
279962306a36Sopenharmony_ci	bool callee = (callchain_param.order == ORDER_CALLEE);
280062306a36Sopenharmony_ci	struct ip_callchain *chain = sample->callchain;
280162306a36Sopenharmony_ci	int chain_nr = min(max_stack, (int)chain->nr), i;
280262306a36Sopenharmony_ci	struct lbr_stitch *lbr_stitch;
280362306a36Sopenharmony_ci	bool stitched_lbr = false;
280462306a36Sopenharmony_ci	u64 branch_from = 0;
280562306a36Sopenharmony_ci	int err;
280662306a36Sopenharmony_ci
280762306a36Sopenharmony_ci	for (i = 0; i < chain_nr; i++) {
280862306a36Sopenharmony_ci		if (chain->ips[i] == PERF_CONTEXT_USER)
280962306a36Sopenharmony_ci			break;
281062306a36Sopenharmony_ci	}
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci	/* LBR only affects the user callchain */
281362306a36Sopenharmony_ci	if (i == chain_nr)
281462306a36Sopenharmony_ci		return 0;
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_ci	if (thread__lbr_stitch_enable(thread) && !sample->no_hw_idx &&
281762306a36Sopenharmony_ci	    (max_lbr > 0) && alloc_lbr_stitch(thread, max_lbr)) {
281862306a36Sopenharmony_ci		lbr_stitch = thread__lbr_stitch(thread);
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci		stitched_lbr = has_stitched_lbr(thread, sample,
282162306a36Sopenharmony_ci						&lbr_stitch->prev_sample,
282262306a36Sopenharmony_ci						max_lbr, callee);
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci		if (!stitched_lbr && !list_empty(&lbr_stitch->lists)) {
282562306a36Sopenharmony_ci			list_replace_init(&lbr_stitch->lists,
282662306a36Sopenharmony_ci					  &lbr_stitch->free_lists);
282762306a36Sopenharmony_ci		}
282862306a36Sopenharmony_ci		memcpy(&lbr_stitch->prev_sample, sample, sizeof(*sample));
282962306a36Sopenharmony_ci	}
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci	if (callee) {
283262306a36Sopenharmony_ci		/* Add kernel ip */
283362306a36Sopenharmony_ci		err = lbr_callchain_add_kernel_ip(thread, cursor, sample,
283462306a36Sopenharmony_ci						  parent, root_al, branch_from,
283562306a36Sopenharmony_ci						  true, i);
283662306a36Sopenharmony_ci		if (err)
283762306a36Sopenharmony_ci			goto error;
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci		err = lbr_callchain_add_lbr_ip(thread, cursor, sample, parent,
284062306a36Sopenharmony_ci					       root_al, &branch_from, true);
284162306a36Sopenharmony_ci		if (err)
284262306a36Sopenharmony_ci			goto error;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci		if (stitched_lbr) {
284562306a36Sopenharmony_ci			err = lbr_callchain_add_stitched_lbr_ip(thread, cursor);
284662306a36Sopenharmony_ci			if (err)
284762306a36Sopenharmony_ci				goto error;
284862306a36Sopenharmony_ci		}
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	} else {
285162306a36Sopenharmony_ci		if (stitched_lbr) {
285262306a36Sopenharmony_ci			err = lbr_callchain_add_stitched_lbr_ip(thread, cursor);
285362306a36Sopenharmony_ci			if (err)
285462306a36Sopenharmony_ci				goto error;
285562306a36Sopenharmony_ci		}
285662306a36Sopenharmony_ci		err = lbr_callchain_add_lbr_ip(thread, cursor, sample, parent,
285762306a36Sopenharmony_ci					       root_al, &branch_from, false);
285862306a36Sopenharmony_ci		if (err)
285962306a36Sopenharmony_ci			goto error;
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci		/* Add kernel ip */
286262306a36Sopenharmony_ci		err = lbr_callchain_add_kernel_ip(thread, cursor, sample,
286362306a36Sopenharmony_ci						  parent, root_al, branch_from,
286462306a36Sopenharmony_ci						  false, i);
286562306a36Sopenharmony_ci		if (err)
286662306a36Sopenharmony_ci			goto error;
286762306a36Sopenharmony_ci	}
286862306a36Sopenharmony_ci	return 1;
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_cierror:
287162306a36Sopenharmony_ci	return (err < 0) ? err : 0;
287262306a36Sopenharmony_ci}
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_cistatic int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread,
287562306a36Sopenharmony_ci			     struct callchain_cursor *cursor,
287662306a36Sopenharmony_ci			     struct symbol **parent,
287762306a36Sopenharmony_ci			     struct addr_location *root_al,
287862306a36Sopenharmony_ci			     u8 *cpumode, int ent)
287962306a36Sopenharmony_ci{
288062306a36Sopenharmony_ci	int err = 0;
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci	while (--ent >= 0) {
288362306a36Sopenharmony_ci		u64 ip = chain->ips[ent];
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci		if (ip >= PERF_CONTEXT_MAX) {
288662306a36Sopenharmony_ci			err = add_callchain_ip(thread, cursor, parent,
288762306a36Sopenharmony_ci					       root_al, cpumode, ip,
288862306a36Sopenharmony_ci					       false, NULL, NULL, 0);
288962306a36Sopenharmony_ci			break;
289062306a36Sopenharmony_ci		}
289162306a36Sopenharmony_ci	}
289262306a36Sopenharmony_ci	return err;
289362306a36Sopenharmony_ci}
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_cistatic u64 get_leaf_frame_caller(struct perf_sample *sample,
289662306a36Sopenharmony_ci		struct thread *thread, int usr_idx)
289762306a36Sopenharmony_ci{
289862306a36Sopenharmony_ci	if (machine__normalized_is(maps__machine(thread__maps(thread)), "arm64"))
289962306a36Sopenharmony_ci		return get_leaf_frame_caller_aarch64(sample, thread, usr_idx);
290062306a36Sopenharmony_ci	else
290162306a36Sopenharmony_ci		return 0;
290262306a36Sopenharmony_ci}
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_cistatic int thread__resolve_callchain_sample(struct thread *thread,
290562306a36Sopenharmony_ci					    struct callchain_cursor *cursor,
290662306a36Sopenharmony_ci					    struct evsel *evsel,
290762306a36Sopenharmony_ci					    struct perf_sample *sample,
290862306a36Sopenharmony_ci					    struct symbol **parent,
290962306a36Sopenharmony_ci					    struct addr_location *root_al,
291062306a36Sopenharmony_ci					    int max_stack)
291162306a36Sopenharmony_ci{
291262306a36Sopenharmony_ci	struct branch_stack *branch = sample->branch_stack;
291362306a36Sopenharmony_ci	struct branch_entry *entries = perf_sample__branch_entries(sample);
291462306a36Sopenharmony_ci	struct ip_callchain *chain = sample->callchain;
291562306a36Sopenharmony_ci	int chain_nr = 0;
291662306a36Sopenharmony_ci	u8 cpumode = PERF_RECORD_MISC_USER;
291762306a36Sopenharmony_ci	int i, j, err, nr_entries, usr_idx;
291862306a36Sopenharmony_ci	int skip_idx = -1;
291962306a36Sopenharmony_ci	int first_call = 0;
292062306a36Sopenharmony_ci	u64 leaf_frame_caller;
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci	if (chain)
292362306a36Sopenharmony_ci		chain_nr = chain->nr;
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_ci	if (evsel__has_branch_callstack(evsel)) {
292662306a36Sopenharmony_ci		struct perf_env *env = evsel__env(evsel);
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci		err = resolve_lbr_callchain_sample(thread, cursor, sample, parent,
292962306a36Sopenharmony_ci						   root_al, max_stack,
293062306a36Sopenharmony_ci						   !env ? 0 : env->max_branches);
293162306a36Sopenharmony_ci		if (err)
293262306a36Sopenharmony_ci			return (err < 0) ? err : 0;
293362306a36Sopenharmony_ci	}
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci	/*
293662306a36Sopenharmony_ci	 * Based on DWARF debug information, some architectures skip
293762306a36Sopenharmony_ci	 * a callchain entry saved by the kernel.
293862306a36Sopenharmony_ci	 */
293962306a36Sopenharmony_ci	skip_idx = arch_skip_callchain_idx(thread, chain);
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci	/*
294262306a36Sopenharmony_ci	 * Add branches to call stack for easier browsing. This gives
294362306a36Sopenharmony_ci	 * more context for a sample than just the callers.
294462306a36Sopenharmony_ci	 *
294562306a36Sopenharmony_ci	 * This uses individual histograms of paths compared to the
294662306a36Sopenharmony_ci	 * aggregated histograms the normal LBR mode uses.
294762306a36Sopenharmony_ci	 *
294862306a36Sopenharmony_ci	 * Limitations for now:
294962306a36Sopenharmony_ci	 * - No extra filters
295062306a36Sopenharmony_ci	 * - No annotations (should annotate somehow)
295162306a36Sopenharmony_ci	 */
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	if (branch && callchain_param.branch_callstack) {
295462306a36Sopenharmony_ci		int nr = min(max_stack, (int)branch->nr);
295562306a36Sopenharmony_ci		struct branch_entry be[nr];
295662306a36Sopenharmony_ci		struct iterations iter[nr];
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_ci		if (branch->nr > PERF_MAX_BRANCH_DEPTH) {
295962306a36Sopenharmony_ci			pr_warning("corrupted branch chain. skipping...\n");
296062306a36Sopenharmony_ci			goto check_calls;
296162306a36Sopenharmony_ci		}
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci		for (i = 0; i < nr; i++) {
296462306a36Sopenharmony_ci			if (callchain_param.order == ORDER_CALLEE) {
296562306a36Sopenharmony_ci				be[i] = entries[i];
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci				if (chain == NULL)
296862306a36Sopenharmony_ci					continue;
296962306a36Sopenharmony_ci
297062306a36Sopenharmony_ci				/*
297162306a36Sopenharmony_ci				 * Check for overlap into the callchain.
297262306a36Sopenharmony_ci				 * The return address is one off compared to
297362306a36Sopenharmony_ci				 * the branch entry. To adjust for this
297462306a36Sopenharmony_ci				 * assume the calling instruction is not longer
297562306a36Sopenharmony_ci				 * than 8 bytes.
297662306a36Sopenharmony_ci				 */
297762306a36Sopenharmony_ci				if (i == skip_idx ||
297862306a36Sopenharmony_ci				    chain->ips[first_call] >= PERF_CONTEXT_MAX)
297962306a36Sopenharmony_ci					first_call++;
298062306a36Sopenharmony_ci				else if (be[i].from < chain->ips[first_call] &&
298162306a36Sopenharmony_ci				    be[i].from >= chain->ips[first_call] - 8)
298262306a36Sopenharmony_ci					first_call++;
298362306a36Sopenharmony_ci			} else
298462306a36Sopenharmony_ci				be[i] = entries[branch->nr - i - 1];
298562306a36Sopenharmony_ci		}
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci		memset(iter, 0, sizeof(struct iterations) * nr);
298862306a36Sopenharmony_ci		nr = remove_loops(be, nr, iter);
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci		for (i = 0; i < nr; i++) {
299162306a36Sopenharmony_ci			err = add_callchain_ip(thread, cursor, parent,
299262306a36Sopenharmony_ci					       root_al,
299362306a36Sopenharmony_ci					       NULL, be[i].to,
299462306a36Sopenharmony_ci					       true, &be[i].flags,
299562306a36Sopenharmony_ci					       NULL, be[i].from);
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci			if (!err)
299862306a36Sopenharmony_ci				err = add_callchain_ip(thread, cursor, parent, root_al,
299962306a36Sopenharmony_ci						       NULL, be[i].from,
300062306a36Sopenharmony_ci						       true, &be[i].flags,
300162306a36Sopenharmony_ci						       &iter[i], 0);
300262306a36Sopenharmony_ci			if (err == -EINVAL)
300362306a36Sopenharmony_ci				break;
300462306a36Sopenharmony_ci			if (err)
300562306a36Sopenharmony_ci				return err;
300662306a36Sopenharmony_ci		}
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci		if (chain_nr == 0)
300962306a36Sopenharmony_ci			return 0;
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci		chain_nr -= nr;
301262306a36Sopenharmony_ci	}
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_cicheck_calls:
301562306a36Sopenharmony_ci	if (chain && callchain_param.order != ORDER_CALLEE) {
301662306a36Sopenharmony_ci		err = find_prev_cpumode(chain, thread, cursor, parent, root_al,
301762306a36Sopenharmony_ci					&cpumode, chain->nr - first_call);
301862306a36Sopenharmony_ci		if (err)
301962306a36Sopenharmony_ci			return (err < 0) ? err : 0;
302062306a36Sopenharmony_ci	}
302162306a36Sopenharmony_ci	for (i = first_call, nr_entries = 0;
302262306a36Sopenharmony_ci	     i < chain_nr && nr_entries < max_stack; i++) {
302362306a36Sopenharmony_ci		u64 ip;
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci		if (callchain_param.order == ORDER_CALLEE)
302662306a36Sopenharmony_ci			j = i;
302762306a36Sopenharmony_ci		else
302862306a36Sopenharmony_ci			j = chain->nr - i - 1;
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_ci#ifdef HAVE_SKIP_CALLCHAIN_IDX
303162306a36Sopenharmony_ci		if (j == skip_idx)
303262306a36Sopenharmony_ci			continue;
303362306a36Sopenharmony_ci#endif
303462306a36Sopenharmony_ci		ip = chain->ips[j];
303562306a36Sopenharmony_ci		if (ip < PERF_CONTEXT_MAX)
303662306a36Sopenharmony_ci                       ++nr_entries;
303762306a36Sopenharmony_ci		else if (callchain_param.order != ORDER_CALLEE) {
303862306a36Sopenharmony_ci			err = find_prev_cpumode(chain, thread, cursor, parent,
303962306a36Sopenharmony_ci						root_al, &cpumode, j);
304062306a36Sopenharmony_ci			if (err)
304162306a36Sopenharmony_ci				return (err < 0) ? err : 0;
304262306a36Sopenharmony_ci			continue;
304362306a36Sopenharmony_ci		}
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci		/*
304662306a36Sopenharmony_ci		 * PERF_CONTEXT_USER allows us to locate where the user stack ends.
304762306a36Sopenharmony_ci		 * Depending on callchain_param.order and the position of PERF_CONTEXT_USER,
304862306a36Sopenharmony_ci		 * the index will be different in order to add the missing frame
304962306a36Sopenharmony_ci		 * at the right place.
305062306a36Sopenharmony_ci		 */
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci		usr_idx = callchain_param.order == ORDER_CALLEE ? j-2 : j-1;
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci		if (usr_idx >= 0 && chain->ips[usr_idx] == PERF_CONTEXT_USER) {
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci			leaf_frame_caller = get_leaf_frame_caller(sample, thread, usr_idx);
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci			/*
305962306a36Sopenharmony_ci			 * check if leaf_frame_Caller != ip to not add the same
306062306a36Sopenharmony_ci			 * value twice.
306162306a36Sopenharmony_ci			 */
306262306a36Sopenharmony_ci
306362306a36Sopenharmony_ci			if (leaf_frame_caller && leaf_frame_caller != ip) {
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci				err = add_callchain_ip(thread, cursor, parent,
306662306a36Sopenharmony_ci					       root_al, &cpumode, leaf_frame_caller,
306762306a36Sopenharmony_ci					       false, NULL, NULL, 0);
306862306a36Sopenharmony_ci				if (err)
306962306a36Sopenharmony_ci					return (err < 0) ? err : 0;
307062306a36Sopenharmony_ci			}
307162306a36Sopenharmony_ci		}
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci		err = add_callchain_ip(thread, cursor, parent,
307462306a36Sopenharmony_ci				       root_al, &cpumode, ip,
307562306a36Sopenharmony_ci				       false, NULL, NULL, 0);
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_ci		if (err)
307862306a36Sopenharmony_ci			return (err < 0) ? err : 0;
307962306a36Sopenharmony_ci	}
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	return 0;
308262306a36Sopenharmony_ci}
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_cistatic int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms, u64 ip)
308562306a36Sopenharmony_ci{
308662306a36Sopenharmony_ci	struct symbol *sym = ms->sym;
308762306a36Sopenharmony_ci	struct map *map = ms->map;
308862306a36Sopenharmony_ci	struct inline_node *inline_node;
308962306a36Sopenharmony_ci	struct inline_list *ilist;
309062306a36Sopenharmony_ci	struct dso *dso;
309162306a36Sopenharmony_ci	u64 addr;
309262306a36Sopenharmony_ci	int ret = 1;
309362306a36Sopenharmony_ci	struct map_symbol ilist_ms;
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci	if (!symbol_conf.inline_name || !map || !sym)
309662306a36Sopenharmony_ci		return ret;
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	addr = map__dso_map_ip(map, ip);
309962306a36Sopenharmony_ci	addr = map__rip_2objdump(map, addr);
310062306a36Sopenharmony_ci	dso = map__dso(map);
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	inline_node = inlines__tree_find(&dso->inlined_nodes, addr);
310362306a36Sopenharmony_ci	if (!inline_node) {
310462306a36Sopenharmony_ci		inline_node = dso__parse_addr_inlines(dso, addr, sym);
310562306a36Sopenharmony_ci		if (!inline_node)
310662306a36Sopenharmony_ci			return ret;
310762306a36Sopenharmony_ci		inlines__tree_insert(&dso->inlined_nodes, inline_node);
310862306a36Sopenharmony_ci	}
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci	ilist_ms = (struct map_symbol) {
311162306a36Sopenharmony_ci		.maps = maps__get(ms->maps),
311262306a36Sopenharmony_ci		.map = map__get(map),
311362306a36Sopenharmony_ci	};
311462306a36Sopenharmony_ci	list_for_each_entry(ilist, &inline_node->val, list) {
311562306a36Sopenharmony_ci		ilist_ms.sym = ilist->symbol;
311662306a36Sopenharmony_ci		ret = callchain_cursor_append(cursor, ip, &ilist_ms, false,
311762306a36Sopenharmony_ci					      NULL, 0, 0, 0, ilist->srcline);
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci		if (ret != 0)
312062306a36Sopenharmony_ci			return ret;
312162306a36Sopenharmony_ci	}
312262306a36Sopenharmony_ci	map__put(ilist_ms.map);
312362306a36Sopenharmony_ci	maps__put(ilist_ms.maps);
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	return ret;
312662306a36Sopenharmony_ci}
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_cistatic int unwind_entry(struct unwind_entry *entry, void *arg)
312962306a36Sopenharmony_ci{
313062306a36Sopenharmony_ci	struct callchain_cursor *cursor = arg;
313162306a36Sopenharmony_ci	const char *srcline = NULL;
313262306a36Sopenharmony_ci	u64 addr = entry->ip;
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci	if (symbol_conf.hide_unresolved && entry->ms.sym == NULL)
313562306a36Sopenharmony_ci		return 0;
313662306a36Sopenharmony_ci
313762306a36Sopenharmony_ci	if (append_inlines(cursor, &entry->ms, entry->ip) == 0)
313862306a36Sopenharmony_ci		return 0;
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci	/*
314162306a36Sopenharmony_ci	 * Convert entry->ip from a virtual address to an offset in
314262306a36Sopenharmony_ci	 * its corresponding binary.
314362306a36Sopenharmony_ci	 */
314462306a36Sopenharmony_ci	if (entry->ms.map)
314562306a36Sopenharmony_ci		addr = map__dso_map_ip(entry->ms.map, entry->ip);
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_ci	srcline = callchain_srcline(&entry->ms, addr);
314862306a36Sopenharmony_ci	return callchain_cursor_append(cursor, entry->ip, &entry->ms,
314962306a36Sopenharmony_ci				       false, NULL, 0, 0, 0, srcline);
315062306a36Sopenharmony_ci}
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_cistatic int thread__resolve_callchain_unwind(struct thread *thread,
315362306a36Sopenharmony_ci					    struct callchain_cursor *cursor,
315462306a36Sopenharmony_ci					    struct evsel *evsel,
315562306a36Sopenharmony_ci					    struct perf_sample *sample,
315662306a36Sopenharmony_ci					    int max_stack)
315762306a36Sopenharmony_ci{
315862306a36Sopenharmony_ci	/* Can we do dwarf post unwind? */
315962306a36Sopenharmony_ci	if (!((evsel->core.attr.sample_type & PERF_SAMPLE_REGS_USER) &&
316062306a36Sopenharmony_ci	      (evsel->core.attr.sample_type & PERF_SAMPLE_STACK_USER)))
316162306a36Sopenharmony_ci		return 0;
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci	/* Bail out if nothing was captured. */
316462306a36Sopenharmony_ci	if ((!sample->user_regs.regs) ||
316562306a36Sopenharmony_ci	    (!sample->user_stack.size))
316662306a36Sopenharmony_ci		return 0;
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	return unwind__get_entries(unwind_entry, cursor,
316962306a36Sopenharmony_ci				   thread, sample, max_stack, false);
317062306a36Sopenharmony_ci}
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ciint thread__resolve_callchain(struct thread *thread,
317362306a36Sopenharmony_ci			      struct callchain_cursor *cursor,
317462306a36Sopenharmony_ci			      struct evsel *evsel,
317562306a36Sopenharmony_ci			      struct perf_sample *sample,
317662306a36Sopenharmony_ci			      struct symbol **parent,
317762306a36Sopenharmony_ci			      struct addr_location *root_al,
317862306a36Sopenharmony_ci			      int max_stack)
317962306a36Sopenharmony_ci{
318062306a36Sopenharmony_ci	int ret = 0;
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	if (cursor == NULL)
318362306a36Sopenharmony_ci		return -ENOMEM;
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci	callchain_cursor_reset(cursor);
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci	if (callchain_param.order == ORDER_CALLEE) {
318862306a36Sopenharmony_ci		ret = thread__resolve_callchain_sample(thread, cursor,
318962306a36Sopenharmony_ci						       evsel, sample,
319062306a36Sopenharmony_ci						       parent, root_al,
319162306a36Sopenharmony_ci						       max_stack);
319262306a36Sopenharmony_ci		if (ret)
319362306a36Sopenharmony_ci			return ret;
319462306a36Sopenharmony_ci		ret = thread__resolve_callchain_unwind(thread, cursor,
319562306a36Sopenharmony_ci						       evsel, sample,
319662306a36Sopenharmony_ci						       max_stack);
319762306a36Sopenharmony_ci	} else {
319862306a36Sopenharmony_ci		ret = thread__resolve_callchain_unwind(thread, cursor,
319962306a36Sopenharmony_ci						       evsel, sample,
320062306a36Sopenharmony_ci						       max_stack);
320162306a36Sopenharmony_ci		if (ret)
320262306a36Sopenharmony_ci			return ret;
320362306a36Sopenharmony_ci		ret = thread__resolve_callchain_sample(thread, cursor,
320462306a36Sopenharmony_ci						       evsel, sample,
320562306a36Sopenharmony_ci						       parent, root_al,
320662306a36Sopenharmony_ci						       max_stack);
320762306a36Sopenharmony_ci	}
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	return ret;
321062306a36Sopenharmony_ci}
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ciint machine__for_each_thread(struct machine *machine,
321362306a36Sopenharmony_ci			     int (*fn)(struct thread *thread, void *p),
321462306a36Sopenharmony_ci			     void *priv)
321562306a36Sopenharmony_ci{
321662306a36Sopenharmony_ci	struct threads *threads;
321762306a36Sopenharmony_ci	struct rb_node *nd;
321862306a36Sopenharmony_ci	int rc = 0;
321962306a36Sopenharmony_ci	int i;
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	for (i = 0; i < THREADS__TABLE_SIZE; i++) {
322262306a36Sopenharmony_ci		threads = &machine->threads[i];
322362306a36Sopenharmony_ci		for (nd = rb_first_cached(&threads->entries); nd;
322462306a36Sopenharmony_ci		     nd = rb_next(nd)) {
322562306a36Sopenharmony_ci			struct thread_rb_node *trb = rb_entry(nd, struct thread_rb_node, rb_node);
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci			rc = fn(trb->thread, priv);
322862306a36Sopenharmony_ci			if (rc != 0)
322962306a36Sopenharmony_ci				return rc;
323062306a36Sopenharmony_ci		}
323162306a36Sopenharmony_ci	}
323262306a36Sopenharmony_ci	return rc;
323362306a36Sopenharmony_ci}
323462306a36Sopenharmony_ci
323562306a36Sopenharmony_ciint machines__for_each_thread(struct machines *machines,
323662306a36Sopenharmony_ci			      int (*fn)(struct thread *thread, void *p),
323762306a36Sopenharmony_ci			      void *priv)
323862306a36Sopenharmony_ci{
323962306a36Sopenharmony_ci	struct rb_node *nd;
324062306a36Sopenharmony_ci	int rc = 0;
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_ci	rc = machine__for_each_thread(&machines->host, fn, priv);
324362306a36Sopenharmony_ci	if (rc != 0)
324462306a36Sopenharmony_ci		return rc;
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ci	for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) {
324762306a36Sopenharmony_ci		struct machine *machine = rb_entry(nd, struct machine, rb_node);
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci		rc = machine__for_each_thread(machine, fn, priv);
325062306a36Sopenharmony_ci		if (rc != 0)
325162306a36Sopenharmony_ci			return rc;
325262306a36Sopenharmony_ci	}
325362306a36Sopenharmony_ci	return rc;
325462306a36Sopenharmony_ci}
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_cipid_t machine__get_current_tid(struct machine *machine, int cpu)
325762306a36Sopenharmony_ci{
325862306a36Sopenharmony_ci	if (cpu < 0 || (size_t)cpu >= machine->current_tid_sz)
325962306a36Sopenharmony_ci		return -1;
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci	return machine->current_tid[cpu];
326262306a36Sopenharmony_ci}
326362306a36Sopenharmony_ci
326462306a36Sopenharmony_ciint machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
326562306a36Sopenharmony_ci			     pid_t tid)
326662306a36Sopenharmony_ci{
326762306a36Sopenharmony_ci	struct thread *thread;
326862306a36Sopenharmony_ci	const pid_t init_val = -1;
326962306a36Sopenharmony_ci
327062306a36Sopenharmony_ci	if (cpu < 0)
327162306a36Sopenharmony_ci		return -EINVAL;
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ci	if (realloc_array_as_needed(machine->current_tid,
327462306a36Sopenharmony_ci				    machine->current_tid_sz,
327562306a36Sopenharmony_ci				    (unsigned int)cpu,
327662306a36Sopenharmony_ci				    &init_val))
327762306a36Sopenharmony_ci		return -ENOMEM;
327862306a36Sopenharmony_ci
327962306a36Sopenharmony_ci	machine->current_tid[cpu] = tid;
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	thread = machine__findnew_thread(machine, pid, tid);
328262306a36Sopenharmony_ci	if (!thread)
328362306a36Sopenharmony_ci		return -ENOMEM;
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_ci	thread__set_cpu(thread, cpu);
328662306a36Sopenharmony_ci	thread__put(thread);
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci	return 0;
328962306a36Sopenharmony_ci}
329062306a36Sopenharmony_ci
329162306a36Sopenharmony_ci/*
329262306a36Sopenharmony_ci * Compares the raw arch string. N.B. see instead perf_env__arch() or
329362306a36Sopenharmony_ci * machine__normalized_is() if a normalized arch is needed.
329462306a36Sopenharmony_ci */
329562306a36Sopenharmony_cibool machine__is(struct machine *machine, const char *arch)
329662306a36Sopenharmony_ci{
329762306a36Sopenharmony_ci	return machine && !strcmp(perf_env__raw_arch(machine->env), arch);
329862306a36Sopenharmony_ci}
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_cibool machine__normalized_is(struct machine *machine, const char *arch)
330162306a36Sopenharmony_ci{
330262306a36Sopenharmony_ci	return machine && !strcmp(perf_env__arch(machine->env), arch);
330362306a36Sopenharmony_ci}
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ciint machine__nr_cpus_avail(struct machine *machine)
330662306a36Sopenharmony_ci{
330762306a36Sopenharmony_ci	return machine ? perf_env__nr_cpus_avail(machine->env) : 0;
330862306a36Sopenharmony_ci}
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_ciint machine__get_kernel_start(struct machine *machine)
331162306a36Sopenharmony_ci{
331262306a36Sopenharmony_ci	struct map *map = machine__kernel_map(machine);
331362306a36Sopenharmony_ci	int err = 0;
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_ci	/*
331662306a36Sopenharmony_ci	 * The only addresses above 2^63 are kernel addresses of a 64-bit
331762306a36Sopenharmony_ci	 * kernel.  Note that addresses are unsigned so that on a 32-bit system
331862306a36Sopenharmony_ci	 * all addresses including kernel addresses are less than 2^32.  In
331962306a36Sopenharmony_ci	 * that case (32-bit system), if the kernel mapping is unknown, all
332062306a36Sopenharmony_ci	 * addresses will be assumed to be in user space - see
332162306a36Sopenharmony_ci	 * machine__kernel_ip().
332262306a36Sopenharmony_ci	 */
332362306a36Sopenharmony_ci	machine->kernel_start = 1ULL << 63;
332462306a36Sopenharmony_ci	if (map) {
332562306a36Sopenharmony_ci		err = map__load(map);
332662306a36Sopenharmony_ci		/*
332762306a36Sopenharmony_ci		 * On x86_64, PTI entry trampolines are less than the
332862306a36Sopenharmony_ci		 * start of kernel text, but still above 2^63. So leave
332962306a36Sopenharmony_ci		 * kernel_start = 1ULL << 63 for x86_64.
333062306a36Sopenharmony_ci		 */
333162306a36Sopenharmony_ci		if (!err && !machine__is(machine, "x86_64"))
333262306a36Sopenharmony_ci			machine->kernel_start = map__start(map);
333362306a36Sopenharmony_ci	}
333462306a36Sopenharmony_ci	return err;
333562306a36Sopenharmony_ci}
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ciu8 machine__addr_cpumode(struct machine *machine, u8 cpumode, u64 addr)
333862306a36Sopenharmony_ci{
333962306a36Sopenharmony_ci	u8 addr_cpumode = cpumode;
334062306a36Sopenharmony_ci	bool kernel_ip;
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci	if (!machine->single_address_space)
334362306a36Sopenharmony_ci		goto out;
334462306a36Sopenharmony_ci
334562306a36Sopenharmony_ci	kernel_ip = machine__kernel_ip(machine, addr);
334662306a36Sopenharmony_ci	switch (cpumode) {
334762306a36Sopenharmony_ci	case PERF_RECORD_MISC_KERNEL:
334862306a36Sopenharmony_ci	case PERF_RECORD_MISC_USER:
334962306a36Sopenharmony_ci		addr_cpumode = kernel_ip ? PERF_RECORD_MISC_KERNEL :
335062306a36Sopenharmony_ci					   PERF_RECORD_MISC_USER;
335162306a36Sopenharmony_ci		break;
335262306a36Sopenharmony_ci	case PERF_RECORD_MISC_GUEST_KERNEL:
335362306a36Sopenharmony_ci	case PERF_RECORD_MISC_GUEST_USER:
335462306a36Sopenharmony_ci		addr_cpumode = kernel_ip ? PERF_RECORD_MISC_GUEST_KERNEL :
335562306a36Sopenharmony_ci					   PERF_RECORD_MISC_GUEST_USER;
335662306a36Sopenharmony_ci		break;
335762306a36Sopenharmony_ci	default:
335862306a36Sopenharmony_ci		break;
335962306a36Sopenharmony_ci	}
336062306a36Sopenharmony_ciout:
336162306a36Sopenharmony_ci	return addr_cpumode;
336262306a36Sopenharmony_ci}
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_cistruct dso *machine__findnew_dso_id(struct machine *machine, const char *filename, struct dso_id *id)
336562306a36Sopenharmony_ci{
336662306a36Sopenharmony_ci	return dsos__findnew_id(&machine->dsos, filename, id);
336762306a36Sopenharmony_ci}
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_cistruct dso *machine__findnew_dso(struct machine *machine, const char *filename)
337062306a36Sopenharmony_ci{
337162306a36Sopenharmony_ci	return machine__findnew_dso_id(machine, filename, NULL);
337262306a36Sopenharmony_ci}
337362306a36Sopenharmony_ci
337462306a36Sopenharmony_cichar *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
337562306a36Sopenharmony_ci{
337662306a36Sopenharmony_ci	struct machine *machine = vmachine;
337762306a36Sopenharmony_ci	struct map *map;
337862306a36Sopenharmony_ci	struct symbol *sym = machine__find_kernel_symbol(machine, *addrp, &map);
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	if (sym == NULL)
338162306a36Sopenharmony_ci		return NULL;
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci	*modp = __map__is_kmodule(map) ? (char *)map__dso(map)->short_name : NULL;
338462306a36Sopenharmony_ci	*addrp = map__unmap_ip(map, sym->start);
338562306a36Sopenharmony_ci	return sym->name;
338662306a36Sopenharmony_ci}
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ciint machine__for_each_dso(struct machine *machine, machine__dso_t fn, void *priv)
338962306a36Sopenharmony_ci{
339062306a36Sopenharmony_ci	struct dso *pos;
339162306a36Sopenharmony_ci	int err = 0;
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	list_for_each_entry(pos, &machine->dsos.head, node) {
339462306a36Sopenharmony_ci		if (fn(pos, machine, priv))
339562306a36Sopenharmony_ci			err = -1;
339662306a36Sopenharmony_ci	}
339762306a36Sopenharmony_ci	return err;
339862306a36Sopenharmony_ci}
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ciint machine__for_each_kernel_map(struct machine *machine, machine__map_t fn, void *priv)
340162306a36Sopenharmony_ci{
340262306a36Sopenharmony_ci	struct maps *maps = machine__kernel_maps(machine);
340362306a36Sopenharmony_ci	struct map_rb_node *pos;
340462306a36Sopenharmony_ci	int err = 0;
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci	maps__for_each_entry(maps, pos) {
340762306a36Sopenharmony_ci		err = fn(pos->map, priv);
340862306a36Sopenharmony_ci		if (err != 0) {
340962306a36Sopenharmony_ci			break;
341062306a36Sopenharmony_ci		}
341162306a36Sopenharmony_ci	}
341262306a36Sopenharmony_ci	return err;
341362306a36Sopenharmony_ci}
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_cibool machine__is_lock_function(struct machine *machine, u64 addr)
341662306a36Sopenharmony_ci{
341762306a36Sopenharmony_ci	if (!machine->sched.text_start) {
341862306a36Sopenharmony_ci		struct map *kmap;
341962306a36Sopenharmony_ci		struct symbol *sym = machine__find_kernel_symbol_by_name(machine, "__sched_text_start", &kmap);
342062306a36Sopenharmony_ci
342162306a36Sopenharmony_ci		if (!sym) {
342262306a36Sopenharmony_ci			/* to avoid retry */
342362306a36Sopenharmony_ci			machine->sched.text_start = 1;
342462306a36Sopenharmony_ci			return false;
342562306a36Sopenharmony_ci		}
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci		machine->sched.text_start = map__unmap_ip(kmap, sym->start);
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci		/* should not fail from here */
343062306a36Sopenharmony_ci		sym = machine__find_kernel_symbol_by_name(machine, "__sched_text_end", &kmap);
343162306a36Sopenharmony_ci		machine->sched.text_end = map__unmap_ip(kmap, sym->start);
343262306a36Sopenharmony_ci
343362306a36Sopenharmony_ci		sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_start", &kmap);
343462306a36Sopenharmony_ci		machine->lock.text_start = map__unmap_ip(kmap, sym->start);
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci		sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_end", &kmap);
343762306a36Sopenharmony_ci		machine->lock.text_end = map__unmap_ip(kmap, sym->start);
343862306a36Sopenharmony_ci	}
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	/* failed to get kernel symbols */
344162306a36Sopenharmony_ci	if (machine->sched.text_start == 1)
344262306a36Sopenharmony_ci		return false;
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_ci	/* mutex and rwsem functions are in sched text section */
344562306a36Sopenharmony_ci	if (machine->sched.text_start <= addr && addr < machine->sched.text_end)
344662306a36Sopenharmony_ci		return true;
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_ci	/* spinlock functions are in lock text section */
344962306a36Sopenharmony_ci	if (machine->lock.text_start <= addr && addr < machine->lock.text_end)
345062306a36Sopenharmony_ci		return true;
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci	return false;
345362306a36Sopenharmony_ci}
3454