18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <dirent.h>
38c2ecf20Sopenharmony_ci#include <errno.h>
48c2ecf20Sopenharmony_ci#include <stdlib.h>
58c2ecf20Sopenharmony_ci#include <stdio.h>
68c2ecf20Sopenharmony_ci#include <string.h>
78c2ecf20Sopenharmony_ci#include <linux/capability.h>
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/mman.h>
108c2ecf20Sopenharmony_ci#include <linux/string.h>
118c2ecf20Sopenharmony_ci#include <linux/time64.h>
128c2ecf20Sopenharmony_ci#include <sys/types.h>
138c2ecf20Sopenharmony_ci#include <sys/stat.h>
148c2ecf20Sopenharmony_ci#include <sys/param.h>
158c2ecf20Sopenharmony_ci#include <fcntl.h>
168c2ecf20Sopenharmony_ci#include <unistd.h>
178c2ecf20Sopenharmony_ci#include <inttypes.h>
188c2ecf20Sopenharmony_ci#include "annotate.h"
198c2ecf20Sopenharmony_ci#include "build-id.h"
208c2ecf20Sopenharmony_ci#include "cap.h"
218c2ecf20Sopenharmony_ci#include "dso.h"
228c2ecf20Sopenharmony_ci#include "util.h" // lsdir()
238c2ecf20Sopenharmony_ci#include "debug.h"
248c2ecf20Sopenharmony_ci#include "event.h"
258c2ecf20Sopenharmony_ci#include "machine.h"
268c2ecf20Sopenharmony_ci#include "map.h"
278c2ecf20Sopenharmony_ci#include "symbol.h"
288c2ecf20Sopenharmony_ci#include "map_symbol.h"
298c2ecf20Sopenharmony_ci#include "mem-events.h"
308c2ecf20Sopenharmony_ci#include "symsrc.h"
318c2ecf20Sopenharmony_ci#include "strlist.h"
328c2ecf20Sopenharmony_ci#include "intlist.h"
338c2ecf20Sopenharmony_ci#include "namespaces.h"
348c2ecf20Sopenharmony_ci#include "header.h"
358c2ecf20Sopenharmony_ci#include "path.h"
368c2ecf20Sopenharmony_ci#include <linux/ctype.h>
378c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#include <elf.h>
408c2ecf20Sopenharmony_ci#include <limits.h>
418c2ecf20Sopenharmony_ci#include <symbol/kallsyms.h>
428c2ecf20Sopenharmony_ci#include <sys/utsname.h>
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic int dso__load_kernel_sym(struct dso *dso, struct map *map);
458c2ecf20Sopenharmony_cistatic int dso__load_guest_kernel_sym(struct dso *dso, struct map *map);
468c2ecf20Sopenharmony_cistatic bool symbol__is_idle(const char *name);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciint vmlinux_path__nr_entries;
498c2ecf20Sopenharmony_cichar **vmlinux_path;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistruct symbol_conf symbol_conf = {
528c2ecf20Sopenharmony_ci	.nanosecs		= false,
538c2ecf20Sopenharmony_ci	.use_modules		= true,
548c2ecf20Sopenharmony_ci	.try_vmlinux_path	= true,
558c2ecf20Sopenharmony_ci	.demangle		= true,
568c2ecf20Sopenharmony_ci	.demangle_kernel	= false,
578c2ecf20Sopenharmony_ci	.cumulate_callchain	= true,
588c2ecf20Sopenharmony_ci	.time_quantum		= 100 * NSEC_PER_MSEC, /* 100ms */
598c2ecf20Sopenharmony_ci	.show_hist_headers	= true,
608c2ecf20Sopenharmony_ci	.symfs			= "",
618c2ecf20Sopenharmony_ci	.event_group		= true,
628c2ecf20Sopenharmony_ci	.inline_name		= true,
638c2ecf20Sopenharmony_ci	.res_sample		= 0,
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic enum dso_binary_type binary_type_symtab[] = {
678c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__KALLSYMS,
688c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__GUEST_KALLSYMS,
698c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__JAVA_JIT,
708c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__DEBUGLINK,
718c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__BUILD_ID_CACHE,
728c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO,
738c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
748c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
758c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
768c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
778c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__GUEST_KMODULE,
788c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
798c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
808c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
818c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
828c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO,
838c2ecf20Sopenharmony_ci	DSO_BINARY_TYPE__NOT_FOUND,
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic bool symbol_type__filter(char symbol_type)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	symbol_type = toupper(symbol_type);
918c2ecf20Sopenharmony_ci	return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D' || symbol_type == 'B';
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic int prefix_underscores_count(const char *str)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	const char *tail = str;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	while (*tail == '_')
998c2ecf20Sopenharmony_ci		tail++;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	return tail - str;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ciconst char * __weak arch__normalize_symbol_name(const char *name)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	return name;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ciint __weak arch__compare_symbol_names(const char *namea, const char *nameb)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	return strcmp(namea, nameb);
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ciint __weak arch__compare_symbol_names_n(const char *namea, const char *nameb,
1158c2ecf20Sopenharmony_ci					unsigned int n)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	return strncmp(namea, nameb, n);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ciint __weak arch__choose_best_symbol(struct symbol *syma,
1218c2ecf20Sopenharmony_ci				    struct symbol *symb __maybe_unused)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	/* Avoid "SyS" kernel syscall aliases */
1248c2ecf20Sopenharmony_ci	if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3))
1258c2ecf20Sopenharmony_ci		return SYMBOL_B;
1268c2ecf20Sopenharmony_ci	if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10))
1278c2ecf20Sopenharmony_ci		return SYMBOL_B;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return SYMBOL_A;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int choose_best_symbol(struct symbol *syma, struct symbol *symb)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	s64 a;
1358c2ecf20Sopenharmony_ci	s64 b;
1368c2ecf20Sopenharmony_ci	size_t na, nb;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/* Prefer a symbol with non zero length */
1398c2ecf20Sopenharmony_ci	a = syma->end - syma->start;
1408c2ecf20Sopenharmony_ci	b = symb->end - symb->start;
1418c2ecf20Sopenharmony_ci	if ((b == 0) && (a > 0))
1428c2ecf20Sopenharmony_ci		return SYMBOL_A;
1438c2ecf20Sopenharmony_ci	else if ((a == 0) && (b > 0))
1448c2ecf20Sopenharmony_ci		return SYMBOL_B;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* Prefer a non weak symbol over a weak one */
1478c2ecf20Sopenharmony_ci	a = syma->binding == STB_WEAK;
1488c2ecf20Sopenharmony_ci	b = symb->binding == STB_WEAK;
1498c2ecf20Sopenharmony_ci	if (b && !a)
1508c2ecf20Sopenharmony_ci		return SYMBOL_A;
1518c2ecf20Sopenharmony_ci	if (a && !b)
1528c2ecf20Sopenharmony_ci		return SYMBOL_B;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* Prefer a global symbol over a non global one */
1558c2ecf20Sopenharmony_ci	a = syma->binding == STB_GLOBAL;
1568c2ecf20Sopenharmony_ci	b = symb->binding == STB_GLOBAL;
1578c2ecf20Sopenharmony_ci	if (a && !b)
1588c2ecf20Sopenharmony_ci		return SYMBOL_A;
1598c2ecf20Sopenharmony_ci	if (b && !a)
1608c2ecf20Sopenharmony_ci		return SYMBOL_B;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* Prefer a symbol with less underscores */
1638c2ecf20Sopenharmony_ci	a = prefix_underscores_count(syma->name);
1648c2ecf20Sopenharmony_ci	b = prefix_underscores_count(symb->name);
1658c2ecf20Sopenharmony_ci	if (b > a)
1668c2ecf20Sopenharmony_ci		return SYMBOL_A;
1678c2ecf20Sopenharmony_ci	else if (a > b)
1688c2ecf20Sopenharmony_ci		return SYMBOL_B;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	/* Choose the symbol with the longest name */
1718c2ecf20Sopenharmony_ci	na = strlen(syma->name);
1728c2ecf20Sopenharmony_ci	nb = strlen(symb->name);
1738c2ecf20Sopenharmony_ci	if (na > nb)
1748c2ecf20Sopenharmony_ci		return SYMBOL_A;
1758c2ecf20Sopenharmony_ci	else if (na < nb)
1768c2ecf20Sopenharmony_ci		return SYMBOL_B;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return arch__choose_best_symbol(syma, symb);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_civoid symbols__fixup_duplicate(struct rb_root_cached *symbols)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct rb_node *nd;
1848c2ecf20Sopenharmony_ci	struct symbol *curr, *next;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (symbol_conf.allow_aliases)
1878c2ecf20Sopenharmony_ci		return;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	nd = rb_first_cached(symbols);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	while (nd) {
1928c2ecf20Sopenharmony_ci		curr = rb_entry(nd, struct symbol, rb_node);
1938c2ecf20Sopenharmony_ciagain:
1948c2ecf20Sopenharmony_ci		nd = rb_next(&curr->rb_node);
1958c2ecf20Sopenharmony_ci		next = rb_entry(nd, struct symbol, rb_node);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		if (!nd)
1988c2ecf20Sopenharmony_ci			break;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		if (curr->start != next->start)
2018c2ecf20Sopenharmony_ci			continue;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		if (choose_best_symbol(curr, next) == SYMBOL_A) {
2048c2ecf20Sopenharmony_ci			rb_erase_cached(&next->rb_node, symbols);
2058c2ecf20Sopenharmony_ci			symbol__delete(next);
2068c2ecf20Sopenharmony_ci			goto again;
2078c2ecf20Sopenharmony_ci		} else {
2088c2ecf20Sopenharmony_ci			nd = rb_next(&curr->rb_node);
2098c2ecf20Sopenharmony_ci			rb_erase_cached(&curr->rb_node, symbols);
2108c2ecf20Sopenharmony_ci			symbol__delete(curr);
2118c2ecf20Sopenharmony_ci		}
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/* Update zero-sized symbols using the address of the next symbol */
2168c2ecf20Sopenharmony_civoid symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct rb_node *nd, *prevnd = rb_first_cached(symbols);
2198c2ecf20Sopenharmony_ci	struct symbol *curr, *prev;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (prevnd == NULL)
2228c2ecf20Sopenharmony_ci		return;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	curr = rb_entry(prevnd, struct symbol, rb_node);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
2278c2ecf20Sopenharmony_ci		prev = curr;
2288c2ecf20Sopenharmony_ci		curr = rb_entry(nd, struct symbol, rb_node);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		/*
2318c2ecf20Sopenharmony_ci		 * On some architecture kernel text segment start is located at
2328c2ecf20Sopenharmony_ci		 * some low memory address, while modules are located at high
2338c2ecf20Sopenharmony_ci		 * memory addresses (or vice versa).  The gap between end of
2348c2ecf20Sopenharmony_ci		 * kernel text segment and beginning of first module's text
2358c2ecf20Sopenharmony_ci		 * segment is very big.  Therefore do not fill this gap and do
2368c2ecf20Sopenharmony_ci		 * not assign it to the kernel dso map (kallsyms).
2378c2ecf20Sopenharmony_ci		 *
2388c2ecf20Sopenharmony_ci		 * In kallsyms, it determines module symbols using '[' character
2398c2ecf20Sopenharmony_ci		 * like in:
2408c2ecf20Sopenharmony_ci		 *   ffffffffc1937000 T hdmi_driver_init  [snd_hda_codec_hdmi]
2418c2ecf20Sopenharmony_ci		 */
2428c2ecf20Sopenharmony_ci		if (prev->end == prev->start) {
2438c2ecf20Sopenharmony_ci			/* Last kernel/module symbol mapped to end of page */
2448c2ecf20Sopenharmony_ci			if (is_kallsyms && (!strchr(prev->name, '[') !=
2458c2ecf20Sopenharmony_ci					    !strchr(curr->name, '[')))
2468c2ecf20Sopenharmony_ci				prev->end = roundup(prev->end + 4096, 4096);
2478c2ecf20Sopenharmony_ci			else
2488c2ecf20Sopenharmony_ci				prev->end = curr->start;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci			pr_debug4("%s sym:%s end:%#" PRIx64 "\n",
2518c2ecf20Sopenharmony_ci				  __func__, prev->name, prev->end);
2528c2ecf20Sopenharmony_ci		}
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	/* Last entry */
2568c2ecf20Sopenharmony_ci	if (curr->end == curr->start)
2578c2ecf20Sopenharmony_ci		curr->end = roundup(curr->start, 4096) + 4096;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_civoid maps__fixup_end(struct maps *maps)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct map *prev = NULL, *curr;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	down_write(&maps->lock);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	maps__for_each_entry(maps, curr) {
2678c2ecf20Sopenharmony_ci		if (prev != NULL && !prev->end)
2688c2ecf20Sopenharmony_ci			prev->end = curr->start;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		prev = curr;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/*
2748c2ecf20Sopenharmony_ci	 * We still haven't the actual symbols, so guess the
2758c2ecf20Sopenharmony_ci	 * last map final address.
2768c2ecf20Sopenharmony_ci	 */
2778c2ecf20Sopenharmony_ci	if (curr && !curr->end)
2788c2ecf20Sopenharmony_ci		curr->end = ~0ULL;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	up_write(&maps->lock);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistruct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	size_t namelen = strlen(name) + 1;
2868c2ecf20Sopenharmony_ci	struct symbol *sym = calloc(1, (symbol_conf.priv_size +
2878c2ecf20Sopenharmony_ci					sizeof(*sym) + namelen));
2888c2ecf20Sopenharmony_ci	if (sym == NULL)
2898c2ecf20Sopenharmony_ci		return NULL;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (symbol_conf.priv_size) {
2928c2ecf20Sopenharmony_ci		if (symbol_conf.init_annotation) {
2938c2ecf20Sopenharmony_ci			struct annotation *notes = (void *)sym;
2948c2ecf20Sopenharmony_ci			pthread_mutex_init(&notes->lock, NULL);
2958c2ecf20Sopenharmony_ci		}
2968c2ecf20Sopenharmony_ci		sym = ((void *)sym) + symbol_conf.priv_size;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	sym->start   = start;
3008c2ecf20Sopenharmony_ci	sym->end     = len ? start + len : start;
3018c2ecf20Sopenharmony_ci	sym->type    = type;
3028c2ecf20Sopenharmony_ci	sym->binding = binding;
3038c2ecf20Sopenharmony_ci	sym->namelen = namelen - 1;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
3068c2ecf20Sopenharmony_ci		  __func__, name, start, sym->end);
3078c2ecf20Sopenharmony_ci	memcpy(sym->name, name, namelen);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	return sym;
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_civoid symbol__delete(struct symbol *sym)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	free(((void *)sym) - symbol_conf.priv_size);
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_civoid symbols__delete(struct rb_root_cached *symbols)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct symbol *pos;
3208c2ecf20Sopenharmony_ci	struct rb_node *next = rb_first_cached(symbols);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	while (next) {
3238c2ecf20Sopenharmony_ci		pos = rb_entry(next, struct symbol, rb_node);
3248c2ecf20Sopenharmony_ci		next = rb_next(&pos->rb_node);
3258c2ecf20Sopenharmony_ci		rb_erase_cached(&pos->rb_node, symbols);
3268c2ecf20Sopenharmony_ci		symbol__delete(pos);
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_civoid __symbols__insert(struct rb_root_cached *symbols,
3318c2ecf20Sopenharmony_ci		       struct symbol *sym, bool kernel)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct rb_node **p = &symbols->rb_root.rb_node;
3348c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
3358c2ecf20Sopenharmony_ci	const u64 ip = sym->start;
3368c2ecf20Sopenharmony_ci	struct symbol *s;
3378c2ecf20Sopenharmony_ci	bool leftmost = true;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (kernel) {
3408c2ecf20Sopenharmony_ci		const char *name = sym->name;
3418c2ecf20Sopenharmony_ci		/*
3428c2ecf20Sopenharmony_ci		 * ppc64 uses function descriptors and appends a '.' to the
3438c2ecf20Sopenharmony_ci		 * start of every instruction address. Remove it.
3448c2ecf20Sopenharmony_ci		 */
3458c2ecf20Sopenharmony_ci		if (name[0] == '.')
3468c2ecf20Sopenharmony_ci			name++;
3478c2ecf20Sopenharmony_ci		sym->idle = symbol__is_idle(name);
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	while (*p != NULL) {
3518c2ecf20Sopenharmony_ci		parent = *p;
3528c2ecf20Sopenharmony_ci		s = rb_entry(parent, struct symbol, rb_node);
3538c2ecf20Sopenharmony_ci		if (ip < s->start)
3548c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
3558c2ecf20Sopenharmony_ci		else {
3568c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
3578c2ecf20Sopenharmony_ci			leftmost = false;
3588c2ecf20Sopenharmony_ci		}
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci	rb_link_node(&sym->rb_node, parent, p);
3618c2ecf20Sopenharmony_ci	rb_insert_color_cached(&sym->rb_node, symbols, leftmost);
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_civoid symbols__insert(struct rb_root_cached *symbols, struct symbol *sym)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	__symbols__insert(symbols, sym, false);
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic struct symbol *symbols__find(struct rb_root_cached *symbols, u64 ip)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	struct rb_node *n;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	if (symbols == NULL)
3748c2ecf20Sopenharmony_ci		return NULL;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	n = symbols->rb_root.rb_node;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	while (n) {
3798c2ecf20Sopenharmony_ci		struct symbol *s = rb_entry(n, struct symbol, rb_node);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci		if (ip < s->start)
3828c2ecf20Sopenharmony_ci			n = n->rb_left;
3838c2ecf20Sopenharmony_ci		else if (ip > s->end || (ip == s->end && ip != s->start))
3848c2ecf20Sopenharmony_ci			n = n->rb_right;
3858c2ecf20Sopenharmony_ci		else
3868c2ecf20Sopenharmony_ci			return s;
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	return NULL;
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic struct symbol *symbols__first(struct rb_root_cached *symbols)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	struct rb_node *n = rb_first_cached(symbols);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (n)
3978c2ecf20Sopenharmony_ci		return rb_entry(n, struct symbol, rb_node);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	return NULL;
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic struct symbol *symbols__last(struct rb_root_cached *symbols)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct rb_node *n = rb_last(&symbols->rb_root);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	if (n)
4078c2ecf20Sopenharmony_ci		return rb_entry(n, struct symbol, rb_node);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return NULL;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic struct symbol *symbols__next(struct symbol *sym)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct rb_node *n = rb_next(&sym->rb_node);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (n)
4178c2ecf20Sopenharmony_ci		return rb_entry(n, struct symbol, rb_node);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return NULL;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic void symbols__insert_by_name(struct rb_root_cached *symbols, struct symbol *sym)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct rb_node **p = &symbols->rb_root.rb_node;
4258c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
4268c2ecf20Sopenharmony_ci	struct symbol_name_rb_node *symn, *s;
4278c2ecf20Sopenharmony_ci	bool leftmost = true;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	symn = container_of(sym, struct symbol_name_rb_node, sym);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	while (*p != NULL) {
4328c2ecf20Sopenharmony_ci		parent = *p;
4338c2ecf20Sopenharmony_ci		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
4348c2ecf20Sopenharmony_ci		if (strcmp(sym->name, s->sym.name) < 0)
4358c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
4368c2ecf20Sopenharmony_ci		else {
4378c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
4388c2ecf20Sopenharmony_ci			leftmost = false;
4398c2ecf20Sopenharmony_ci		}
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci	rb_link_node(&symn->rb_node, parent, p);
4428c2ecf20Sopenharmony_ci	rb_insert_color_cached(&symn->rb_node, symbols, leftmost);
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_cistatic void symbols__sort_by_name(struct rb_root_cached *symbols,
4468c2ecf20Sopenharmony_ci				  struct rb_root_cached *source)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	struct rb_node *nd;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) {
4518c2ecf20Sopenharmony_ci		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
4528c2ecf20Sopenharmony_ci		symbols__insert_by_name(symbols, pos);
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ciint symbol__match_symbol_name(const char *name, const char *str,
4578c2ecf20Sopenharmony_ci			      enum symbol_tag_include includes)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	const char *versioning;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	if (includes == SYMBOL_TAG_INCLUDE__DEFAULT_ONLY &&
4628c2ecf20Sopenharmony_ci	    (versioning = strstr(name, "@@"))) {
4638c2ecf20Sopenharmony_ci		int len = strlen(str);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		if (len < versioning - name)
4668c2ecf20Sopenharmony_ci			len = versioning - name;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		return arch__compare_symbol_names_n(name, str, len);
4698c2ecf20Sopenharmony_ci	} else
4708c2ecf20Sopenharmony_ci		return arch__compare_symbol_names(name, str);
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic struct symbol *symbols__find_by_name(struct rb_root_cached *symbols,
4748c2ecf20Sopenharmony_ci					    const char *name,
4758c2ecf20Sopenharmony_ci					    enum symbol_tag_include includes)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	struct rb_node *n;
4788c2ecf20Sopenharmony_ci	struct symbol_name_rb_node *s = NULL;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	if (symbols == NULL)
4818c2ecf20Sopenharmony_ci		return NULL;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	n = symbols->rb_root.rb_node;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	while (n) {
4868c2ecf20Sopenharmony_ci		int cmp;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
4898c2ecf20Sopenharmony_ci		cmp = symbol__match_symbol_name(s->sym.name, name, includes);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci		if (cmp > 0)
4928c2ecf20Sopenharmony_ci			n = n->rb_left;
4938c2ecf20Sopenharmony_ci		else if (cmp < 0)
4948c2ecf20Sopenharmony_ci			n = n->rb_right;
4958c2ecf20Sopenharmony_ci		else
4968c2ecf20Sopenharmony_ci			break;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (n == NULL)
5008c2ecf20Sopenharmony_ci		return NULL;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY)
5038c2ecf20Sopenharmony_ci		/* return first symbol that has same name (if any) */
5048c2ecf20Sopenharmony_ci		for (n = rb_prev(n); n; n = rb_prev(n)) {
5058c2ecf20Sopenharmony_ci			struct symbol_name_rb_node *tmp;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci			tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
5088c2ecf20Sopenharmony_ci			if (arch__compare_symbol_names(tmp->sym.name, s->sym.name))
5098c2ecf20Sopenharmony_ci				break;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci			s = tmp;
5128c2ecf20Sopenharmony_ci		}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	return &s->sym;
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_civoid dso__reset_find_symbol_cache(struct dso *dso)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	dso->last_find_result.addr   = 0;
5208c2ecf20Sopenharmony_ci	dso->last_find_result.symbol = NULL;
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_civoid dso__insert_symbol(struct dso *dso, struct symbol *sym)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	__symbols__insert(&dso->symbols, sym, dso->kernel);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	/* update the symbol cache if necessary */
5288c2ecf20Sopenharmony_ci	if (dso->last_find_result.addr >= sym->start &&
5298c2ecf20Sopenharmony_ci	    (dso->last_find_result.addr < sym->end ||
5308c2ecf20Sopenharmony_ci	    sym->start == sym->end)) {
5318c2ecf20Sopenharmony_ci		dso->last_find_result.symbol = sym;
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_civoid dso__delete_symbol(struct dso *dso, struct symbol *sym)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	rb_erase_cached(&sym->rb_node, &dso->symbols);
5388c2ecf20Sopenharmony_ci	symbol__delete(sym);
5398c2ecf20Sopenharmony_ci	dso__reset_find_symbol_cache(dso);
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistruct symbol *dso__find_symbol(struct dso *dso, u64 addr)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	if (dso->last_find_result.addr != addr || dso->last_find_result.symbol == NULL) {
5458c2ecf20Sopenharmony_ci		dso->last_find_result.addr   = addr;
5468c2ecf20Sopenharmony_ci		dso->last_find_result.symbol = symbols__find(&dso->symbols, addr);
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	return dso->last_find_result.symbol;
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cistruct symbol *dso__first_symbol(struct dso *dso)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	return symbols__first(&dso->symbols);
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistruct symbol *dso__last_symbol(struct dso *dso)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	return symbols__last(&dso->symbols);
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_cistruct symbol *dso__next_symbol(struct symbol *sym)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	return symbols__next(sym);
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistruct symbol *symbol__next_by_name(struct symbol *sym)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym);
5708c2ecf20Sopenharmony_ci	struct rb_node *n = rb_next(&s->rb_node);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL;
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci /*
5768c2ecf20Sopenharmony_ci  * Returns first symbol that matched with @name.
5778c2ecf20Sopenharmony_ci  */
5788c2ecf20Sopenharmony_cistruct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	struct symbol *s = symbols__find_by_name(&dso->symbol_names, name,
5818c2ecf20Sopenharmony_ci						 SYMBOL_TAG_INCLUDE__NONE);
5828c2ecf20Sopenharmony_ci	if (!s)
5838c2ecf20Sopenharmony_ci		s = symbols__find_by_name(&dso->symbol_names, name,
5848c2ecf20Sopenharmony_ci					  SYMBOL_TAG_INCLUDE__DEFAULT_ONLY);
5858c2ecf20Sopenharmony_ci	return s;
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_civoid dso__sort_by_name(struct dso *dso)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	dso__set_sorted_by_name(dso);
5918c2ecf20Sopenharmony_ci	return symbols__sort_by_name(&dso->symbol_names, &dso->symbols);
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci/*
5958c2ecf20Sopenharmony_ci * While we find nice hex chars, build a long_val.
5968c2ecf20Sopenharmony_ci * Return number of chars processed.
5978c2ecf20Sopenharmony_ci */
5988c2ecf20Sopenharmony_cistatic int hex2u64(const char *ptr, u64 *long_val)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	char *p;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	*long_val = strtoull(ptr, &p, 16);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	return p - ptr;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ciint modules__parse(const char *filename, void *arg,
6098c2ecf20Sopenharmony_ci		   int (*process_module)(void *arg, const char *name,
6108c2ecf20Sopenharmony_ci					 u64 start, u64 size))
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	char *line = NULL;
6138c2ecf20Sopenharmony_ci	size_t n;
6148c2ecf20Sopenharmony_ci	FILE *file;
6158c2ecf20Sopenharmony_ci	int err = 0;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	file = fopen(filename, "r");
6188c2ecf20Sopenharmony_ci	if (file == NULL)
6198c2ecf20Sopenharmony_ci		return -1;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	while (1) {
6228c2ecf20Sopenharmony_ci		char name[PATH_MAX];
6238c2ecf20Sopenharmony_ci		u64 start, size;
6248c2ecf20Sopenharmony_ci		char *sep, *endptr;
6258c2ecf20Sopenharmony_ci		ssize_t line_len;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci		line_len = getline(&line, &n, file);
6288c2ecf20Sopenharmony_ci		if (line_len < 0) {
6298c2ecf20Sopenharmony_ci			if (feof(file))
6308c2ecf20Sopenharmony_ci				break;
6318c2ecf20Sopenharmony_ci			err = -1;
6328c2ecf20Sopenharmony_ci			goto out;
6338c2ecf20Sopenharmony_ci		}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		if (!line) {
6368c2ecf20Sopenharmony_ci			err = -1;
6378c2ecf20Sopenharmony_ci			goto out;
6388c2ecf20Sopenharmony_ci		}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci		line[--line_len] = '\0'; /* \n */
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		sep = strrchr(line, 'x');
6438c2ecf20Sopenharmony_ci		if (sep == NULL)
6448c2ecf20Sopenharmony_ci			continue;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci		hex2u64(sep + 1, &start);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci		sep = strchr(line, ' ');
6498c2ecf20Sopenharmony_ci		if (sep == NULL)
6508c2ecf20Sopenharmony_ci			continue;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci		*sep = '\0';
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci		scnprintf(name, sizeof(name), "[%s]", line);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci		size = strtoul(sep + 1, &endptr, 0);
6578c2ecf20Sopenharmony_ci		if (*endptr != ' ' && *endptr != '\t')
6588c2ecf20Sopenharmony_ci			continue;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci		err = process_module(arg, name, start, size);
6618c2ecf20Sopenharmony_ci		if (err)
6628c2ecf20Sopenharmony_ci			break;
6638c2ecf20Sopenharmony_ci	}
6648c2ecf20Sopenharmony_ciout:
6658c2ecf20Sopenharmony_ci	free(line);
6668c2ecf20Sopenharmony_ci	fclose(file);
6678c2ecf20Sopenharmony_ci	return err;
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci/*
6718c2ecf20Sopenharmony_ci * These are symbols in the kernel image, so make sure that
6728c2ecf20Sopenharmony_ci * sym is from a kernel DSO.
6738c2ecf20Sopenharmony_ci */
6748c2ecf20Sopenharmony_cistatic bool symbol__is_idle(const char *name)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	const char * const idle_symbols[] = {
6778c2ecf20Sopenharmony_ci		"acpi_idle_do_entry",
6788c2ecf20Sopenharmony_ci		"acpi_processor_ffh_cstate_enter",
6798c2ecf20Sopenharmony_ci		"arch_cpu_idle",
6808c2ecf20Sopenharmony_ci		"cpu_idle",
6818c2ecf20Sopenharmony_ci		"cpu_startup_entry",
6828c2ecf20Sopenharmony_ci		"idle_cpu",
6838c2ecf20Sopenharmony_ci		"intel_idle",
6848c2ecf20Sopenharmony_ci		"default_idle",
6858c2ecf20Sopenharmony_ci		"native_safe_halt",
6868c2ecf20Sopenharmony_ci		"enter_idle",
6878c2ecf20Sopenharmony_ci		"exit_idle",
6888c2ecf20Sopenharmony_ci		"mwait_idle",
6898c2ecf20Sopenharmony_ci		"mwait_idle_with_hints",
6908c2ecf20Sopenharmony_ci		"mwait_idle_with_hints.constprop.0",
6918c2ecf20Sopenharmony_ci		"poll_idle",
6928c2ecf20Sopenharmony_ci		"ppc64_runlatch_off",
6938c2ecf20Sopenharmony_ci		"pseries_dedicated_idle_sleep",
6948c2ecf20Sopenharmony_ci		"psw_idle",
6958c2ecf20Sopenharmony_ci		"psw_idle_exit",
6968c2ecf20Sopenharmony_ci		NULL
6978c2ecf20Sopenharmony_ci	};
6988c2ecf20Sopenharmony_ci	int i;
6998c2ecf20Sopenharmony_ci	static struct strlist *idle_symbols_list;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	if (idle_symbols_list)
7028c2ecf20Sopenharmony_ci		return strlist__has_entry(idle_symbols_list, name);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	idle_symbols_list = strlist__new(NULL, NULL);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	for (i = 0; idle_symbols[i]; i++)
7078c2ecf20Sopenharmony_ci		strlist__add(idle_symbols_list, idle_symbols[i]);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	return strlist__has_entry(idle_symbols_list, name);
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic int map__process_kallsym_symbol(void *arg, const char *name,
7138c2ecf20Sopenharmony_ci				       char type, u64 start)
7148c2ecf20Sopenharmony_ci{
7158c2ecf20Sopenharmony_ci	struct symbol *sym;
7168c2ecf20Sopenharmony_ci	struct dso *dso = arg;
7178c2ecf20Sopenharmony_ci	struct rb_root_cached *root = &dso->symbols;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	if (!symbol_type__filter(type))
7208c2ecf20Sopenharmony_ci		return 0;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	/*
7238c2ecf20Sopenharmony_ci	 * module symbols are not sorted so we add all
7248c2ecf20Sopenharmony_ci	 * symbols, setting length to 0, and rely on
7258c2ecf20Sopenharmony_ci	 * symbols__fixup_end() to fix it up.
7268c2ecf20Sopenharmony_ci	 */
7278c2ecf20Sopenharmony_ci	sym = symbol__new(start, 0, kallsyms2elf_binding(type), kallsyms2elf_type(type), name);
7288c2ecf20Sopenharmony_ci	if (sym == NULL)
7298c2ecf20Sopenharmony_ci		return -ENOMEM;
7308c2ecf20Sopenharmony_ci	/*
7318c2ecf20Sopenharmony_ci	 * We will pass the symbols to the filter later, in
7328c2ecf20Sopenharmony_ci	 * map__split_kallsyms, when we have split the maps per module
7338c2ecf20Sopenharmony_ci	 */
7348c2ecf20Sopenharmony_ci	__symbols__insert(root, sym, !strchr(name, '['));
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	return 0;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci/*
7408c2ecf20Sopenharmony_ci * Loads the function entries in /proc/kallsyms into kernel_map->dso,
7418c2ecf20Sopenharmony_ci * so that we can in the next step set the symbol ->end address and then
7428c2ecf20Sopenharmony_ci * call kernel_maps__split_kallsyms.
7438c2ecf20Sopenharmony_ci */
7448c2ecf20Sopenharmony_cistatic int dso__load_all_kallsyms(struct dso *dso, const char *filename)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	return kallsyms__parse(filename, dso, map__process_kallsym_symbol);
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_cistatic int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	struct map *curr_map;
7528c2ecf20Sopenharmony_ci	struct symbol *pos;
7538c2ecf20Sopenharmony_ci	int count = 0;
7548c2ecf20Sopenharmony_ci	struct rb_root_cached old_root = dso->symbols;
7558c2ecf20Sopenharmony_ci	struct rb_root_cached *root = &dso->symbols;
7568c2ecf20Sopenharmony_ci	struct rb_node *next = rb_first_cached(root);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (!kmaps)
7598c2ecf20Sopenharmony_ci		return -1;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	*root = RB_ROOT_CACHED;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	while (next) {
7648c2ecf20Sopenharmony_ci		char *module;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci		pos = rb_entry(next, struct symbol, rb_node);
7678c2ecf20Sopenharmony_ci		next = rb_next(&pos->rb_node);
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci		rb_erase_cached(&pos->rb_node, &old_root);
7708c2ecf20Sopenharmony_ci		RB_CLEAR_NODE(&pos->rb_node);
7718c2ecf20Sopenharmony_ci		module = strchr(pos->name, '\t');
7728c2ecf20Sopenharmony_ci		if (module)
7738c2ecf20Sopenharmony_ci			*module = '\0';
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci		curr_map = maps__find(kmaps, pos->start);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci		if (!curr_map) {
7788c2ecf20Sopenharmony_ci			symbol__delete(pos);
7798c2ecf20Sopenharmony_ci			continue;
7808c2ecf20Sopenharmony_ci		}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci		pos->start -= curr_map->start - curr_map->pgoff;
7838c2ecf20Sopenharmony_ci		if (pos->end > curr_map->end)
7848c2ecf20Sopenharmony_ci			pos->end = curr_map->end;
7858c2ecf20Sopenharmony_ci		if (pos->end)
7868c2ecf20Sopenharmony_ci			pos->end -= curr_map->start - curr_map->pgoff;
7878c2ecf20Sopenharmony_ci		symbols__insert(&curr_map->dso->symbols, pos);
7888c2ecf20Sopenharmony_ci		++count;
7898c2ecf20Sopenharmony_ci	}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	/* Symbols have been adjusted */
7928c2ecf20Sopenharmony_ci	dso->adjust_symbols = 1;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	return count;
7958c2ecf20Sopenharmony_ci}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci/*
7988c2ecf20Sopenharmony_ci * Split the symbols into maps, making sure there are no overlaps, i.e. the
7998c2ecf20Sopenharmony_ci * kernel range is broken in several maps, named [kernel].N, as we don't have
8008c2ecf20Sopenharmony_ci * the original ELF section names vmlinux have.
8018c2ecf20Sopenharmony_ci */
8028c2ecf20Sopenharmony_cistatic int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
8038c2ecf20Sopenharmony_ci				struct map *initial_map)
8048c2ecf20Sopenharmony_ci{
8058c2ecf20Sopenharmony_ci	struct machine *machine;
8068c2ecf20Sopenharmony_ci	struct map *curr_map = initial_map;
8078c2ecf20Sopenharmony_ci	struct symbol *pos;
8088c2ecf20Sopenharmony_ci	int count = 0, moved = 0;
8098c2ecf20Sopenharmony_ci	struct rb_root_cached *root = &dso->symbols;
8108c2ecf20Sopenharmony_ci	struct rb_node *next = rb_first_cached(root);
8118c2ecf20Sopenharmony_ci	int kernel_range = 0;
8128c2ecf20Sopenharmony_ci	bool x86_64;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	if (!kmaps)
8158c2ecf20Sopenharmony_ci		return -1;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	machine = kmaps->machine;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	x86_64 = machine__is(machine, "x86_64");
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	while (next) {
8228c2ecf20Sopenharmony_ci		char *module;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci		pos = rb_entry(next, struct symbol, rb_node);
8258c2ecf20Sopenharmony_ci		next = rb_next(&pos->rb_node);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci		module = strchr(pos->name, '\t');
8288c2ecf20Sopenharmony_ci		if (module) {
8298c2ecf20Sopenharmony_ci			if (!symbol_conf.use_modules)
8308c2ecf20Sopenharmony_ci				goto discard_symbol;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci			*module++ = '\0';
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci			if (strcmp(curr_map->dso->short_name, module)) {
8358c2ecf20Sopenharmony_ci				if (curr_map != initial_map &&
8368c2ecf20Sopenharmony_ci				    dso->kernel == DSO_SPACE__KERNEL_GUEST &&
8378c2ecf20Sopenharmony_ci				    machine__is_default_guest(machine)) {
8388c2ecf20Sopenharmony_ci					/*
8398c2ecf20Sopenharmony_ci					 * We assume all symbols of a module are
8408c2ecf20Sopenharmony_ci					 * continuous in * kallsyms, so curr_map
8418c2ecf20Sopenharmony_ci					 * points to a module and all its
8428c2ecf20Sopenharmony_ci					 * symbols are in its kmap. Mark it as
8438c2ecf20Sopenharmony_ci					 * loaded.
8448c2ecf20Sopenharmony_ci					 */
8458c2ecf20Sopenharmony_ci					dso__set_loaded(curr_map->dso);
8468c2ecf20Sopenharmony_ci				}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci				curr_map = maps__find_by_name(kmaps, module);
8498c2ecf20Sopenharmony_ci				if (curr_map == NULL) {
8508c2ecf20Sopenharmony_ci					pr_debug("%s/proc/{kallsyms,modules} "
8518c2ecf20Sopenharmony_ci					         "inconsistency while looking "
8528c2ecf20Sopenharmony_ci						 "for \"%s\" module!\n",
8538c2ecf20Sopenharmony_ci						 machine->root_dir, module);
8548c2ecf20Sopenharmony_ci					curr_map = initial_map;
8558c2ecf20Sopenharmony_ci					goto discard_symbol;
8568c2ecf20Sopenharmony_ci				}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci				if (curr_map->dso->loaded &&
8598c2ecf20Sopenharmony_ci				    !machine__is_default_guest(machine))
8608c2ecf20Sopenharmony_ci					goto discard_symbol;
8618c2ecf20Sopenharmony_ci			}
8628c2ecf20Sopenharmony_ci			/*
8638c2ecf20Sopenharmony_ci			 * So that we look just like we get from .ko files,
8648c2ecf20Sopenharmony_ci			 * i.e. not prelinked, relative to initial_map->start.
8658c2ecf20Sopenharmony_ci			 */
8668c2ecf20Sopenharmony_ci			pos->start = curr_map->map_ip(curr_map, pos->start);
8678c2ecf20Sopenharmony_ci			pos->end   = curr_map->map_ip(curr_map, pos->end);
8688c2ecf20Sopenharmony_ci		} else if (x86_64 && is_entry_trampoline(pos->name)) {
8698c2ecf20Sopenharmony_ci			/*
8708c2ecf20Sopenharmony_ci			 * These symbols are not needed anymore since the
8718c2ecf20Sopenharmony_ci			 * trampoline maps refer to the text section and it's
8728c2ecf20Sopenharmony_ci			 * symbols instead. Avoid having to deal with
8738c2ecf20Sopenharmony_ci			 * relocations, and the assumption that the first symbol
8748c2ecf20Sopenharmony_ci			 * is the start of kernel text, by simply removing the
8758c2ecf20Sopenharmony_ci			 * symbols at this point.
8768c2ecf20Sopenharmony_ci			 */
8778c2ecf20Sopenharmony_ci			goto discard_symbol;
8788c2ecf20Sopenharmony_ci		} else if (curr_map != initial_map) {
8798c2ecf20Sopenharmony_ci			char dso_name[PATH_MAX];
8808c2ecf20Sopenharmony_ci			struct dso *ndso;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci			if (delta) {
8838c2ecf20Sopenharmony_ci				/* Kernel was relocated at boot time */
8848c2ecf20Sopenharmony_ci				pos->start -= delta;
8858c2ecf20Sopenharmony_ci				pos->end -= delta;
8868c2ecf20Sopenharmony_ci			}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci			if (count == 0) {
8898c2ecf20Sopenharmony_ci				curr_map = initial_map;
8908c2ecf20Sopenharmony_ci				goto add_symbol;
8918c2ecf20Sopenharmony_ci			}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci			if (dso->kernel == DSO_SPACE__KERNEL_GUEST)
8948c2ecf20Sopenharmony_ci				snprintf(dso_name, sizeof(dso_name),
8958c2ecf20Sopenharmony_ci					"[guest.kernel].%d",
8968c2ecf20Sopenharmony_ci					kernel_range++);
8978c2ecf20Sopenharmony_ci			else
8988c2ecf20Sopenharmony_ci				snprintf(dso_name, sizeof(dso_name),
8998c2ecf20Sopenharmony_ci					"[kernel].%d",
9008c2ecf20Sopenharmony_ci					kernel_range++);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci			ndso = dso__new(dso_name);
9038c2ecf20Sopenharmony_ci			if (ndso == NULL)
9048c2ecf20Sopenharmony_ci				return -1;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci			ndso->kernel = dso->kernel;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci			curr_map = map__new2(pos->start, ndso);
9098c2ecf20Sopenharmony_ci			if (curr_map == NULL) {
9108c2ecf20Sopenharmony_ci				dso__put(ndso);
9118c2ecf20Sopenharmony_ci				return -1;
9128c2ecf20Sopenharmony_ci			}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
9158c2ecf20Sopenharmony_ci			maps__insert(kmaps, curr_map);
9168c2ecf20Sopenharmony_ci			++kernel_range;
9178c2ecf20Sopenharmony_ci		} else if (delta) {
9188c2ecf20Sopenharmony_ci			/* Kernel was relocated at boot time */
9198c2ecf20Sopenharmony_ci			pos->start -= delta;
9208c2ecf20Sopenharmony_ci			pos->end -= delta;
9218c2ecf20Sopenharmony_ci		}
9228c2ecf20Sopenharmony_ciadd_symbol:
9238c2ecf20Sopenharmony_ci		if (curr_map != initial_map) {
9248c2ecf20Sopenharmony_ci			rb_erase_cached(&pos->rb_node, root);
9258c2ecf20Sopenharmony_ci			symbols__insert(&curr_map->dso->symbols, pos);
9268c2ecf20Sopenharmony_ci			++moved;
9278c2ecf20Sopenharmony_ci		} else
9288c2ecf20Sopenharmony_ci			++count;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci		continue;
9318c2ecf20Sopenharmony_cidiscard_symbol:
9328c2ecf20Sopenharmony_ci		rb_erase_cached(&pos->rb_node, root);
9338c2ecf20Sopenharmony_ci		symbol__delete(pos);
9348c2ecf20Sopenharmony_ci	}
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	if (curr_map != initial_map &&
9378c2ecf20Sopenharmony_ci	    dso->kernel == DSO_SPACE__KERNEL_GUEST &&
9388c2ecf20Sopenharmony_ci	    machine__is_default_guest(kmaps->machine)) {
9398c2ecf20Sopenharmony_ci		dso__set_loaded(curr_map->dso);
9408c2ecf20Sopenharmony_ci	}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	return count + moved;
9438c2ecf20Sopenharmony_ci}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_cibool symbol__restricted_filename(const char *filename,
9468c2ecf20Sopenharmony_ci				 const char *restricted_filename)
9478c2ecf20Sopenharmony_ci{
9488c2ecf20Sopenharmony_ci	bool restricted = false;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	if (symbol_conf.kptr_restrict) {
9518c2ecf20Sopenharmony_ci		char *r = realpath(filename, NULL);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci		if (r != NULL) {
9548c2ecf20Sopenharmony_ci			restricted = strcmp(r, restricted_filename) == 0;
9558c2ecf20Sopenharmony_ci			free(r);
9568c2ecf20Sopenharmony_ci			return restricted;
9578c2ecf20Sopenharmony_ci		}
9588c2ecf20Sopenharmony_ci	}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	return restricted;
9618c2ecf20Sopenharmony_ci}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_cistruct module_info {
9648c2ecf20Sopenharmony_ci	struct rb_node rb_node;
9658c2ecf20Sopenharmony_ci	char *name;
9668c2ecf20Sopenharmony_ci	u64 start;
9678c2ecf20Sopenharmony_ci};
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_cistatic void add_module(struct module_info *mi, struct rb_root *modules)
9708c2ecf20Sopenharmony_ci{
9718c2ecf20Sopenharmony_ci	struct rb_node **p = &modules->rb_node;
9728c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
9738c2ecf20Sopenharmony_ci	struct module_info *m;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	while (*p != NULL) {
9768c2ecf20Sopenharmony_ci		parent = *p;
9778c2ecf20Sopenharmony_ci		m = rb_entry(parent, struct module_info, rb_node);
9788c2ecf20Sopenharmony_ci		if (strcmp(mi->name, m->name) < 0)
9798c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
9808c2ecf20Sopenharmony_ci		else
9818c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
9828c2ecf20Sopenharmony_ci	}
9838c2ecf20Sopenharmony_ci	rb_link_node(&mi->rb_node, parent, p);
9848c2ecf20Sopenharmony_ci	rb_insert_color(&mi->rb_node, modules);
9858c2ecf20Sopenharmony_ci}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_cistatic void delete_modules(struct rb_root *modules)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	struct module_info *mi;
9908c2ecf20Sopenharmony_ci	struct rb_node *next = rb_first(modules);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	while (next) {
9938c2ecf20Sopenharmony_ci		mi = rb_entry(next, struct module_info, rb_node);
9948c2ecf20Sopenharmony_ci		next = rb_next(&mi->rb_node);
9958c2ecf20Sopenharmony_ci		rb_erase(&mi->rb_node, modules);
9968c2ecf20Sopenharmony_ci		zfree(&mi->name);
9978c2ecf20Sopenharmony_ci		free(mi);
9988c2ecf20Sopenharmony_ci	}
9998c2ecf20Sopenharmony_ci}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_cistatic struct module_info *find_module(const char *name,
10028c2ecf20Sopenharmony_ci				       struct rb_root *modules)
10038c2ecf20Sopenharmony_ci{
10048c2ecf20Sopenharmony_ci	struct rb_node *n = modules->rb_node;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	while (n) {
10078c2ecf20Sopenharmony_ci		struct module_info *m;
10088c2ecf20Sopenharmony_ci		int cmp;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci		m = rb_entry(n, struct module_info, rb_node);
10118c2ecf20Sopenharmony_ci		cmp = strcmp(name, m->name);
10128c2ecf20Sopenharmony_ci		if (cmp < 0)
10138c2ecf20Sopenharmony_ci			n = n->rb_left;
10148c2ecf20Sopenharmony_ci		else if (cmp > 0)
10158c2ecf20Sopenharmony_ci			n = n->rb_right;
10168c2ecf20Sopenharmony_ci		else
10178c2ecf20Sopenharmony_ci			return m;
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	return NULL;
10218c2ecf20Sopenharmony_ci}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_cistatic int __read_proc_modules(void *arg, const char *name, u64 start,
10248c2ecf20Sopenharmony_ci			       u64 size __maybe_unused)
10258c2ecf20Sopenharmony_ci{
10268c2ecf20Sopenharmony_ci	struct rb_root *modules = arg;
10278c2ecf20Sopenharmony_ci	struct module_info *mi;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	mi = zalloc(sizeof(struct module_info));
10308c2ecf20Sopenharmony_ci	if (!mi)
10318c2ecf20Sopenharmony_ci		return -ENOMEM;
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	mi->name = strdup(name);
10348c2ecf20Sopenharmony_ci	mi->start = start;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	if (!mi->name) {
10378c2ecf20Sopenharmony_ci		free(mi);
10388c2ecf20Sopenharmony_ci		return -ENOMEM;
10398c2ecf20Sopenharmony_ci	}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	add_module(mi, modules);
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	return 0;
10448c2ecf20Sopenharmony_ci}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_cistatic int read_proc_modules(const char *filename, struct rb_root *modules)
10478c2ecf20Sopenharmony_ci{
10488c2ecf20Sopenharmony_ci	if (symbol__restricted_filename(filename, "/proc/modules"))
10498c2ecf20Sopenharmony_ci		return -1;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	if (modules__parse(filename, modules, __read_proc_modules)) {
10528c2ecf20Sopenharmony_ci		delete_modules(modules);
10538c2ecf20Sopenharmony_ci		return -1;
10548c2ecf20Sopenharmony_ci	}
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	return 0;
10578c2ecf20Sopenharmony_ci}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ciint compare_proc_modules(const char *from, const char *to)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	struct rb_root from_modules = RB_ROOT;
10628c2ecf20Sopenharmony_ci	struct rb_root to_modules = RB_ROOT;
10638c2ecf20Sopenharmony_ci	struct rb_node *from_node, *to_node;
10648c2ecf20Sopenharmony_ci	struct module_info *from_m, *to_m;
10658c2ecf20Sopenharmony_ci	int ret = -1;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (read_proc_modules(from, &from_modules))
10688c2ecf20Sopenharmony_ci		return -1;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (read_proc_modules(to, &to_modules))
10718c2ecf20Sopenharmony_ci		goto out_delete_from;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	from_node = rb_first(&from_modules);
10748c2ecf20Sopenharmony_ci	to_node = rb_first(&to_modules);
10758c2ecf20Sopenharmony_ci	while (from_node) {
10768c2ecf20Sopenharmony_ci		if (!to_node)
10778c2ecf20Sopenharmony_ci			break;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci		from_m = rb_entry(from_node, struct module_info, rb_node);
10808c2ecf20Sopenharmony_ci		to_m = rb_entry(to_node, struct module_info, rb_node);
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci		if (from_m->start != to_m->start ||
10838c2ecf20Sopenharmony_ci		    strcmp(from_m->name, to_m->name))
10848c2ecf20Sopenharmony_ci			break;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci		from_node = rb_next(from_node);
10878c2ecf20Sopenharmony_ci		to_node = rb_next(to_node);
10888c2ecf20Sopenharmony_ci	}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	if (!from_node && !to_node)
10918c2ecf20Sopenharmony_ci		ret = 0;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	delete_modules(&to_modules);
10948c2ecf20Sopenharmony_ciout_delete_from:
10958c2ecf20Sopenharmony_ci	delete_modules(&from_modules);
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	return ret;
10988c2ecf20Sopenharmony_ci}
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_cistatic int do_validate_kcore_modules(const char *filename, struct maps *kmaps)
11018c2ecf20Sopenharmony_ci{
11028c2ecf20Sopenharmony_ci	struct rb_root modules = RB_ROOT;
11038c2ecf20Sopenharmony_ci	struct map *old_map;
11048c2ecf20Sopenharmony_ci	int err;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	err = read_proc_modules(filename, &modules);
11078c2ecf20Sopenharmony_ci	if (err)
11088c2ecf20Sopenharmony_ci		return err;
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	maps__for_each_entry(kmaps, old_map) {
11118c2ecf20Sopenharmony_ci		struct module_info *mi;
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci		if (!__map__is_kmodule(old_map)) {
11148c2ecf20Sopenharmony_ci			continue;
11158c2ecf20Sopenharmony_ci		}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci		/* Module must be in memory at the same address */
11188c2ecf20Sopenharmony_ci		mi = find_module(old_map->dso->short_name, &modules);
11198c2ecf20Sopenharmony_ci		if (!mi || mi->start != old_map->start) {
11208c2ecf20Sopenharmony_ci			err = -EINVAL;
11218c2ecf20Sopenharmony_ci			goto out;
11228c2ecf20Sopenharmony_ci		}
11238c2ecf20Sopenharmony_ci	}
11248c2ecf20Sopenharmony_ciout:
11258c2ecf20Sopenharmony_ci	delete_modules(&modules);
11268c2ecf20Sopenharmony_ci	return err;
11278c2ecf20Sopenharmony_ci}
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci/*
11308c2ecf20Sopenharmony_ci * If kallsyms is referenced by name then we look for filename in the same
11318c2ecf20Sopenharmony_ci * directory.
11328c2ecf20Sopenharmony_ci */
11338c2ecf20Sopenharmony_cistatic bool filename_from_kallsyms_filename(char *filename,
11348c2ecf20Sopenharmony_ci					    const char *base_name,
11358c2ecf20Sopenharmony_ci					    const char *kallsyms_filename)
11368c2ecf20Sopenharmony_ci{
11378c2ecf20Sopenharmony_ci	char *name;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	strcpy(filename, kallsyms_filename);
11408c2ecf20Sopenharmony_ci	name = strrchr(filename, '/');
11418c2ecf20Sopenharmony_ci	if (!name)
11428c2ecf20Sopenharmony_ci		return false;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	name += 1;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	if (!strcmp(name, "kallsyms")) {
11478c2ecf20Sopenharmony_ci		strcpy(name, base_name);
11488c2ecf20Sopenharmony_ci		return true;
11498c2ecf20Sopenharmony_ci	}
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	return false;
11528c2ecf20Sopenharmony_ci}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_cistatic int validate_kcore_modules(const char *kallsyms_filename,
11558c2ecf20Sopenharmony_ci				  struct map *map)
11568c2ecf20Sopenharmony_ci{
11578c2ecf20Sopenharmony_ci	struct maps *kmaps = map__kmaps(map);
11588c2ecf20Sopenharmony_ci	char modules_filename[PATH_MAX];
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	if (!kmaps)
11618c2ecf20Sopenharmony_ci		return -EINVAL;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	if (!filename_from_kallsyms_filename(modules_filename, "modules",
11648c2ecf20Sopenharmony_ci					     kallsyms_filename))
11658c2ecf20Sopenharmony_ci		return -EINVAL;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	if (do_validate_kcore_modules(modules_filename, kmaps))
11688c2ecf20Sopenharmony_ci		return -EINVAL;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	return 0;
11718c2ecf20Sopenharmony_ci}
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_cistatic int validate_kcore_addresses(const char *kallsyms_filename,
11748c2ecf20Sopenharmony_ci				    struct map *map)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	struct kmap *kmap = map__kmap(map);
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	if (!kmap)
11798c2ecf20Sopenharmony_ci		return -EINVAL;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
11828c2ecf20Sopenharmony_ci		u64 start;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci		if (kallsyms__get_function_start(kallsyms_filename,
11858c2ecf20Sopenharmony_ci						 kmap->ref_reloc_sym->name, &start))
11868c2ecf20Sopenharmony_ci			return -ENOENT;
11878c2ecf20Sopenharmony_ci		if (start != kmap->ref_reloc_sym->addr)
11888c2ecf20Sopenharmony_ci			return -EINVAL;
11898c2ecf20Sopenharmony_ci	}
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	return validate_kcore_modules(kallsyms_filename, map);
11928c2ecf20Sopenharmony_ci}
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_cistruct kcore_mapfn_data {
11958c2ecf20Sopenharmony_ci	struct dso *dso;
11968c2ecf20Sopenharmony_ci	struct list_head maps;
11978c2ecf20Sopenharmony_ci};
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_cistatic int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
12008c2ecf20Sopenharmony_ci{
12018c2ecf20Sopenharmony_ci	struct kcore_mapfn_data *md = data;
12028c2ecf20Sopenharmony_ci	struct map *map;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	map = map__new2(start, md->dso);
12058c2ecf20Sopenharmony_ci	if (map == NULL)
12068c2ecf20Sopenharmony_ci		return -ENOMEM;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	map->end = map->start + len;
12098c2ecf20Sopenharmony_ci	map->pgoff = pgoff;
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	list_add(&map->node, &md->maps);
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	return 0;
12148c2ecf20Sopenharmony_ci}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci/*
12178c2ecf20Sopenharmony_ci * Merges map into maps by splitting the new map within the existing map
12188c2ecf20Sopenharmony_ci * regions.
12198c2ecf20Sopenharmony_ci */
12208c2ecf20Sopenharmony_ciint maps__merge_in(struct maps *kmaps, struct map *new_map)
12218c2ecf20Sopenharmony_ci{
12228c2ecf20Sopenharmony_ci	struct map *old_map;
12238c2ecf20Sopenharmony_ci	LIST_HEAD(merged);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	maps__for_each_entry(kmaps, old_map) {
12268c2ecf20Sopenharmony_ci		/* no overload with this one */
12278c2ecf20Sopenharmony_ci		if (new_map->end < old_map->start ||
12288c2ecf20Sopenharmony_ci		    new_map->start >= old_map->end)
12298c2ecf20Sopenharmony_ci			continue;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci		if (new_map->start < old_map->start) {
12328c2ecf20Sopenharmony_ci			/*
12338c2ecf20Sopenharmony_ci			 * |new......
12348c2ecf20Sopenharmony_ci			 *       |old....
12358c2ecf20Sopenharmony_ci			 */
12368c2ecf20Sopenharmony_ci			if (new_map->end < old_map->end) {
12378c2ecf20Sopenharmony_ci				/*
12388c2ecf20Sopenharmony_ci				 * |new......|     -> |new..|
12398c2ecf20Sopenharmony_ci				 *       |old....| ->       |old....|
12408c2ecf20Sopenharmony_ci				 */
12418c2ecf20Sopenharmony_ci				new_map->end = old_map->start;
12428c2ecf20Sopenharmony_ci			} else {
12438c2ecf20Sopenharmony_ci				/*
12448c2ecf20Sopenharmony_ci				 * |new.............| -> |new..|       |new..|
12458c2ecf20Sopenharmony_ci				 *       |old....|    ->       |old....|
12468c2ecf20Sopenharmony_ci				 */
12478c2ecf20Sopenharmony_ci				struct map *m = map__clone(new_map);
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci				if (!m)
12508c2ecf20Sopenharmony_ci					return -ENOMEM;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci				m->end = old_map->start;
12538c2ecf20Sopenharmony_ci				list_add_tail(&m->node, &merged);
12548c2ecf20Sopenharmony_ci				new_map->pgoff += old_map->end - new_map->start;
12558c2ecf20Sopenharmony_ci				new_map->start = old_map->end;
12568c2ecf20Sopenharmony_ci			}
12578c2ecf20Sopenharmony_ci		} else {
12588c2ecf20Sopenharmony_ci			/*
12598c2ecf20Sopenharmony_ci			 *      |new......
12608c2ecf20Sopenharmony_ci			 * |old....
12618c2ecf20Sopenharmony_ci			 */
12628c2ecf20Sopenharmony_ci			if (new_map->end < old_map->end) {
12638c2ecf20Sopenharmony_ci				/*
12648c2ecf20Sopenharmony_ci				 *      |new..|   -> x
12658c2ecf20Sopenharmony_ci				 * |old.........| -> |old.........|
12668c2ecf20Sopenharmony_ci				 */
12678c2ecf20Sopenharmony_ci				map__put(new_map);
12688c2ecf20Sopenharmony_ci				new_map = NULL;
12698c2ecf20Sopenharmony_ci				break;
12708c2ecf20Sopenharmony_ci			} else {
12718c2ecf20Sopenharmony_ci				/*
12728c2ecf20Sopenharmony_ci				 *      |new......| ->         |new...|
12738c2ecf20Sopenharmony_ci				 * |old....|        -> |old....|
12748c2ecf20Sopenharmony_ci				 */
12758c2ecf20Sopenharmony_ci				new_map->pgoff += old_map->end - new_map->start;
12768c2ecf20Sopenharmony_ci				new_map->start = old_map->end;
12778c2ecf20Sopenharmony_ci			}
12788c2ecf20Sopenharmony_ci		}
12798c2ecf20Sopenharmony_ci	}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	while (!list_empty(&merged)) {
12828c2ecf20Sopenharmony_ci		old_map = list_entry(merged.next, struct map, node);
12838c2ecf20Sopenharmony_ci		list_del_init(&old_map->node);
12848c2ecf20Sopenharmony_ci		maps__insert(kmaps, old_map);
12858c2ecf20Sopenharmony_ci		map__put(old_map);
12868c2ecf20Sopenharmony_ci	}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	if (new_map) {
12898c2ecf20Sopenharmony_ci		maps__insert(kmaps, new_map);
12908c2ecf20Sopenharmony_ci		map__put(new_map);
12918c2ecf20Sopenharmony_ci	}
12928c2ecf20Sopenharmony_ci	return 0;
12938c2ecf20Sopenharmony_ci}
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_cistatic int dso__load_kcore(struct dso *dso, struct map *map,
12968c2ecf20Sopenharmony_ci			   const char *kallsyms_filename)
12978c2ecf20Sopenharmony_ci{
12988c2ecf20Sopenharmony_ci	struct maps *kmaps = map__kmaps(map);
12998c2ecf20Sopenharmony_ci	struct kcore_mapfn_data md;
13008c2ecf20Sopenharmony_ci	struct map *old_map, *new_map, *replacement_map = NULL, *next;
13018c2ecf20Sopenharmony_ci	struct machine *machine;
13028c2ecf20Sopenharmony_ci	bool is_64_bit;
13038c2ecf20Sopenharmony_ci	int err, fd;
13048c2ecf20Sopenharmony_ci	char kcore_filename[PATH_MAX];
13058c2ecf20Sopenharmony_ci	u64 stext;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	if (!kmaps)
13088c2ecf20Sopenharmony_ci		return -EINVAL;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	machine = kmaps->machine;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	/* This function requires that the map is the kernel map */
13138c2ecf20Sopenharmony_ci	if (!__map__is_kernel(map))
13148c2ecf20Sopenharmony_ci		return -EINVAL;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
13178c2ecf20Sopenharmony_ci					     kallsyms_filename))
13188c2ecf20Sopenharmony_ci		return -EINVAL;
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	/* Modules and kernel must be present at their original addresses */
13218c2ecf20Sopenharmony_ci	if (validate_kcore_addresses(kallsyms_filename, map))
13228c2ecf20Sopenharmony_ci		return -EINVAL;
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	md.dso = dso;
13258c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&md.maps);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	fd = open(kcore_filename, O_RDONLY);
13288c2ecf20Sopenharmony_ci	if (fd < 0) {
13298c2ecf20Sopenharmony_ci		pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n",
13308c2ecf20Sopenharmony_ci			 kcore_filename);
13318c2ecf20Sopenharmony_ci		return -EINVAL;
13328c2ecf20Sopenharmony_ci	}
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	/* Read new maps into temporary lists */
13358c2ecf20Sopenharmony_ci	err = file__read_maps(fd, map->prot & PROT_EXEC, kcore_mapfn, &md,
13368c2ecf20Sopenharmony_ci			      &is_64_bit);
13378c2ecf20Sopenharmony_ci	if (err)
13388c2ecf20Sopenharmony_ci		goto out_err;
13398c2ecf20Sopenharmony_ci	dso->is_64_bit = is_64_bit;
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	if (list_empty(&md.maps)) {
13428c2ecf20Sopenharmony_ci		err = -EINVAL;
13438c2ecf20Sopenharmony_ci		goto out_err;
13448c2ecf20Sopenharmony_ci	}
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci	/* Remove old maps */
13478c2ecf20Sopenharmony_ci	maps__for_each_entry_safe(kmaps, old_map, next) {
13488c2ecf20Sopenharmony_ci		/*
13498c2ecf20Sopenharmony_ci		 * We need to preserve eBPF maps even if they are
13508c2ecf20Sopenharmony_ci		 * covered by kcore, because we need to access
13518c2ecf20Sopenharmony_ci		 * eBPF dso for source data.
13528c2ecf20Sopenharmony_ci		 */
13538c2ecf20Sopenharmony_ci		if (old_map != map && !__map__is_bpf_prog(old_map))
13548c2ecf20Sopenharmony_ci			maps__remove(kmaps, old_map);
13558c2ecf20Sopenharmony_ci	}
13568c2ecf20Sopenharmony_ci	machine->trampolines_mapped = false;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	/* Find the kernel map using the '_stext' symbol */
13598c2ecf20Sopenharmony_ci	if (!kallsyms__get_function_start(kallsyms_filename, "_stext", &stext)) {
13608c2ecf20Sopenharmony_ci		list_for_each_entry(new_map, &md.maps, node) {
13618c2ecf20Sopenharmony_ci			if (stext >= new_map->start && stext < new_map->end) {
13628c2ecf20Sopenharmony_ci				replacement_map = new_map;
13638c2ecf20Sopenharmony_ci				break;
13648c2ecf20Sopenharmony_ci			}
13658c2ecf20Sopenharmony_ci		}
13668c2ecf20Sopenharmony_ci	}
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	if (!replacement_map)
13698c2ecf20Sopenharmony_ci		replacement_map = list_entry(md.maps.next, struct map, node);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	/* Add new maps */
13728c2ecf20Sopenharmony_ci	while (!list_empty(&md.maps)) {
13738c2ecf20Sopenharmony_ci		new_map = list_entry(md.maps.next, struct map, node);
13748c2ecf20Sopenharmony_ci		list_del_init(&new_map->node);
13758c2ecf20Sopenharmony_ci		if (new_map == replacement_map) {
13768c2ecf20Sopenharmony_ci			map->start	= new_map->start;
13778c2ecf20Sopenharmony_ci			map->end	= new_map->end;
13788c2ecf20Sopenharmony_ci			map->pgoff	= new_map->pgoff;
13798c2ecf20Sopenharmony_ci			map->map_ip	= new_map->map_ip;
13808c2ecf20Sopenharmony_ci			map->unmap_ip	= new_map->unmap_ip;
13818c2ecf20Sopenharmony_ci			/* Ensure maps are correctly ordered */
13828c2ecf20Sopenharmony_ci			map__get(map);
13838c2ecf20Sopenharmony_ci			maps__remove(kmaps, map);
13848c2ecf20Sopenharmony_ci			maps__insert(kmaps, map);
13858c2ecf20Sopenharmony_ci			map__put(map);
13868c2ecf20Sopenharmony_ci			map__put(new_map);
13878c2ecf20Sopenharmony_ci		} else {
13888c2ecf20Sopenharmony_ci			/*
13898c2ecf20Sopenharmony_ci			 * Merge kcore map into existing maps,
13908c2ecf20Sopenharmony_ci			 * and ensure that current maps (eBPF)
13918c2ecf20Sopenharmony_ci			 * stay intact.
13928c2ecf20Sopenharmony_ci			 */
13938c2ecf20Sopenharmony_ci			if (maps__merge_in(kmaps, new_map))
13948c2ecf20Sopenharmony_ci				goto out_err;
13958c2ecf20Sopenharmony_ci		}
13968c2ecf20Sopenharmony_ci	}
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	if (machine__is(machine, "x86_64")) {
13998c2ecf20Sopenharmony_ci		u64 addr;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci		/*
14028c2ecf20Sopenharmony_ci		 * If one of the corresponding symbols is there, assume the
14038c2ecf20Sopenharmony_ci		 * entry trampoline maps are too.
14048c2ecf20Sopenharmony_ci		 */
14058c2ecf20Sopenharmony_ci		if (!kallsyms__get_function_start(kallsyms_filename,
14068c2ecf20Sopenharmony_ci						  ENTRY_TRAMPOLINE_NAME,
14078c2ecf20Sopenharmony_ci						  &addr))
14088c2ecf20Sopenharmony_ci			machine->trampolines_mapped = true;
14098c2ecf20Sopenharmony_ci	}
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	/*
14128c2ecf20Sopenharmony_ci	 * Set the data type and long name so that kcore can be read via
14138c2ecf20Sopenharmony_ci	 * dso__data_read_addr().
14148c2ecf20Sopenharmony_ci	 */
14158c2ecf20Sopenharmony_ci	if (dso->kernel == DSO_SPACE__KERNEL_GUEST)
14168c2ecf20Sopenharmony_ci		dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
14178c2ecf20Sopenharmony_ci	else
14188c2ecf20Sopenharmony_ci		dso->binary_type = DSO_BINARY_TYPE__KCORE;
14198c2ecf20Sopenharmony_ci	dso__set_long_name(dso, strdup(kcore_filename), true);
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	close(fd);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	if (map->prot & PROT_EXEC)
14248c2ecf20Sopenharmony_ci		pr_debug("Using %s for kernel object code\n", kcore_filename);
14258c2ecf20Sopenharmony_ci	else
14268c2ecf20Sopenharmony_ci		pr_debug("Using %s for kernel data\n", kcore_filename);
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	return 0;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ciout_err:
14318c2ecf20Sopenharmony_ci	while (!list_empty(&md.maps)) {
14328c2ecf20Sopenharmony_ci		map = list_entry(md.maps.next, struct map, node);
14338c2ecf20Sopenharmony_ci		list_del_init(&map->node);
14348c2ecf20Sopenharmony_ci		map__put(map);
14358c2ecf20Sopenharmony_ci	}
14368c2ecf20Sopenharmony_ci	close(fd);
14378c2ecf20Sopenharmony_ci	return -EINVAL;
14388c2ecf20Sopenharmony_ci}
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci/*
14418c2ecf20Sopenharmony_ci * If the kernel is relocated at boot time, kallsyms won't match.  Compute the
14428c2ecf20Sopenharmony_ci * delta based on the relocation reference symbol.
14438c2ecf20Sopenharmony_ci */
14448c2ecf20Sopenharmony_cistatic int kallsyms__delta(struct kmap *kmap, const char *filename, u64 *delta)
14458c2ecf20Sopenharmony_ci{
14468c2ecf20Sopenharmony_ci	u64 addr;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
14498c2ecf20Sopenharmony_ci		return 0;
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	if (kallsyms__get_function_start(filename, kmap->ref_reloc_sym->name, &addr))
14528c2ecf20Sopenharmony_ci		return -1;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	*delta = addr - kmap->ref_reloc_sym->addr;
14558c2ecf20Sopenharmony_ci	return 0;
14568c2ecf20Sopenharmony_ci}
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ciint __dso__load_kallsyms(struct dso *dso, const char *filename,
14598c2ecf20Sopenharmony_ci			 struct map *map, bool no_kcore)
14608c2ecf20Sopenharmony_ci{
14618c2ecf20Sopenharmony_ci	struct kmap *kmap = map__kmap(map);
14628c2ecf20Sopenharmony_ci	u64 delta = 0;
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
14658c2ecf20Sopenharmony_ci		return -1;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	if (!kmap || !kmap->kmaps)
14688c2ecf20Sopenharmony_ci		return -1;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	if (dso__load_all_kallsyms(dso, filename) < 0)
14718c2ecf20Sopenharmony_ci		return -1;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	if (kallsyms__delta(kmap, filename, &delta))
14748c2ecf20Sopenharmony_ci		return -1;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	symbols__fixup_end(&dso->symbols, true);
14778c2ecf20Sopenharmony_ci	symbols__fixup_duplicate(&dso->symbols);
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	if (dso->kernel == DSO_SPACE__KERNEL_GUEST)
14808c2ecf20Sopenharmony_ci		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
14818c2ecf20Sopenharmony_ci	else
14828c2ecf20Sopenharmony_ci		dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	if (!no_kcore && !dso__load_kcore(dso, map, filename))
14858c2ecf20Sopenharmony_ci		return maps__split_kallsyms_for_kcore(kmap->kmaps, dso);
14868c2ecf20Sopenharmony_ci	else
14878c2ecf20Sopenharmony_ci		return maps__split_kallsyms(kmap->kmaps, dso, delta, map);
14888c2ecf20Sopenharmony_ci}
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ciint dso__load_kallsyms(struct dso *dso, const char *filename,
14918c2ecf20Sopenharmony_ci		       struct map *map)
14928c2ecf20Sopenharmony_ci{
14938c2ecf20Sopenharmony_ci	return __dso__load_kallsyms(dso, filename, map, false);
14948c2ecf20Sopenharmony_ci}
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_cistatic int dso__load_perf_map(const char *map_path, struct dso *dso)
14978c2ecf20Sopenharmony_ci{
14988c2ecf20Sopenharmony_ci	char *line = NULL;
14998c2ecf20Sopenharmony_ci	size_t n;
15008c2ecf20Sopenharmony_ci	FILE *file;
15018c2ecf20Sopenharmony_ci	int nr_syms = 0;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	file = fopen(map_path, "r");
15048c2ecf20Sopenharmony_ci	if (file == NULL)
15058c2ecf20Sopenharmony_ci		goto out_failure;
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	while (!feof(file)) {
15088c2ecf20Sopenharmony_ci		u64 start, size;
15098c2ecf20Sopenharmony_ci		struct symbol *sym;
15108c2ecf20Sopenharmony_ci		int line_len, len;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci		line_len = getline(&line, &n, file);
15138c2ecf20Sopenharmony_ci		if (line_len < 0)
15148c2ecf20Sopenharmony_ci			break;
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci		if (!line)
15178c2ecf20Sopenharmony_ci			goto out_failure;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci		line[--line_len] = '\0'; /* \n */
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci		len = hex2u64(line, &start);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci		len++;
15248c2ecf20Sopenharmony_ci		if (len + 2 >= line_len)
15258c2ecf20Sopenharmony_ci			continue;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci		len += hex2u64(line + len, &size);
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci		len++;
15308c2ecf20Sopenharmony_ci		if (len + 2 >= line_len)
15318c2ecf20Sopenharmony_ci			continue;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci		sym = symbol__new(start, size, STB_GLOBAL, STT_FUNC, line + len);
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci		if (sym == NULL)
15368c2ecf20Sopenharmony_ci			goto out_delete_line;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci		symbols__insert(&dso->symbols, sym);
15398c2ecf20Sopenharmony_ci		nr_syms++;
15408c2ecf20Sopenharmony_ci	}
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	free(line);
15438c2ecf20Sopenharmony_ci	fclose(file);
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	return nr_syms;
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ciout_delete_line:
15488c2ecf20Sopenharmony_ci	free(line);
15498c2ecf20Sopenharmony_ciout_failure:
15508c2ecf20Sopenharmony_ci	return -1;
15518c2ecf20Sopenharmony_ci}
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci#ifdef HAVE_LIBBFD_SUPPORT
15548c2ecf20Sopenharmony_ci#define PACKAGE 'perf'
15558c2ecf20Sopenharmony_ci#include <bfd.h>
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_cistatic int bfd_symbols__cmpvalue(const void *a, const void *b)
15588c2ecf20Sopenharmony_ci{
15598c2ecf20Sopenharmony_ci	const asymbol *as = *(const asymbol **)a, *bs = *(const asymbol **)b;
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	if (bfd_asymbol_value(as) != bfd_asymbol_value(bs))
15628c2ecf20Sopenharmony_ci		return bfd_asymbol_value(as) - bfd_asymbol_value(bs);
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	return bfd_asymbol_name(as)[0] - bfd_asymbol_name(bs)[0];
15658c2ecf20Sopenharmony_ci}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_cistatic int bfd2elf_binding(asymbol *symbol)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	if (symbol->flags & BSF_WEAK)
15708c2ecf20Sopenharmony_ci		return STB_WEAK;
15718c2ecf20Sopenharmony_ci	if (symbol->flags & BSF_GLOBAL)
15728c2ecf20Sopenharmony_ci		return STB_GLOBAL;
15738c2ecf20Sopenharmony_ci	if (symbol->flags & BSF_LOCAL)
15748c2ecf20Sopenharmony_ci		return STB_LOCAL;
15758c2ecf20Sopenharmony_ci	return -1;
15768c2ecf20Sopenharmony_ci}
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ciint dso__load_bfd_symbols(struct dso *dso, const char *debugfile)
15798c2ecf20Sopenharmony_ci{
15808c2ecf20Sopenharmony_ci	int err = -1;
15818c2ecf20Sopenharmony_ci	long symbols_size, symbols_count, i;
15828c2ecf20Sopenharmony_ci	asection *section;
15838c2ecf20Sopenharmony_ci	asymbol **symbols, *sym;
15848c2ecf20Sopenharmony_ci	struct symbol *symbol;
15858c2ecf20Sopenharmony_ci	bfd *abfd;
15868c2ecf20Sopenharmony_ci	u64 start, len;
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	abfd = bfd_openr(dso->long_name, NULL);
15898c2ecf20Sopenharmony_ci	if (!abfd)
15908c2ecf20Sopenharmony_ci		return -1;
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	if (!bfd_check_format(abfd, bfd_object)) {
15938c2ecf20Sopenharmony_ci		pr_debug2("%s: cannot read %s bfd file.\n", __func__,
15948c2ecf20Sopenharmony_ci			  dso->long_name);
15958c2ecf20Sopenharmony_ci		goto out_close;
15968c2ecf20Sopenharmony_ci	}
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	if (bfd_get_flavour(abfd) == bfd_target_elf_flavour)
15998c2ecf20Sopenharmony_ci		goto out_close;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	section = bfd_get_section_by_name(abfd, ".text");
16028c2ecf20Sopenharmony_ci	if (section)
16038c2ecf20Sopenharmony_ci		dso->text_offset = section->vma - section->filepos;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	bfd_close(abfd);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	abfd = bfd_openr(debugfile, NULL);
16088c2ecf20Sopenharmony_ci	if (!abfd)
16098c2ecf20Sopenharmony_ci		return -1;
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	if (!bfd_check_format(abfd, bfd_object)) {
16128c2ecf20Sopenharmony_ci		pr_debug2("%s: cannot read %s bfd file.\n", __func__,
16138c2ecf20Sopenharmony_ci			  debugfile);
16148c2ecf20Sopenharmony_ci		goto out_close;
16158c2ecf20Sopenharmony_ci	}
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	if (bfd_get_flavour(abfd) == bfd_target_elf_flavour)
16188c2ecf20Sopenharmony_ci		goto out_close;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	symbols_size = bfd_get_symtab_upper_bound(abfd);
16218c2ecf20Sopenharmony_ci	if (symbols_size == 0) {
16228c2ecf20Sopenharmony_ci		bfd_close(abfd);
16238c2ecf20Sopenharmony_ci		return 0;
16248c2ecf20Sopenharmony_ci	}
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	if (symbols_size < 0)
16278c2ecf20Sopenharmony_ci		goto out_close;
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	symbols = malloc(symbols_size);
16308c2ecf20Sopenharmony_ci	if (!symbols)
16318c2ecf20Sopenharmony_ci		goto out_close;
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	symbols_count = bfd_canonicalize_symtab(abfd, symbols);
16348c2ecf20Sopenharmony_ci	if (symbols_count < 0)
16358c2ecf20Sopenharmony_ci		goto out_free;
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	qsort(symbols, symbols_count, sizeof(asymbol *), bfd_symbols__cmpvalue);
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci#ifdef bfd_get_section
16408c2ecf20Sopenharmony_ci#define bfd_asymbol_section bfd_get_section
16418c2ecf20Sopenharmony_ci#endif
16428c2ecf20Sopenharmony_ci	for (i = 0; i < symbols_count; ++i) {
16438c2ecf20Sopenharmony_ci		sym = symbols[i];
16448c2ecf20Sopenharmony_ci		section = bfd_asymbol_section(sym);
16458c2ecf20Sopenharmony_ci		if (bfd2elf_binding(sym) < 0)
16468c2ecf20Sopenharmony_ci			continue;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci		while (i + 1 < symbols_count &&
16498c2ecf20Sopenharmony_ci		       bfd_asymbol_section(symbols[i + 1]) == section &&
16508c2ecf20Sopenharmony_ci		       bfd2elf_binding(symbols[i + 1]) < 0)
16518c2ecf20Sopenharmony_ci			i++;
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci		if (i + 1 < symbols_count &&
16548c2ecf20Sopenharmony_ci		    bfd_asymbol_section(symbols[i + 1]) == section)
16558c2ecf20Sopenharmony_ci			len = symbols[i + 1]->value - sym->value;
16568c2ecf20Sopenharmony_ci		else
16578c2ecf20Sopenharmony_ci			len = section->size - sym->value;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci		start = bfd_asymbol_value(sym) - dso->text_offset;
16608c2ecf20Sopenharmony_ci		symbol = symbol__new(start, len, bfd2elf_binding(sym), STT_FUNC,
16618c2ecf20Sopenharmony_ci				     bfd_asymbol_name(sym));
16628c2ecf20Sopenharmony_ci		if (!symbol)
16638c2ecf20Sopenharmony_ci			goto out_free;
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_ci		symbols__insert(&dso->symbols, symbol);
16668c2ecf20Sopenharmony_ci	}
16678c2ecf20Sopenharmony_ci#ifdef bfd_get_section
16688c2ecf20Sopenharmony_ci#undef bfd_asymbol_section
16698c2ecf20Sopenharmony_ci#endif
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	symbols__fixup_end(&dso->symbols, false);
16728c2ecf20Sopenharmony_ci	symbols__fixup_duplicate(&dso->symbols);
16738c2ecf20Sopenharmony_ci	dso->adjust_symbols = 1;
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	err = 0;
16768c2ecf20Sopenharmony_ciout_free:
16778c2ecf20Sopenharmony_ci	free(symbols);
16788c2ecf20Sopenharmony_ciout_close:
16798c2ecf20Sopenharmony_ci	bfd_close(abfd);
16808c2ecf20Sopenharmony_ci	return err;
16818c2ecf20Sopenharmony_ci}
16828c2ecf20Sopenharmony_ci#endif
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_cistatic bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
16858c2ecf20Sopenharmony_ci					   enum dso_binary_type type)
16868c2ecf20Sopenharmony_ci{
16878c2ecf20Sopenharmony_ci	switch (type) {
16888c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__JAVA_JIT:
16898c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__DEBUGLINK:
16908c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
16918c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
16928c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
16938c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO:
16948c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
16958c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
16968c2ecf20Sopenharmony_ci		return !kmod && dso->kernel == DSO_SPACE__USER;
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__KALLSYMS:
16998c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__VMLINUX:
17008c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__KCORE:
17018c2ecf20Sopenharmony_ci		return dso->kernel == DSO_SPACE__KERNEL;
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
17048c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__GUEST_VMLINUX:
17058c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__GUEST_KCORE:
17068c2ecf20Sopenharmony_ci		return dso->kernel == DSO_SPACE__KERNEL_GUEST;
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__GUEST_KMODULE:
17098c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
17108c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
17118c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
17128c2ecf20Sopenharmony_ci		/*
17138c2ecf20Sopenharmony_ci		 * kernel modules know their symtab type - it's set when
17148c2ecf20Sopenharmony_ci		 * creating a module dso in machine__addnew_module_map().
17158c2ecf20Sopenharmony_ci		 */
17168c2ecf20Sopenharmony_ci		return kmod && dso->symtab_type == type;
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__BUILD_ID_CACHE:
17198c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
17208c2ecf20Sopenharmony_ci		return true;
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__BPF_PROG_INFO:
17238c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__BPF_IMAGE:
17248c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__OOL:
17258c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__NOT_FOUND:
17268c2ecf20Sopenharmony_ci	default:
17278c2ecf20Sopenharmony_ci		return false;
17288c2ecf20Sopenharmony_ci	}
17298c2ecf20Sopenharmony_ci}
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci/* Checks for the existence of the perf-<pid>.map file in two different
17328c2ecf20Sopenharmony_ci * locations.  First, if the process is a separate mount namespace, check in
17338c2ecf20Sopenharmony_ci * that namespace using the pid of the innermost pid namespace.  If's not in a
17348c2ecf20Sopenharmony_ci * namespace, or the file can't be found there, try in the mount namespace of
17358c2ecf20Sopenharmony_ci * the tracing process using our view of its pid.
17368c2ecf20Sopenharmony_ci */
17378c2ecf20Sopenharmony_cistatic int dso__find_perf_map(char *filebuf, size_t bufsz,
17388c2ecf20Sopenharmony_ci			      struct nsinfo **nsip)
17398c2ecf20Sopenharmony_ci{
17408c2ecf20Sopenharmony_ci	struct nscookie nsc;
17418c2ecf20Sopenharmony_ci	struct nsinfo *nsi;
17428c2ecf20Sopenharmony_ci	struct nsinfo *nnsi;
17438c2ecf20Sopenharmony_ci	int rc = -1;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	nsi = *nsip;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	if (nsi->need_setns) {
17488c2ecf20Sopenharmony_ci		snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsi->nstgid);
17498c2ecf20Sopenharmony_ci		nsinfo__mountns_enter(nsi, &nsc);
17508c2ecf20Sopenharmony_ci		rc = access(filebuf, R_OK);
17518c2ecf20Sopenharmony_ci		nsinfo__mountns_exit(&nsc);
17528c2ecf20Sopenharmony_ci		if (rc == 0)
17538c2ecf20Sopenharmony_ci			return rc;
17548c2ecf20Sopenharmony_ci	}
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	nnsi = nsinfo__copy(nsi);
17578c2ecf20Sopenharmony_ci	if (nnsi) {
17588c2ecf20Sopenharmony_ci		nsinfo__put(nsi);
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci		nnsi->need_setns = false;
17618c2ecf20Sopenharmony_ci		snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nnsi->tgid);
17628c2ecf20Sopenharmony_ci		*nsip = nnsi;
17638c2ecf20Sopenharmony_ci		rc = 0;
17648c2ecf20Sopenharmony_ci	}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	return rc;
17678c2ecf20Sopenharmony_ci}
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ciint dso__load(struct dso *dso, struct map *map)
17708c2ecf20Sopenharmony_ci{
17718c2ecf20Sopenharmony_ci	char *name;
17728c2ecf20Sopenharmony_ci	int ret = -1;
17738c2ecf20Sopenharmony_ci	u_int i;
17748c2ecf20Sopenharmony_ci	struct machine *machine = NULL;
17758c2ecf20Sopenharmony_ci	char *root_dir = (char *) "";
17768c2ecf20Sopenharmony_ci	int ss_pos = 0;
17778c2ecf20Sopenharmony_ci	struct symsrc ss_[2];
17788c2ecf20Sopenharmony_ci	struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
17798c2ecf20Sopenharmony_ci	bool kmod;
17808c2ecf20Sopenharmony_ci	bool perfmap;
17818c2ecf20Sopenharmony_ci	struct build_id bid;
17828c2ecf20Sopenharmony_ci	struct nscookie nsc;
17838c2ecf20Sopenharmony_ci	char newmapname[PATH_MAX];
17848c2ecf20Sopenharmony_ci	const char *map_path = dso->long_name;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0;
17878c2ecf20Sopenharmony_ci	if (perfmap) {
17888c2ecf20Sopenharmony_ci		if (dso->nsinfo && (dso__find_perf_map(newmapname,
17898c2ecf20Sopenharmony_ci		    sizeof(newmapname), &dso->nsinfo) == 0)) {
17908c2ecf20Sopenharmony_ci			map_path = newmapname;
17918c2ecf20Sopenharmony_ci		}
17928c2ecf20Sopenharmony_ci	}
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	nsinfo__mountns_enter(dso->nsinfo, &nsc);
17958c2ecf20Sopenharmony_ci	pthread_mutex_lock(&dso->lock);
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	/* check again under the dso->lock */
17988c2ecf20Sopenharmony_ci	if (dso__loaded(dso)) {
17998c2ecf20Sopenharmony_ci		ret = 1;
18008c2ecf20Sopenharmony_ci		goto out;
18018c2ecf20Sopenharmony_ci	}
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
18048c2ecf20Sopenharmony_ci		dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
18058c2ecf20Sopenharmony_ci		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
18068c2ecf20Sopenharmony_ci		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	if (dso->kernel && !kmod) {
18098c2ecf20Sopenharmony_ci		if (dso->kernel == DSO_SPACE__KERNEL)
18108c2ecf20Sopenharmony_ci			ret = dso__load_kernel_sym(dso, map);
18118c2ecf20Sopenharmony_ci		else if (dso->kernel == DSO_SPACE__KERNEL_GUEST)
18128c2ecf20Sopenharmony_ci			ret = dso__load_guest_kernel_sym(dso, map);
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci		machine = map__kmaps(map)->machine;
18158c2ecf20Sopenharmony_ci		if (machine__is(machine, "x86_64"))
18168c2ecf20Sopenharmony_ci			machine__map_x86_64_entry_trampolines(machine, dso);
18178c2ecf20Sopenharmony_ci		goto out;
18188c2ecf20Sopenharmony_ci	}
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	dso->adjust_symbols = 0;
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	if (perfmap) {
18238c2ecf20Sopenharmony_ci		ret = dso__load_perf_map(map_path, dso);
18248c2ecf20Sopenharmony_ci		dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
18258c2ecf20Sopenharmony_ci					     DSO_BINARY_TYPE__NOT_FOUND;
18268c2ecf20Sopenharmony_ci		goto out;
18278c2ecf20Sopenharmony_ci	}
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci	if (machine)
18308c2ecf20Sopenharmony_ci		root_dir = machine->root_dir;
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	name = malloc(PATH_MAX);
18338c2ecf20Sopenharmony_ci	if (!name)
18348c2ecf20Sopenharmony_ci		goto out;
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	/*
18378c2ecf20Sopenharmony_ci	 * Read the build id if possible. This is required for
18388c2ecf20Sopenharmony_ci	 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
18398c2ecf20Sopenharmony_ci	 */
18408c2ecf20Sopenharmony_ci	if (!dso->has_build_id &&
18418c2ecf20Sopenharmony_ci	    is_regular_file(dso->long_name)) {
18428c2ecf20Sopenharmony_ci	    __symbol__join_symfs(name, PATH_MAX, dso->long_name);
18438c2ecf20Sopenharmony_ci		if (filename__read_build_id(name, &bid) > 0)
18448c2ecf20Sopenharmony_ci			dso__set_build_id(dso, &bid);
18458c2ecf20Sopenharmony_ci	}
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	/*
18488c2ecf20Sopenharmony_ci	 * Iterate over candidate debug images.
18498c2ecf20Sopenharmony_ci	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
18508c2ecf20Sopenharmony_ci	 * and/or opd section) for processing.
18518c2ecf20Sopenharmony_ci	 */
18528c2ecf20Sopenharmony_ci	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
18538c2ecf20Sopenharmony_ci		struct symsrc *ss = &ss_[ss_pos];
18548c2ecf20Sopenharmony_ci		bool next_slot = false;
18558c2ecf20Sopenharmony_ci		bool is_reg;
18568c2ecf20Sopenharmony_ci		bool nsexit;
18578c2ecf20Sopenharmony_ci		int bfdrc = -1;
18588c2ecf20Sopenharmony_ci		int sirc = -1;
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci		enum dso_binary_type symtab_type = binary_type_symtab[i];
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci		nsexit = (symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE ||
18638c2ecf20Sopenharmony_ci		    symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO);
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci		if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
18668c2ecf20Sopenharmony_ci			continue;
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci		if (dso__read_binary_type_filename(dso, symtab_type,
18698c2ecf20Sopenharmony_ci						   root_dir, name, PATH_MAX))
18708c2ecf20Sopenharmony_ci			continue;
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci		if (nsexit)
18738c2ecf20Sopenharmony_ci			nsinfo__mountns_exit(&nsc);
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci		is_reg = is_regular_file(name);
18768c2ecf20Sopenharmony_ci#ifdef HAVE_LIBBFD_SUPPORT
18778c2ecf20Sopenharmony_ci		if (is_reg)
18788c2ecf20Sopenharmony_ci			bfdrc = dso__load_bfd_symbols(dso, name);
18798c2ecf20Sopenharmony_ci#endif
18808c2ecf20Sopenharmony_ci		if (is_reg && bfdrc < 0)
18818c2ecf20Sopenharmony_ci			sirc = symsrc__init(ss, dso, name, symtab_type);
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci		if (nsexit)
18848c2ecf20Sopenharmony_ci			nsinfo__mountns_enter(dso->nsinfo, &nsc);
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci		if (bfdrc == 0) {
18878c2ecf20Sopenharmony_ci			ret = 0;
18888c2ecf20Sopenharmony_ci			break;
18898c2ecf20Sopenharmony_ci		}
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci		if (!is_reg || sirc < 0)
18928c2ecf20Sopenharmony_ci			continue;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci		if (!syms_ss && symsrc__has_symtab(ss)) {
18958c2ecf20Sopenharmony_ci			syms_ss = ss;
18968c2ecf20Sopenharmony_ci			next_slot = true;
18978c2ecf20Sopenharmony_ci			if (!dso->symsrc_filename)
18988c2ecf20Sopenharmony_ci				dso->symsrc_filename = strdup(name);
18998c2ecf20Sopenharmony_ci		}
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci		if (!runtime_ss && symsrc__possibly_runtime(ss)) {
19028c2ecf20Sopenharmony_ci			runtime_ss = ss;
19038c2ecf20Sopenharmony_ci			next_slot = true;
19048c2ecf20Sopenharmony_ci		}
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci		if (next_slot) {
19078c2ecf20Sopenharmony_ci			ss_pos++;
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci			if (syms_ss && runtime_ss)
19108c2ecf20Sopenharmony_ci				break;
19118c2ecf20Sopenharmony_ci		} else {
19128c2ecf20Sopenharmony_ci			symsrc__destroy(ss);
19138c2ecf20Sopenharmony_ci		}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	}
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	if (!runtime_ss && !syms_ss)
19188c2ecf20Sopenharmony_ci		goto out_free;
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	if (runtime_ss && !syms_ss) {
19218c2ecf20Sopenharmony_ci		syms_ss = runtime_ss;
19228c2ecf20Sopenharmony_ci	}
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	/* We'll have to hope for the best */
19258c2ecf20Sopenharmony_ci	if (!runtime_ss && syms_ss)
19268c2ecf20Sopenharmony_ci		runtime_ss = syms_ss;
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	if (syms_ss)
19298c2ecf20Sopenharmony_ci		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod);
19308c2ecf20Sopenharmony_ci	else
19318c2ecf20Sopenharmony_ci		ret = -1;
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	if (ret > 0) {
19348c2ecf20Sopenharmony_ci		int nr_plt;
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci		nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss);
19378c2ecf20Sopenharmony_ci		if (nr_plt > 0)
19388c2ecf20Sopenharmony_ci			ret += nr_plt;
19398c2ecf20Sopenharmony_ci	}
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	for (; ss_pos > 0; ss_pos--)
19428c2ecf20Sopenharmony_ci		symsrc__destroy(&ss_[ss_pos - 1]);
19438c2ecf20Sopenharmony_ciout_free:
19448c2ecf20Sopenharmony_ci	free(name);
19458c2ecf20Sopenharmony_ci	if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
19468c2ecf20Sopenharmony_ci		ret = 0;
19478c2ecf20Sopenharmony_ciout:
19488c2ecf20Sopenharmony_ci	dso__set_loaded(dso);
19498c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&dso->lock);
19508c2ecf20Sopenharmony_ci	nsinfo__mountns_exit(&nsc);
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	return ret;
19538c2ecf20Sopenharmony_ci}
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_cistatic int map__strcmp(const void *a, const void *b)
19568c2ecf20Sopenharmony_ci{
19578c2ecf20Sopenharmony_ci	const struct map *ma = *(const struct map **)a, *mb = *(const struct map **)b;
19588c2ecf20Sopenharmony_ci	return strcmp(ma->dso->short_name, mb->dso->short_name);
19598c2ecf20Sopenharmony_ci}
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_cistatic int map__strcmp_name(const void *name, const void *b)
19628c2ecf20Sopenharmony_ci{
19638c2ecf20Sopenharmony_ci	const struct map *map = *(const struct map **)b;
19648c2ecf20Sopenharmony_ci	return strcmp(name, map->dso->short_name);
19658c2ecf20Sopenharmony_ci}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_civoid __maps__sort_by_name(struct maps *maps)
19688c2ecf20Sopenharmony_ci{
19698c2ecf20Sopenharmony_ci	qsort(maps->maps_by_name, maps->nr_maps, sizeof(struct map *), map__strcmp);
19708c2ecf20Sopenharmony_ci}
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_cistatic int map__groups__sort_by_name_from_rbtree(struct maps *maps)
19738c2ecf20Sopenharmony_ci{
19748c2ecf20Sopenharmony_ci	struct map *map;
19758c2ecf20Sopenharmony_ci	struct map **maps_by_name = realloc(maps->maps_by_name, maps->nr_maps * sizeof(map));
19768c2ecf20Sopenharmony_ci	int i = 0;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	if (maps_by_name == NULL)
19798c2ecf20Sopenharmony_ci		return -1;
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci	maps->maps_by_name = maps_by_name;
19828c2ecf20Sopenharmony_ci	maps->nr_maps_allocated = maps->nr_maps;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	maps__for_each_entry(maps, map)
19858c2ecf20Sopenharmony_ci		maps_by_name[i++] = map;
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	__maps__sort_by_name(maps);
19888c2ecf20Sopenharmony_ci	return 0;
19898c2ecf20Sopenharmony_ci}
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_cistatic struct map *__maps__find_by_name(struct maps *maps, const char *name)
19928c2ecf20Sopenharmony_ci{
19938c2ecf20Sopenharmony_ci	struct map **mapp;
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	if (maps->maps_by_name == NULL &&
19968c2ecf20Sopenharmony_ci	    map__groups__sort_by_name_from_rbtree(maps))
19978c2ecf20Sopenharmony_ci		return NULL;
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_ci	mapp = bsearch(name, maps->maps_by_name, maps->nr_maps, sizeof(*mapp), map__strcmp_name);
20008c2ecf20Sopenharmony_ci	if (mapp)
20018c2ecf20Sopenharmony_ci		return *mapp;
20028c2ecf20Sopenharmony_ci	return NULL;
20038c2ecf20Sopenharmony_ci}
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_cistruct map *maps__find_by_name(struct maps *maps, const char *name)
20068c2ecf20Sopenharmony_ci{
20078c2ecf20Sopenharmony_ci	struct map *map;
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	down_read(&maps->lock);
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	if (maps->last_search_by_name && strcmp(maps->last_search_by_name->dso->short_name, name) == 0) {
20128c2ecf20Sopenharmony_ci		map = maps->last_search_by_name;
20138c2ecf20Sopenharmony_ci		goto out_unlock;
20148c2ecf20Sopenharmony_ci	}
20158c2ecf20Sopenharmony_ci	/*
20168c2ecf20Sopenharmony_ci	 * If we have maps->maps_by_name, then the name isn't in the rbtree,
20178c2ecf20Sopenharmony_ci	 * as maps->maps_by_name mirrors the rbtree when lookups by name are
20188c2ecf20Sopenharmony_ci	 * made.
20198c2ecf20Sopenharmony_ci	 */
20208c2ecf20Sopenharmony_ci	map = __maps__find_by_name(maps, name);
20218c2ecf20Sopenharmony_ci	if (map || maps->maps_by_name != NULL)
20228c2ecf20Sopenharmony_ci		goto out_unlock;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	/* Fallback to traversing the rbtree... */
20258c2ecf20Sopenharmony_ci	maps__for_each_entry(maps, map)
20268c2ecf20Sopenharmony_ci		if (strcmp(map->dso->short_name, name) == 0) {
20278c2ecf20Sopenharmony_ci			maps->last_search_by_name = map;
20288c2ecf20Sopenharmony_ci			goto out_unlock;
20298c2ecf20Sopenharmony_ci		}
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	map = NULL;
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ciout_unlock:
20348c2ecf20Sopenharmony_ci	up_read(&maps->lock);
20358c2ecf20Sopenharmony_ci	return map;
20368c2ecf20Sopenharmony_ci}
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ciint dso__load_vmlinux(struct dso *dso, struct map *map,
20398c2ecf20Sopenharmony_ci		      const char *vmlinux, bool vmlinux_allocated)
20408c2ecf20Sopenharmony_ci{
20418c2ecf20Sopenharmony_ci	int err = -1;
20428c2ecf20Sopenharmony_ci	struct symsrc ss;
20438c2ecf20Sopenharmony_ci	char symfs_vmlinux[PATH_MAX];
20448c2ecf20Sopenharmony_ci	enum dso_binary_type symtab_type;
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	if (vmlinux[0] == '/')
20478c2ecf20Sopenharmony_ci		snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
20488c2ecf20Sopenharmony_ci	else
20498c2ecf20Sopenharmony_ci		symbol__join_symfs(symfs_vmlinux, vmlinux);
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci	if (dso->kernel == DSO_SPACE__KERNEL_GUEST)
20528c2ecf20Sopenharmony_ci		symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
20538c2ecf20Sopenharmony_ci	else
20548c2ecf20Sopenharmony_ci		symtab_type = DSO_BINARY_TYPE__VMLINUX;
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci	if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
20578c2ecf20Sopenharmony_ci		return -1;
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci	err = dso__load_sym(dso, map, &ss, &ss, 0);
20608c2ecf20Sopenharmony_ci	symsrc__destroy(&ss);
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci	if (err > 0) {
20638c2ecf20Sopenharmony_ci		if (dso->kernel == DSO_SPACE__KERNEL_GUEST)
20648c2ecf20Sopenharmony_ci			dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
20658c2ecf20Sopenharmony_ci		else
20668c2ecf20Sopenharmony_ci			dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
20678c2ecf20Sopenharmony_ci		dso__set_long_name(dso, vmlinux, vmlinux_allocated);
20688c2ecf20Sopenharmony_ci		dso__set_loaded(dso);
20698c2ecf20Sopenharmony_ci		pr_debug("Using %s for symbols\n", symfs_vmlinux);
20708c2ecf20Sopenharmony_ci	}
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	return err;
20738c2ecf20Sopenharmony_ci}
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ciint dso__load_vmlinux_path(struct dso *dso, struct map *map)
20768c2ecf20Sopenharmony_ci{
20778c2ecf20Sopenharmony_ci	int i, err = 0;
20788c2ecf20Sopenharmony_ci	char *filename = NULL;
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
20818c2ecf20Sopenharmony_ci		 vmlinux_path__nr_entries + 1);
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
20848c2ecf20Sopenharmony_ci		err = dso__load_vmlinux(dso, map, vmlinux_path[i], false);
20858c2ecf20Sopenharmony_ci		if (err > 0)
20868c2ecf20Sopenharmony_ci			goto out;
20878c2ecf20Sopenharmony_ci	}
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	if (!symbol_conf.ignore_vmlinux_buildid)
20908c2ecf20Sopenharmony_ci		filename = dso__build_id_filename(dso, NULL, 0, false);
20918c2ecf20Sopenharmony_ci	if (filename != NULL) {
20928c2ecf20Sopenharmony_ci		err = dso__load_vmlinux(dso, map, filename, true);
20938c2ecf20Sopenharmony_ci		if (err > 0)
20948c2ecf20Sopenharmony_ci			goto out;
20958c2ecf20Sopenharmony_ci		free(filename);
20968c2ecf20Sopenharmony_ci	}
20978c2ecf20Sopenharmony_ciout:
20988c2ecf20Sopenharmony_ci	return err;
20998c2ecf20Sopenharmony_ci}
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_cistatic bool visible_dir_filter(const char *name, struct dirent *d)
21028c2ecf20Sopenharmony_ci{
21038c2ecf20Sopenharmony_ci	if (d->d_type != DT_DIR)
21048c2ecf20Sopenharmony_ci		return false;
21058c2ecf20Sopenharmony_ci	return lsdir_no_dot_filter(name, d);
21068c2ecf20Sopenharmony_ci}
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_cistatic int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
21098c2ecf20Sopenharmony_ci{
21108c2ecf20Sopenharmony_ci	char kallsyms_filename[PATH_MAX];
21118c2ecf20Sopenharmony_ci	int ret = -1;
21128c2ecf20Sopenharmony_ci	struct strlist *dirs;
21138c2ecf20Sopenharmony_ci	struct str_node *nd;
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	dirs = lsdir(dir, visible_dir_filter);
21168c2ecf20Sopenharmony_ci	if (!dirs)
21178c2ecf20Sopenharmony_ci		return -1;
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci	strlist__for_each_entry(nd, dirs) {
21208c2ecf20Sopenharmony_ci		scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
21218c2ecf20Sopenharmony_ci			  "%s/%s/kallsyms", dir, nd->s);
21228c2ecf20Sopenharmony_ci		if (!validate_kcore_addresses(kallsyms_filename, map)) {
21238c2ecf20Sopenharmony_ci			strlcpy(dir, kallsyms_filename, dir_sz);
21248c2ecf20Sopenharmony_ci			ret = 0;
21258c2ecf20Sopenharmony_ci			break;
21268c2ecf20Sopenharmony_ci		}
21278c2ecf20Sopenharmony_ci	}
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	strlist__delete(dirs);
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci	return ret;
21328c2ecf20Sopenharmony_ci}
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci/*
21358c2ecf20Sopenharmony_ci * Use open(O_RDONLY) to check readability directly instead of access(R_OK)
21368c2ecf20Sopenharmony_ci * since access(R_OK) only checks with real UID/GID but open() use effective
21378c2ecf20Sopenharmony_ci * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO).
21388c2ecf20Sopenharmony_ci */
21398c2ecf20Sopenharmony_cistatic bool filename__readable(const char *file)
21408c2ecf20Sopenharmony_ci{
21418c2ecf20Sopenharmony_ci	int fd = open(file, O_RDONLY);
21428c2ecf20Sopenharmony_ci	if (fd < 0)
21438c2ecf20Sopenharmony_ci		return false;
21448c2ecf20Sopenharmony_ci	close(fd);
21458c2ecf20Sopenharmony_ci	return true;
21468c2ecf20Sopenharmony_ci}
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_cistatic char *dso__find_kallsyms(struct dso *dso, struct map *map)
21498c2ecf20Sopenharmony_ci{
21508c2ecf20Sopenharmony_ci	struct build_id bid;
21518c2ecf20Sopenharmony_ci	char sbuild_id[SBUILD_ID_SIZE];
21528c2ecf20Sopenharmony_ci	bool is_host = false;
21538c2ecf20Sopenharmony_ci	char path[PATH_MAX];
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	if (!dso->has_build_id) {
21568c2ecf20Sopenharmony_ci		/*
21578c2ecf20Sopenharmony_ci		 * Last resort, if we don't have a build-id and couldn't find
21588c2ecf20Sopenharmony_ci		 * any vmlinux file, try the running kernel kallsyms table.
21598c2ecf20Sopenharmony_ci		 */
21608c2ecf20Sopenharmony_ci		goto proc_kallsyms;
21618c2ecf20Sopenharmony_ci	}
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	if (sysfs__read_build_id("/sys/kernel/notes", &bid) == 0)
21648c2ecf20Sopenharmony_ci		is_host = dso__build_id_equal(dso, &bid);
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ci	/* Try a fast path for /proc/kallsyms if possible */
21678c2ecf20Sopenharmony_ci	if (is_host) {
21688c2ecf20Sopenharmony_ci		/*
21698c2ecf20Sopenharmony_ci		 * Do not check the build-id cache, unless we know we cannot use
21708c2ecf20Sopenharmony_ci		 * /proc/kcore or module maps don't match to /proc/kallsyms.
21718c2ecf20Sopenharmony_ci		 * To check readability of /proc/kcore, do not use access(R_OK)
21728c2ecf20Sopenharmony_ci		 * since /proc/kcore requires CAP_SYS_RAWIO to read and access
21738c2ecf20Sopenharmony_ci		 * can't check it.
21748c2ecf20Sopenharmony_ci		 */
21758c2ecf20Sopenharmony_ci		if (filename__readable("/proc/kcore") &&
21768c2ecf20Sopenharmony_ci		    !validate_kcore_addresses("/proc/kallsyms", map))
21778c2ecf20Sopenharmony_ci			goto proc_kallsyms;
21788c2ecf20Sopenharmony_ci	}
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	build_id__sprintf(&dso->bid, sbuild_id);
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci	/* Find kallsyms in build-id cache with kcore */
21838c2ecf20Sopenharmony_ci	scnprintf(path, sizeof(path), "%s/%s/%s",
21848c2ecf20Sopenharmony_ci		  buildid_dir, DSO__NAME_KCORE, sbuild_id);
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	if (!find_matching_kcore(map, path, sizeof(path)))
21878c2ecf20Sopenharmony_ci		return strdup(path);
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	/* Use current /proc/kallsyms if possible */
21908c2ecf20Sopenharmony_ci	if (is_host) {
21918c2ecf20Sopenharmony_ciproc_kallsyms:
21928c2ecf20Sopenharmony_ci		return strdup("/proc/kallsyms");
21938c2ecf20Sopenharmony_ci	}
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	/* Finally, find a cache of kallsyms */
21968c2ecf20Sopenharmony_ci	if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) {
21978c2ecf20Sopenharmony_ci		pr_err("No kallsyms or vmlinux with build-id %s was found\n",
21988c2ecf20Sopenharmony_ci		       sbuild_id);
21998c2ecf20Sopenharmony_ci		return NULL;
22008c2ecf20Sopenharmony_ci	}
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	return strdup(path);
22038c2ecf20Sopenharmony_ci}
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_cistatic int dso__load_kernel_sym(struct dso *dso, struct map *map)
22068c2ecf20Sopenharmony_ci{
22078c2ecf20Sopenharmony_ci	int err;
22088c2ecf20Sopenharmony_ci	const char *kallsyms_filename = NULL;
22098c2ecf20Sopenharmony_ci	char *kallsyms_allocated_filename = NULL;
22108c2ecf20Sopenharmony_ci	/*
22118c2ecf20Sopenharmony_ci	 * Step 1: if the user specified a kallsyms or vmlinux filename, use
22128c2ecf20Sopenharmony_ci	 * it and only it, reporting errors to the user if it cannot be used.
22138c2ecf20Sopenharmony_ci	 *
22148c2ecf20Sopenharmony_ci	 * For instance, try to analyse an ARM perf.data file _without_ a
22158c2ecf20Sopenharmony_ci	 * build-id, or if the user specifies the wrong path to the right
22168c2ecf20Sopenharmony_ci	 * vmlinux file, obviously we can't fallback to another vmlinux (a
22178c2ecf20Sopenharmony_ci	 * x86_86 one, on the machine where analysis is being performed, say),
22188c2ecf20Sopenharmony_ci	 * or worse, /proc/kallsyms.
22198c2ecf20Sopenharmony_ci	 *
22208c2ecf20Sopenharmony_ci	 * If the specified file _has_ a build-id and there is a build-id
22218c2ecf20Sopenharmony_ci	 * section in the perf.data file, we will still do the expected
22228c2ecf20Sopenharmony_ci	 * validation in dso__load_vmlinux and will bail out if they don't
22238c2ecf20Sopenharmony_ci	 * match.
22248c2ecf20Sopenharmony_ci	 */
22258c2ecf20Sopenharmony_ci	if (symbol_conf.kallsyms_name != NULL) {
22268c2ecf20Sopenharmony_ci		kallsyms_filename = symbol_conf.kallsyms_name;
22278c2ecf20Sopenharmony_ci		goto do_kallsyms;
22288c2ecf20Sopenharmony_ci	}
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci	if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
22318c2ecf20Sopenharmony_ci		return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false);
22328c2ecf20Sopenharmony_ci	}
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
22358c2ecf20Sopenharmony_ci		err = dso__load_vmlinux_path(dso, map);
22368c2ecf20Sopenharmony_ci		if (err > 0)
22378c2ecf20Sopenharmony_ci			return err;
22388c2ecf20Sopenharmony_ci	}
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ci	/* do not try local files if a symfs was given */
22418c2ecf20Sopenharmony_ci	if (symbol_conf.symfs[0] != 0)
22428c2ecf20Sopenharmony_ci		return -1;
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
22458c2ecf20Sopenharmony_ci	if (!kallsyms_allocated_filename)
22468c2ecf20Sopenharmony_ci		return -1;
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	kallsyms_filename = kallsyms_allocated_filename;
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_cido_kallsyms:
22518c2ecf20Sopenharmony_ci	err = dso__load_kallsyms(dso, kallsyms_filename, map);
22528c2ecf20Sopenharmony_ci	if (err > 0)
22538c2ecf20Sopenharmony_ci		pr_debug("Using %s for symbols\n", kallsyms_filename);
22548c2ecf20Sopenharmony_ci	free(kallsyms_allocated_filename);
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_ci	if (err > 0 && !dso__is_kcore(dso)) {
22578c2ecf20Sopenharmony_ci		dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
22588c2ecf20Sopenharmony_ci		dso__set_long_name(dso, DSO__NAME_KALLSYMS, false);
22598c2ecf20Sopenharmony_ci		map__fixup_start(map);
22608c2ecf20Sopenharmony_ci		map__fixup_end(map);
22618c2ecf20Sopenharmony_ci	}
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	return err;
22648c2ecf20Sopenharmony_ci}
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_cistatic int dso__load_guest_kernel_sym(struct dso *dso, struct map *map)
22678c2ecf20Sopenharmony_ci{
22688c2ecf20Sopenharmony_ci	int err;
22698c2ecf20Sopenharmony_ci	const char *kallsyms_filename = NULL;
22708c2ecf20Sopenharmony_ci	struct machine *machine = map__kmaps(map)->machine;
22718c2ecf20Sopenharmony_ci	char path[PATH_MAX];
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	if (machine__is_default_guest(machine)) {
22748c2ecf20Sopenharmony_ci		/*
22758c2ecf20Sopenharmony_ci		 * if the user specified a vmlinux filename, use it and only
22768c2ecf20Sopenharmony_ci		 * it, reporting errors to the user if it cannot be used.
22778c2ecf20Sopenharmony_ci		 * Or use file guest_kallsyms inputted by user on commandline
22788c2ecf20Sopenharmony_ci		 */
22798c2ecf20Sopenharmony_ci		if (symbol_conf.default_guest_vmlinux_name != NULL) {
22808c2ecf20Sopenharmony_ci			err = dso__load_vmlinux(dso, map,
22818c2ecf20Sopenharmony_ci						symbol_conf.default_guest_vmlinux_name,
22828c2ecf20Sopenharmony_ci						false);
22838c2ecf20Sopenharmony_ci			return err;
22848c2ecf20Sopenharmony_ci		}
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci		kallsyms_filename = symbol_conf.default_guest_kallsyms;
22878c2ecf20Sopenharmony_ci		if (!kallsyms_filename)
22888c2ecf20Sopenharmony_ci			return -1;
22898c2ecf20Sopenharmony_ci	} else {
22908c2ecf20Sopenharmony_ci		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
22918c2ecf20Sopenharmony_ci		kallsyms_filename = path;
22928c2ecf20Sopenharmony_ci	}
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	err = dso__load_kallsyms(dso, kallsyms_filename, map);
22958c2ecf20Sopenharmony_ci	if (err > 0)
22968c2ecf20Sopenharmony_ci		pr_debug("Using %s for symbols\n", kallsyms_filename);
22978c2ecf20Sopenharmony_ci	if (err > 0 && !dso__is_kcore(dso)) {
22988c2ecf20Sopenharmony_ci		dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
22998c2ecf20Sopenharmony_ci		dso__set_long_name(dso, machine->mmap_name, false);
23008c2ecf20Sopenharmony_ci		map__fixup_start(map);
23018c2ecf20Sopenharmony_ci		map__fixup_end(map);
23028c2ecf20Sopenharmony_ci	}
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci	return err;
23058c2ecf20Sopenharmony_ci}
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_cistatic void vmlinux_path__exit(void)
23088c2ecf20Sopenharmony_ci{
23098c2ecf20Sopenharmony_ci	while (--vmlinux_path__nr_entries >= 0)
23108c2ecf20Sopenharmony_ci		zfree(&vmlinux_path[vmlinux_path__nr_entries]);
23118c2ecf20Sopenharmony_ci	vmlinux_path__nr_entries = 0;
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci	zfree(&vmlinux_path);
23148c2ecf20Sopenharmony_ci}
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_cistatic const char * const vmlinux_paths[] = {
23178c2ecf20Sopenharmony_ci	"vmlinux",
23188c2ecf20Sopenharmony_ci	"/boot/vmlinux"
23198c2ecf20Sopenharmony_ci};
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_cistatic const char * const vmlinux_paths_upd[] = {
23228c2ecf20Sopenharmony_ci	"/boot/vmlinux-%s",
23238c2ecf20Sopenharmony_ci	"/usr/lib/debug/boot/vmlinux-%s",
23248c2ecf20Sopenharmony_ci	"/lib/modules/%s/build/vmlinux",
23258c2ecf20Sopenharmony_ci	"/usr/lib/debug/lib/modules/%s/vmlinux",
23268c2ecf20Sopenharmony_ci	"/usr/lib/debug/boot/vmlinux-%s.debug"
23278c2ecf20Sopenharmony_ci};
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_cistatic int vmlinux_path__add(const char *new_entry)
23308c2ecf20Sopenharmony_ci{
23318c2ecf20Sopenharmony_ci	vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry);
23328c2ecf20Sopenharmony_ci	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
23338c2ecf20Sopenharmony_ci		return -1;
23348c2ecf20Sopenharmony_ci	++vmlinux_path__nr_entries;
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci	return 0;
23378c2ecf20Sopenharmony_ci}
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_cistatic int vmlinux_path__init(struct perf_env *env)
23408c2ecf20Sopenharmony_ci{
23418c2ecf20Sopenharmony_ci	struct utsname uts;
23428c2ecf20Sopenharmony_ci	char bf[PATH_MAX];
23438c2ecf20Sopenharmony_ci	char *kernel_version;
23448c2ecf20Sopenharmony_ci	unsigned int i;
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) +
23478c2ecf20Sopenharmony_ci			      ARRAY_SIZE(vmlinux_paths_upd)));
23488c2ecf20Sopenharmony_ci	if (vmlinux_path == NULL)
23498c2ecf20Sopenharmony_ci		return -1;
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++)
23528c2ecf20Sopenharmony_ci		if (vmlinux_path__add(vmlinux_paths[i]) < 0)
23538c2ecf20Sopenharmony_ci			goto out_fail;
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_ci	/* only try kernel version if no symfs was given */
23568c2ecf20Sopenharmony_ci	if (symbol_conf.symfs[0] != 0)
23578c2ecf20Sopenharmony_ci		return 0;
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_ci	if (env) {
23608c2ecf20Sopenharmony_ci		kernel_version = env->os_release;
23618c2ecf20Sopenharmony_ci	} else {
23628c2ecf20Sopenharmony_ci		if (uname(&uts) < 0)
23638c2ecf20Sopenharmony_ci			goto out_fail;
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci		kernel_version = uts.release;
23668c2ecf20Sopenharmony_ci	}
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) {
23698c2ecf20Sopenharmony_ci		snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version);
23708c2ecf20Sopenharmony_ci		if (vmlinux_path__add(bf) < 0)
23718c2ecf20Sopenharmony_ci			goto out_fail;
23728c2ecf20Sopenharmony_ci	}
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci	return 0;
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ciout_fail:
23778c2ecf20Sopenharmony_ci	vmlinux_path__exit();
23788c2ecf20Sopenharmony_ci	return -1;
23798c2ecf20Sopenharmony_ci}
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ciint setup_list(struct strlist **list, const char *list_str,
23828c2ecf20Sopenharmony_ci		      const char *list_name)
23838c2ecf20Sopenharmony_ci{
23848c2ecf20Sopenharmony_ci	if (list_str == NULL)
23858c2ecf20Sopenharmony_ci		return 0;
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_ci	*list = strlist__new(list_str, NULL);
23888c2ecf20Sopenharmony_ci	if (!*list) {
23898c2ecf20Sopenharmony_ci		pr_err("problems parsing %s list\n", list_name);
23908c2ecf20Sopenharmony_ci		return -1;
23918c2ecf20Sopenharmony_ci	}
23928c2ecf20Sopenharmony_ci
23938c2ecf20Sopenharmony_ci	symbol_conf.has_filter = true;
23948c2ecf20Sopenharmony_ci	return 0;
23958c2ecf20Sopenharmony_ci}
23968c2ecf20Sopenharmony_ci
23978c2ecf20Sopenharmony_ciint setup_intlist(struct intlist **list, const char *list_str,
23988c2ecf20Sopenharmony_ci		  const char *list_name)
23998c2ecf20Sopenharmony_ci{
24008c2ecf20Sopenharmony_ci	if (list_str == NULL)
24018c2ecf20Sopenharmony_ci		return 0;
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	*list = intlist__new(list_str);
24048c2ecf20Sopenharmony_ci	if (!*list) {
24058c2ecf20Sopenharmony_ci		pr_err("problems parsing %s list\n", list_name);
24068c2ecf20Sopenharmony_ci		return -1;
24078c2ecf20Sopenharmony_ci	}
24088c2ecf20Sopenharmony_ci	return 0;
24098c2ecf20Sopenharmony_ci}
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_cistatic bool symbol__read_kptr_restrict(void)
24128c2ecf20Sopenharmony_ci{
24138c2ecf20Sopenharmony_ci	bool value = false;
24148c2ecf20Sopenharmony_ci	FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci	if (fp != NULL) {
24178c2ecf20Sopenharmony_ci		char line[8];
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ci		if (fgets(line, sizeof(line), fp) != NULL)
24208c2ecf20Sopenharmony_ci			value = perf_cap__capable(CAP_SYSLOG) ?
24218c2ecf20Sopenharmony_ci					(atoi(line) >= 2) :
24228c2ecf20Sopenharmony_ci					(atoi(line) != 0);
24238c2ecf20Sopenharmony_ci
24248c2ecf20Sopenharmony_ci		fclose(fp);
24258c2ecf20Sopenharmony_ci	}
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci	/* Per kernel/kallsyms.c:
24288c2ecf20Sopenharmony_ci	 * we also restrict when perf_event_paranoid > 1 w/o CAP_SYSLOG
24298c2ecf20Sopenharmony_ci	 */
24308c2ecf20Sopenharmony_ci	if (perf_event_paranoid() > 1 && !perf_cap__capable(CAP_SYSLOG))
24318c2ecf20Sopenharmony_ci		value = true;
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ci	return value;
24348c2ecf20Sopenharmony_ci}
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ciint symbol__annotation_init(void)
24378c2ecf20Sopenharmony_ci{
24388c2ecf20Sopenharmony_ci	if (symbol_conf.init_annotation)
24398c2ecf20Sopenharmony_ci		return 0;
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	if (symbol_conf.initialized) {
24428c2ecf20Sopenharmony_ci		pr_err("Annotation needs to be init before symbol__init()\n");
24438c2ecf20Sopenharmony_ci		return -1;
24448c2ecf20Sopenharmony_ci	}
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci	symbol_conf.priv_size += sizeof(struct annotation);
24478c2ecf20Sopenharmony_ci	symbol_conf.init_annotation = true;
24488c2ecf20Sopenharmony_ci	return 0;
24498c2ecf20Sopenharmony_ci}
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_ciint symbol__init(struct perf_env *env)
24528c2ecf20Sopenharmony_ci{
24538c2ecf20Sopenharmony_ci	const char *symfs;
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_ci	if (symbol_conf.initialized)
24568c2ecf20Sopenharmony_ci		return 0;
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci	symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	symbol__elf_init();
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci	if (symbol_conf.sort_by_name)
24638c2ecf20Sopenharmony_ci		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
24648c2ecf20Sopenharmony_ci					  sizeof(struct symbol));
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
24678c2ecf20Sopenharmony_ci		return -1;
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
24708c2ecf20Sopenharmony_ci		pr_err("'.' is the only non valid --field-separator argument\n");
24718c2ecf20Sopenharmony_ci		return -1;
24728c2ecf20Sopenharmony_ci	}
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci	if (setup_list(&symbol_conf.dso_list,
24758c2ecf20Sopenharmony_ci		       symbol_conf.dso_list_str, "dso") < 0)
24768c2ecf20Sopenharmony_ci		return -1;
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci	if (setup_list(&symbol_conf.comm_list,
24798c2ecf20Sopenharmony_ci		       symbol_conf.comm_list_str, "comm") < 0)
24808c2ecf20Sopenharmony_ci		goto out_free_dso_list;
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci	if (setup_intlist(&symbol_conf.pid_list,
24838c2ecf20Sopenharmony_ci		       symbol_conf.pid_list_str, "pid") < 0)
24848c2ecf20Sopenharmony_ci		goto out_free_comm_list;
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci	if (setup_intlist(&symbol_conf.tid_list,
24878c2ecf20Sopenharmony_ci		       symbol_conf.tid_list_str, "tid") < 0)
24888c2ecf20Sopenharmony_ci		goto out_free_pid_list;
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci	if (setup_list(&symbol_conf.sym_list,
24918c2ecf20Sopenharmony_ci		       symbol_conf.sym_list_str, "symbol") < 0)
24928c2ecf20Sopenharmony_ci		goto out_free_tid_list;
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	if (setup_list(&symbol_conf.bt_stop_list,
24958c2ecf20Sopenharmony_ci		       symbol_conf.bt_stop_list_str, "symbol") < 0)
24968c2ecf20Sopenharmony_ci		goto out_free_sym_list;
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_ci	/*
24998c2ecf20Sopenharmony_ci	 * A path to symbols of "/" is identical to ""
25008c2ecf20Sopenharmony_ci	 * reset here for simplicity.
25018c2ecf20Sopenharmony_ci	 */
25028c2ecf20Sopenharmony_ci	symfs = realpath(symbol_conf.symfs, NULL);
25038c2ecf20Sopenharmony_ci	if (symfs == NULL)
25048c2ecf20Sopenharmony_ci		symfs = symbol_conf.symfs;
25058c2ecf20Sopenharmony_ci	if (strcmp(symfs, "/") == 0)
25068c2ecf20Sopenharmony_ci		symbol_conf.symfs = "";
25078c2ecf20Sopenharmony_ci	if (symfs != symbol_conf.symfs)
25088c2ecf20Sopenharmony_ci		free((void *)symfs);
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci	symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci	symbol_conf.initialized = true;
25138c2ecf20Sopenharmony_ci	return 0;
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ciout_free_sym_list:
25168c2ecf20Sopenharmony_ci	strlist__delete(symbol_conf.sym_list);
25178c2ecf20Sopenharmony_ciout_free_tid_list:
25188c2ecf20Sopenharmony_ci	intlist__delete(symbol_conf.tid_list);
25198c2ecf20Sopenharmony_ciout_free_pid_list:
25208c2ecf20Sopenharmony_ci	intlist__delete(symbol_conf.pid_list);
25218c2ecf20Sopenharmony_ciout_free_comm_list:
25228c2ecf20Sopenharmony_ci	strlist__delete(symbol_conf.comm_list);
25238c2ecf20Sopenharmony_ciout_free_dso_list:
25248c2ecf20Sopenharmony_ci	strlist__delete(symbol_conf.dso_list);
25258c2ecf20Sopenharmony_ci	return -1;
25268c2ecf20Sopenharmony_ci}
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_civoid symbol__exit(void)
25298c2ecf20Sopenharmony_ci{
25308c2ecf20Sopenharmony_ci	if (!symbol_conf.initialized)
25318c2ecf20Sopenharmony_ci		return;
25328c2ecf20Sopenharmony_ci	strlist__delete(symbol_conf.bt_stop_list);
25338c2ecf20Sopenharmony_ci	strlist__delete(symbol_conf.sym_list);
25348c2ecf20Sopenharmony_ci	strlist__delete(symbol_conf.dso_list);
25358c2ecf20Sopenharmony_ci	strlist__delete(symbol_conf.comm_list);
25368c2ecf20Sopenharmony_ci	intlist__delete(symbol_conf.tid_list);
25378c2ecf20Sopenharmony_ci	intlist__delete(symbol_conf.pid_list);
25388c2ecf20Sopenharmony_ci	vmlinux_path__exit();
25398c2ecf20Sopenharmony_ci	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
25408c2ecf20Sopenharmony_ci	symbol_conf.bt_stop_list = NULL;
25418c2ecf20Sopenharmony_ci	symbol_conf.initialized = false;
25428c2ecf20Sopenharmony_ci}
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ciint symbol__config_symfs(const struct option *opt __maybe_unused,
25458c2ecf20Sopenharmony_ci			 const char *dir, int unset __maybe_unused)
25468c2ecf20Sopenharmony_ci{
25478c2ecf20Sopenharmony_ci	char *bf = NULL;
25488c2ecf20Sopenharmony_ci	int ret;
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci	symbol_conf.symfs = strdup(dir);
25518c2ecf20Sopenharmony_ci	if (symbol_conf.symfs == NULL)
25528c2ecf20Sopenharmony_ci		return -ENOMEM;
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ci	/* skip the locally configured cache if a symfs is given, and
25558c2ecf20Sopenharmony_ci	 * config buildid dir to symfs/.debug
25568c2ecf20Sopenharmony_ci	 */
25578c2ecf20Sopenharmony_ci	ret = asprintf(&bf, "%s/%s", dir, ".debug");
25588c2ecf20Sopenharmony_ci	if (ret < 0)
25598c2ecf20Sopenharmony_ci		return -ENOMEM;
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_ci	set_buildid_dir(bf);
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci	free(bf);
25648c2ecf20Sopenharmony_ci	return 0;
25658c2ecf20Sopenharmony_ci}
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_cistruct mem_info *mem_info__get(struct mem_info *mi)
25688c2ecf20Sopenharmony_ci{
25698c2ecf20Sopenharmony_ci	if (mi)
25708c2ecf20Sopenharmony_ci		refcount_inc(&mi->refcnt);
25718c2ecf20Sopenharmony_ci	return mi;
25728c2ecf20Sopenharmony_ci}
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_civoid mem_info__put(struct mem_info *mi)
25758c2ecf20Sopenharmony_ci{
25768c2ecf20Sopenharmony_ci	if (mi && refcount_dec_and_test(&mi->refcnt))
25778c2ecf20Sopenharmony_ci		free(mi);
25788c2ecf20Sopenharmony_ci}
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_cistruct mem_info *mem_info__new(void)
25818c2ecf20Sopenharmony_ci{
25828c2ecf20Sopenharmony_ci	struct mem_info *mi = zalloc(sizeof(*mi));
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	if (mi)
25858c2ecf20Sopenharmony_ci		refcount_set(&mi->refcnt, 1);
25868c2ecf20Sopenharmony_ci	return mi;
25878c2ecf20Sopenharmony_ci}
2588