18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Parts came from builtin-annotate.c, see those files for further
68c2ecf20Sopenharmony_ci * copyright notes.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <errno.h>
108c2ecf20Sopenharmony_ci#include <inttypes.h>
118c2ecf20Sopenharmony_ci#include <libgen.h>
128c2ecf20Sopenharmony_ci#include <stdlib.h>
138c2ecf20Sopenharmony_ci#include <bpf/bpf.h>
148c2ecf20Sopenharmony_ci#include <bpf/btf.h>
158c2ecf20Sopenharmony_ci#include <bpf/libbpf.h>
168c2ecf20Sopenharmony_ci#include <linux/btf.h>
178c2ecf20Sopenharmony_ci#include "util.h" // hex_width()
188c2ecf20Sopenharmony_ci#include "ui/ui.h"
198c2ecf20Sopenharmony_ci#include "sort.h"
208c2ecf20Sopenharmony_ci#include "build-id.h"
218c2ecf20Sopenharmony_ci#include "color.h"
228c2ecf20Sopenharmony_ci#include "config.h"
238c2ecf20Sopenharmony_ci#include "dso.h"
248c2ecf20Sopenharmony_ci#include "env.h"
258c2ecf20Sopenharmony_ci#include "map.h"
268c2ecf20Sopenharmony_ci#include "maps.h"
278c2ecf20Sopenharmony_ci#include "symbol.h"
288c2ecf20Sopenharmony_ci#include "srcline.h"
298c2ecf20Sopenharmony_ci#include "units.h"
308c2ecf20Sopenharmony_ci#include "debug.h"
318c2ecf20Sopenharmony_ci#include "annotate.h"
328c2ecf20Sopenharmony_ci#include "evsel.h"
338c2ecf20Sopenharmony_ci#include "evlist.h"
348c2ecf20Sopenharmony_ci#include "bpf-event.h"
358c2ecf20Sopenharmony_ci#include "block-range.h"
368c2ecf20Sopenharmony_ci#include "string2.h"
378c2ecf20Sopenharmony_ci#include "util/event.h"
388c2ecf20Sopenharmony_ci#include "arch/common.h"
398c2ecf20Sopenharmony_ci#include <regex.h>
408c2ecf20Sopenharmony_ci#include <pthread.h>
418c2ecf20Sopenharmony_ci#include <linux/bitops.h>
428c2ecf20Sopenharmony_ci#include <linux/kernel.h>
438c2ecf20Sopenharmony_ci#include <linux/string.h>
448c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h>
458c2ecf20Sopenharmony_ci#include <subcmd/run-command.h>
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/* FIXME: For the HE_COLORSET */
488c2ecf20Sopenharmony_ci#include "ui/browser.h"
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/*
518c2ecf20Sopenharmony_ci * FIXME: Using the same values as slang.h,
528c2ecf20Sopenharmony_ci * but that header may not be available everywhere
538c2ecf20Sopenharmony_ci */
548c2ecf20Sopenharmony_ci#define LARROW_CHAR	((unsigned char)',')
558c2ecf20Sopenharmony_ci#define RARROW_CHAR	((unsigned char)'+')
568c2ecf20Sopenharmony_ci#define DARROW_CHAR	((unsigned char)'.')
578c2ecf20Sopenharmony_ci#define UARROW_CHAR	((unsigned char)'-')
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#include <linux/ctype.h>
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistruct annotation_options annotation__default_options = {
628c2ecf20Sopenharmony_ci	.use_offset     = true,
638c2ecf20Sopenharmony_ci	.jump_arrows    = true,
648c2ecf20Sopenharmony_ci	.annotate_src	= true,
658c2ecf20Sopenharmony_ci	.offset_level	= ANNOTATION__OFFSET_JUMP_TARGETS,
668c2ecf20Sopenharmony_ci	.percent_type	= PERCENT_PERIOD_LOCAL,
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic regex_t	 file_lineno;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic struct ins_ops *ins__find(struct arch *arch, const char *name);
728c2ecf20Sopenharmony_cistatic void ins__sort(struct arch *arch);
738c2ecf20Sopenharmony_cistatic int disasm_line__parse(char *line, const char **namep, char **rawp);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistruct arch {
768c2ecf20Sopenharmony_ci	const char	*name;
778c2ecf20Sopenharmony_ci	struct ins	*instructions;
788c2ecf20Sopenharmony_ci	size_t		nr_instructions;
798c2ecf20Sopenharmony_ci	size_t		nr_instructions_allocated;
808c2ecf20Sopenharmony_ci	struct ins_ops  *(*associate_instruction_ops)(struct arch *arch, const char *name);
818c2ecf20Sopenharmony_ci	bool		sorted_instructions;
828c2ecf20Sopenharmony_ci	bool		initialized;
838c2ecf20Sopenharmony_ci	void		*priv;
848c2ecf20Sopenharmony_ci	unsigned int	model;
858c2ecf20Sopenharmony_ci	unsigned int	family;
868c2ecf20Sopenharmony_ci	int		(*init)(struct arch *arch, char *cpuid);
878c2ecf20Sopenharmony_ci	bool		(*ins_is_fused)(struct arch *arch, const char *ins1,
888c2ecf20Sopenharmony_ci					const char *ins2);
898c2ecf20Sopenharmony_ci	struct		{
908c2ecf20Sopenharmony_ci		char comment_char;
918c2ecf20Sopenharmony_ci		char skip_functions_char;
928c2ecf20Sopenharmony_ci	} objdump;
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic struct ins_ops call_ops;
968c2ecf20Sopenharmony_cistatic struct ins_ops dec_ops;
978c2ecf20Sopenharmony_cistatic struct ins_ops jump_ops;
988c2ecf20Sopenharmony_cistatic struct ins_ops mov_ops;
998c2ecf20Sopenharmony_cistatic struct ins_ops nop_ops;
1008c2ecf20Sopenharmony_cistatic struct ins_ops lock_ops;
1018c2ecf20Sopenharmony_cistatic struct ins_ops ret_ops;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic int arch__grow_instructions(struct arch *arch)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct ins *new_instructions;
1068c2ecf20Sopenharmony_ci	size_t new_nr_allocated;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (arch->nr_instructions_allocated == 0 && arch->instructions)
1098c2ecf20Sopenharmony_ci		goto grow_from_non_allocated_table;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	new_nr_allocated = arch->nr_instructions_allocated + 128;
1128c2ecf20Sopenharmony_ci	new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins));
1138c2ecf20Sopenharmony_ci	if (new_instructions == NULL)
1148c2ecf20Sopenharmony_ci		return -1;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ciout_update_instructions:
1178c2ecf20Sopenharmony_ci	arch->instructions = new_instructions;
1188c2ecf20Sopenharmony_ci	arch->nr_instructions_allocated = new_nr_allocated;
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cigrow_from_non_allocated_table:
1228c2ecf20Sopenharmony_ci	new_nr_allocated = arch->nr_instructions + 128;
1238c2ecf20Sopenharmony_ci	new_instructions = calloc(new_nr_allocated, sizeof(struct ins));
1248c2ecf20Sopenharmony_ci	if (new_instructions == NULL)
1258c2ecf20Sopenharmony_ci		return -1;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	memcpy(new_instructions, arch->instructions, arch->nr_instructions);
1288c2ecf20Sopenharmony_ci	goto out_update_instructions;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct ins *ins;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (arch->nr_instructions == arch->nr_instructions_allocated &&
1368c2ecf20Sopenharmony_ci	    arch__grow_instructions(arch))
1378c2ecf20Sopenharmony_ci		return -1;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	ins = &arch->instructions[arch->nr_instructions];
1408c2ecf20Sopenharmony_ci	ins->name = strdup(name);
1418c2ecf20Sopenharmony_ci	if (!ins->name)
1428c2ecf20Sopenharmony_ci		return -1;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	ins->ops  = ops;
1458c2ecf20Sopenharmony_ci	arch->nr_instructions++;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	ins__sort(arch);
1488c2ecf20Sopenharmony_ci	return 0;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#include "arch/arc/annotate/instructions.c"
1528c2ecf20Sopenharmony_ci#include "arch/arm/annotate/instructions.c"
1538c2ecf20Sopenharmony_ci#include "arch/arm64/annotate/instructions.c"
1548c2ecf20Sopenharmony_ci#include "arch/csky/annotate/instructions.c"
1558c2ecf20Sopenharmony_ci#include "arch/x86/annotate/instructions.c"
1568c2ecf20Sopenharmony_ci#include "arch/powerpc/annotate/instructions.c"
1578c2ecf20Sopenharmony_ci#include "arch/s390/annotate/instructions.c"
1588c2ecf20Sopenharmony_ci#include "arch/sparc/annotate/instructions.c"
1598c2ecf20Sopenharmony_ci#include "arch/loongarch/annotate/instructions.c"
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic struct arch architectures[] = {
1628c2ecf20Sopenharmony_ci	{
1638c2ecf20Sopenharmony_ci		.name = "arc",
1648c2ecf20Sopenharmony_ci		.init = arc__annotate_init,
1658c2ecf20Sopenharmony_ci	},
1668c2ecf20Sopenharmony_ci	{
1678c2ecf20Sopenharmony_ci		.name = "arm",
1688c2ecf20Sopenharmony_ci		.init = arm__annotate_init,
1698c2ecf20Sopenharmony_ci	},
1708c2ecf20Sopenharmony_ci	{
1718c2ecf20Sopenharmony_ci		.name = "arm64",
1728c2ecf20Sopenharmony_ci		.init = arm64__annotate_init,
1738c2ecf20Sopenharmony_ci	},
1748c2ecf20Sopenharmony_ci	{
1758c2ecf20Sopenharmony_ci		.name = "csky",
1768c2ecf20Sopenharmony_ci		.init = csky__annotate_init,
1778c2ecf20Sopenharmony_ci	},
1788c2ecf20Sopenharmony_ci	{
1798c2ecf20Sopenharmony_ci		.name = "x86",
1808c2ecf20Sopenharmony_ci		.init = x86__annotate_init,
1818c2ecf20Sopenharmony_ci		.instructions = x86__instructions,
1828c2ecf20Sopenharmony_ci		.nr_instructions = ARRAY_SIZE(x86__instructions),
1838c2ecf20Sopenharmony_ci		.ins_is_fused = x86__ins_is_fused,
1848c2ecf20Sopenharmony_ci		.objdump =  {
1858c2ecf20Sopenharmony_ci			.comment_char = '#',
1868c2ecf20Sopenharmony_ci		},
1878c2ecf20Sopenharmony_ci	},
1888c2ecf20Sopenharmony_ci	{
1898c2ecf20Sopenharmony_ci		.name = "powerpc",
1908c2ecf20Sopenharmony_ci		.init = powerpc__annotate_init,
1918c2ecf20Sopenharmony_ci	},
1928c2ecf20Sopenharmony_ci	{
1938c2ecf20Sopenharmony_ci		.name = "s390",
1948c2ecf20Sopenharmony_ci		.init = s390__annotate_init,
1958c2ecf20Sopenharmony_ci		.objdump =  {
1968c2ecf20Sopenharmony_ci			.comment_char = '#',
1978c2ecf20Sopenharmony_ci		},
1988c2ecf20Sopenharmony_ci	},
1998c2ecf20Sopenharmony_ci	{
2008c2ecf20Sopenharmony_ci		.name = "sparc",
2018c2ecf20Sopenharmony_ci		.init = sparc__annotate_init,
2028c2ecf20Sopenharmony_ci		.objdump = {
2038c2ecf20Sopenharmony_ci			.comment_char = '#',
2048c2ecf20Sopenharmony_ci		},
2058c2ecf20Sopenharmony_ci	},
2068c2ecf20Sopenharmony_ci	{
2078c2ecf20Sopenharmony_ci		.name = "loongarch",
2088c2ecf20Sopenharmony_ci		.init = loongarch__annotate_init,
2098c2ecf20Sopenharmony_ci		.objdump = {
2108c2ecf20Sopenharmony_ci			.comment_char = '#',
2118c2ecf20Sopenharmony_ci		},
2128c2ecf20Sopenharmony_ci	},
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic void ins__delete(struct ins_operands *ops)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	if (ops == NULL)
2188c2ecf20Sopenharmony_ci		return;
2198c2ecf20Sopenharmony_ci	zfree(&ops->source.raw);
2208c2ecf20Sopenharmony_ci	zfree(&ops->source.name);
2218c2ecf20Sopenharmony_ci	zfree(&ops->target.raw);
2228c2ecf20Sopenharmony_ci	zfree(&ops->target.name);
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
2268c2ecf20Sopenharmony_ci			      struct ins_operands *ops, int max_ins_name)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ciint ins__scnprintf(struct ins *ins, char *bf, size_t size,
2328c2ecf20Sopenharmony_ci		   struct ins_operands *ops, int max_ins_name)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	if (ins->ops->scnprintf)
2358c2ecf20Sopenharmony_ci		return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cibool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	if (!arch || !arch->ins_is_fused)
2438c2ecf20Sopenharmony_ci		return false;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return arch->ins_is_fused(arch, ins1, ins2);
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	char *endptr, *tok, *name;
2518c2ecf20Sopenharmony_ci	struct map *map = ms->map;
2528c2ecf20Sopenharmony_ci	struct addr_map_symbol target = {
2538c2ecf20Sopenharmony_ci		.ms = { .map = map, },
2548c2ecf20Sopenharmony_ci	};
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	ops->target.addr = strtoull(ops->raw, &endptr, 16);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	name = strchr(endptr, '<');
2598c2ecf20Sopenharmony_ci	if (name == NULL)
2608c2ecf20Sopenharmony_ci		goto indirect_call;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	name++;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (arch->objdump.skip_functions_char &&
2658c2ecf20Sopenharmony_ci	    strchr(name, arch->objdump.skip_functions_char))
2668c2ecf20Sopenharmony_ci		return -1;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	tok = strchr(name, '>');
2698c2ecf20Sopenharmony_ci	if (tok == NULL)
2708c2ecf20Sopenharmony_ci		return -1;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	*tok = '\0';
2738c2ecf20Sopenharmony_ci	ops->target.name = strdup(name);
2748c2ecf20Sopenharmony_ci	*tok = '>';
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	if (ops->target.name == NULL)
2778c2ecf20Sopenharmony_ci		return -1;
2788c2ecf20Sopenharmony_cifind_target:
2798c2ecf20Sopenharmony_ci	target.addr = map__objdump_2mem(map, ops->target.addr);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (maps__find_ams(ms->maps, &target) == 0 &&
2828c2ecf20Sopenharmony_ci	    map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr)
2838c2ecf20Sopenharmony_ci		ops->target.sym = target.ms.sym;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	return 0;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ciindirect_call:
2888c2ecf20Sopenharmony_ci	tok = strchr(endptr, '*');
2898c2ecf20Sopenharmony_ci	if (tok != NULL) {
2908c2ecf20Sopenharmony_ci		endptr++;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		/* Indirect call can use a non-rip register and offset: callq  *0x8(%rbx).
2938c2ecf20Sopenharmony_ci		 * Do not parse such instruction.  */
2948c2ecf20Sopenharmony_ci		if (strstr(endptr, "(%r") == NULL)
2958c2ecf20Sopenharmony_ci			ops->target.addr = strtoull(endptr, NULL, 16);
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci	goto find_target;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic int call__scnprintf(struct ins *ins, char *bf, size_t size,
3018c2ecf20Sopenharmony_ci			   struct ins_operands *ops, int max_ins_name)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	if (ops->target.sym)
3048c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (ops->target.addr == 0)
3078c2ecf20Sopenharmony_ci		return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (ops->target.name)
3108c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr);
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic struct ins_ops call_ops = {
3168c2ecf20Sopenharmony_ci	.parse	   = call__parse,
3178c2ecf20Sopenharmony_ci	.scnprintf = call__scnprintf,
3188c2ecf20Sopenharmony_ci};
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cibool ins__is_call(const struct ins *ins)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	return ins->ops == &call_ops || ins->ops == &s390_call_ops;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci/*
3268c2ecf20Sopenharmony_ci * Prevents from matching commas in the comment section, e.g.:
3278c2ecf20Sopenharmony_ci * ffff200008446e70:       b.cs    ffff2000084470f4 <generic_exec_single+0x314>  // b.hs, b.nlast
3288c2ecf20Sopenharmony_ci *
3298c2ecf20Sopenharmony_ci * and skip comma as part of function arguments, e.g.:
3308c2ecf20Sopenharmony_ci * 1d8b4ac <linemap_lookup(line_maps const*, unsigned int)+0xcc>
3318c2ecf20Sopenharmony_ci */
3328c2ecf20Sopenharmony_cistatic inline const char *validate_comma(const char *c, struct ins_operands *ops)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	if (ops->raw_comment && c > ops->raw_comment)
3358c2ecf20Sopenharmony_ci		return NULL;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (ops->raw_func_start && c > ops->raw_func_start)
3388c2ecf20Sopenharmony_ci		return NULL;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	return c;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	struct map *map = ms->map;
3468c2ecf20Sopenharmony_ci	struct symbol *sym = ms->sym;
3478c2ecf20Sopenharmony_ci	struct addr_map_symbol target = {
3488c2ecf20Sopenharmony_ci		.ms = { .map = map, },
3498c2ecf20Sopenharmony_ci	};
3508c2ecf20Sopenharmony_ci	const char *c = strchr(ops->raw, ',');
3518c2ecf20Sopenharmony_ci	u64 start, end;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char);
3548c2ecf20Sopenharmony_ci	ops->raw_func_start = strchr(ops->raw, '<');
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	c = validate_comma(c, ops);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/*
3598c2ecf20Sopenharmony_ci	 * Examples of lines to parse for the _cpp_lex_token@@Base
3608c2ecf20Sopenharmony_ci	 * function:
3618c2ecf20Sopenharmony_ci	 *
3628c2ecf20Sopenharmony_ci	 * 1159e6c: jne    115aa32 <_cpp_lex_token@@Base+0xf92>
3638c2ecf20Sopenharmony_ci	 * 1159e8b: jne    c469be <cpp_named_operator2name@@Base+0xa72>
3648c2ecf20Sopenharmony_ci	 *
3658c2ecf20Sopenharmony_ci	 * The first is a jump to an offset inside the same function,
3668c2ecf20Sopenharmony_ci	 * the second is to another function, i.e. that 0xa72 is an
3678c2ecf20Sopenharmony_ci	 * offset in the cpp_named_operator2name@@base function.
3688c2ecf20Sopenharmony_ci	 */
3698c2ecf20Sopenharmony_ci	/*
3708c2ecf20Sopenharmony_ci	 * skip over possible up to 2 operands to get to address, e.g.:
3718c2ecf20Sopenharmony_ci	 * tbnz	 w0, #26, ffff0000083cd190 <security_file_permission+0xd0>
3728c2ecf20Sopenharmony_ci	 */
3738c2ecf20Sopenharmony_ci	if (c++ != NULL) {
3748c2ecf20Sopenharmony_ci		ops->target.addr = strtoull(c, NULL, 16);
3758c2ecf20Sopenharmony_ci		if (!ops->target.addr) {
3768c2ecf20Sopenharmony_ci			c = strchr(c, ',');
3778c2ecf20Sopenharmony_ci			c = validate_comma(c, ops);
3788c2ecf20Sopenharmony_ci			if (c++ != NULL)
3798c2ecf20Sopenharmony_ci				ops->target.addr = strtoull(c, NULL, 16);
3808c2ecf20Sopenharmony_ci		}
3818c2ecf20Sopenharmony_ci	} else {
3828c2ecf20Sopenharmony_ci		ops->target.addr = strtoull(ops->raw, NULL, 16);
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	target.addr = map__objdump_2mem(map, ops->target.addr);
3868c2ecf20Sopenharmony_ci	start = map->unmap_ip(map, sym->start),
3878c2ecf20Sopenharmony_ci	end = map->unmap_ip(map, sym->end);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	ops->target.outside = target.addr < start || target.addr > end;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/*
3928c2ecf20Sopenharmony_ci	 * FIXME: things like this in _cpp_lex_token (gcc's cc1 program):
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci		cpp_named_operator2name@@Base+0xa72
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	 * Point to a place that is after the cpp_named_operator2name
3978c2ecf20Sopenharmony_ci	 * boundaries, i.e.  in the ELF symbol table for cc1
3988c2ecf20Sopenharmony_ci	 * cpp_named_operator2name is marked as being 32-bytes long, but it in
3998c2ecf20Sopenharmony_ci	 * fact is much larger than that, so we seem to need a symbols__find()
4008c2ecf20Sopenharmony_ci	 * routine that looks for >= current->start and  < next_symbol->start,
4018c2ecf20Sopenharmony_ci	 * possibly just for C++ objects?
4028c2ecf20Sopenharmony_ci	 *
4038c2ecf20Sopenharmony_ci	 * For now lets just make some progress by marking jumps to outside the
4048c2ecf20Sopenharmony_ci	 * current function as call like.
4058c2ecf20Sopenharmony_ci	 *
4068c2ecf20Sopenharmony_ci	 * Actual navigation will come next, with further understanding of how
4078c2ecf20Sopenharmony_ci	 * the symbol searching and disassembly should be done.
4088c2ecf20Sopenharmony_ci	 */
4098c2ecf20Sopenharmony_ci	if (maps__find_ams(ms->maps, &target) == 0 &&
4108c2ecf20Sopenharmony_ci	    map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr)
4118c2ecf20Sopenharmony_ci		ops->target.sym = target.ms.sym;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	if (!ops->target.outside) {
4148c2ecf20Sopenharmony_ci		ops->target.offset = target.addr - start;
4158c2ecf20Sopenharmony_ci		ops->target.offset_avail = true;
4168c2ecf20Sopenharmony_ci	} else {
4178c2ecf20Sopenharmony_ci		ops->target.offset_avail = false;
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	return 0;
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cistatic int jump__scnprintf(struct ins *ins, char *bf, size_t size,
4248c2ecf20Sopenharmony_ci			   struct ins_operands *ops, int max_ins_name)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	const char *c;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	if (!ops->target.addr || ops->target.offset < 0)
4298c2ecf20Sopenharmony_ci		return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	if (ops->target.outside && ops->target.sym != NULL)
4328c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	c = strchr(ops->raw, ',');
4358c2ecf20Sopenharmony_ci	c = validate_comma(c, ops);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	if (c != NULL) {
4388c2ecf20Sopenharmony_ci		const char *c2 = strchr(c + 1, ',');
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci		c2 = validate_comma(c2, ops);
4418c2ecf20Sopenharmony_ci		/* check for 3-op insn */
4428c2ecf20Sopenharmony_ci		if (c2 != NULL)
4438c2ecf20Sopenharmony_ci			c = c2;
4448c2ecf20Sopenharmony_ci		c++;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci		/* mirror arch objdump's space-after-comma style */
4478c2ecf20Sopenharmony_ci		if (*c == ' ')
4488c2ecf20Sopenharmony_ci			c++;
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name,
4528c2ecf20Sopenharmony_ci			 ins->name, c ? c - ops->raw : 0, ops->raw,
4538c2ecf20Sopenharmony_ci			 ops->target.offset);
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic struct ins_ops jump_ops = {
4578c2ecf20Sopenharmony_ci	.parse	   = jump__parse,
4588c2ecf20Sopenharmony_ci	.scnprintf = jump__scnprintf,
4598c2ecf20Sopenharmony_ci};
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_cibool ins__is_jump(const struct ins *ins)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	return ins->ops == &jump_ops;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	char *endptr, *name, *t;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	if (strstr(raw, "(%rip)") == NULL)
4718c2ecf20Sopenharmony_ci		return 0;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	*addrp = strtoull(comment, &endptr, 16);
4748c2ecf20Sopenharmony_ci	if (endptr == comment)
4758c2ecf20Sopenharmony_ci		return 0;
4768c2ecf20Sopenharmony_ci	name = strchr(endptr, '<');
4778c2ecf20Sopenharmony_ci	if (name == NULL)
4788c2ecf20Sopenharmony_ci		return -1;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	name++;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	t = strchr(name, '>');
4838c2ecf20Sopenharmony_ci	if (t == NULL)
4848c2ecf20Sopenharmony_ci		return 0;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	*t = '\0';
4878c2ecf20Sopenharmony_ci	*namep = strdup(name);
4888c2ecf20Sopenharmony_ci	*t = '>';
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	return 0;
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
4968c2ecf20Sopenharmony_ci	if (ops->locked.ops == NULL)
4978c2ecf20Sopenharmony_ci		return 0;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0)
5008c2ecf20Sopenharmony_ci		goto out_free_ops;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	if (ops->locked.ins.ops == NULL)
5058c2ecf20Sopenharmony_ci		goto out_free_ops;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	if (ops->locked.ins.ops->parse &&
5088c2ecf20Sopenharmony_ci	    ops->locked.ins.ops->parse(arch, ops->locked.ops, ms) < 0)
5098c2ecf20Sopenharmony_ci		goto out_free_ops;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	return 0;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ciout_free_ops:
5148c2ecf20Sopenharmony_ci	zfree(&ops->locked.ops);
5158c2ecf20Sopenharmony_ci	return 0;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic int lock__scnprintf(struct ins *ins, char *bf, size_t size,
5198c2ecf20Sopenharmony_ci			   struct ins_operands *ops, int max_ins_name)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	int printed;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (ops->locked.ins.ops == NULL)
5248c2ecf20Sopenharmony_ci		return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	printed = scnprintf(bf, size, "%-*s ", max_ins_name, ins->name);
5278c2ecf20Sopenharmony_ci	return printed + ins__scnprintf(&ops->locked.ins, bf + printed,
5288c2ecf20Sopenharmony_ci					size - printed, ops->locked.ops, max_ins_name);
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic void lock__delete(struct ins_operands *ops)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	struct ins *ins = &ops->locked.ins;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	if (ins->ops && ins->ops->free)
5368c2ecf20Sopenharmony_ci		ins->ops->free(ops->locked.ops);
5378c2ecf20Sopenharmony_ci	else
5388c2ecf20Sopenharmony_ci		ins__delete(ops->locked.ops);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	zfree(&ops->locked.ops);
5418c2ecf20Sopenharmony_ci	zfree(&ops->target.raw);
5428c2ecf20Sopenharmony_ci	zfree(&ops->target.name);
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_cistatic struct ins_ops lock_ops = {
5468c2ecf20Sopenharmony_ci	.free	   = lock__delete,
5478c2ecf20Sopenharmony_ci	.parse	   = lock__parse,
5488c2ecf20Sopenharmony_ci	.scnprintf = lock__scnprintf,
5498c2ecf20Sopenharmony_ci};
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	char *s = strchr(ops->raw, ','), *target, *comment, prev;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	if (s == NULL)
5568c2ecf20Sopenharmony_ci		return -1;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	*s = '\0';
5598c2ecf20Sopenharmony_ci	ops->source.raw = strdup(ops->raw);
5608c2ecf20Sopenharmony_ci	*s = ',';
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (ops->source.raw == NULL)
5638c2ecf20Sopenharmony_ci		return -1;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	target = ++s;
5668c2ecf20Sopenharmony_ci	comment = strchr(s, arch->objdump.comment_char);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	if (comment != NULL)
5698c2ecf20Sopenharmony_ci		s = comment - 1;
5708c2ecf20Sopenharmony_ci	else
5718c2ecf20Sopenharmony_ci		s = strchr(s, '\0') - 1;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	while (s > target && isspace(s[0]))
5748c2ecf20Sopenharmony_ci		--s;
5758c2ecf20Sopenharmony_ci	s++;
5768c2ecf20Sopenharmony_ci	prev = *s;
5778c2ecf20Sopenharmony_ci	*s = '\0';
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	ops->target.raw = strdup(target);
5808c2ecf20Sopenharmony_ci	*s = prev;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	if (ops->target.raw == NULL)
5838c2ecf20Sopenharmony_ci		goto out_free_source;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	if (comment == NULL)
5868c2ecf20Sopenharmony_ci		return 0;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	comment = skip_spaces(comment);
5898c2ecf20Sopenharmony_ci	comment__symbol(ops->source.raw, comment + 1, &ops->source.addr, &ops->source.name);
5908c2ecf20Sopenharmony_ci	comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	return 0;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ciout_free_source:
5958c2ecf20Sopenharmony_ci	zfree(&ops->source.raw);
5968c2ecf20Sopenharmony_ci	return -1;
5978c2ecf20Sopenharmony_ci}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_cistatic int mov__scnprintf(struct ins *ins, char *bf, size_t size,
6008c2ecf20Sopenharmony_ci			   struct ins_operands *ops, int max_ins_name)
6018c2ecf20Sopenharmony_ci{
6028c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "%-*s %s,%s", max_ins_name, ins->name,
6038c2ecf20Sopenharmony_ci			 ops->source.name ?: ops->source.raw,
6048c2ecf20Sopenharmony_ci			 ops->target.name ?: ops->target.raw);
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic struct ins_ops mov_ops = {
6088c2ecf20Sopenharmony_ci	.parse	   = mov__parse,
6098c2ecf20Sopenharmony_ci	.scnprintf = mov__scnprintf,
6108c2ecf20Sopenharmony_ci};
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	char *target, *comment, *s, prev;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	target = s = ops->raw;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	while (s[0] != '\0' && !isspace(s[0]))
6198c2ecf20Sopenharmony_ci		++s;
6208c2ecf20Sopenharmony_ci	prev = *s;
6218c2ecf20Sopenharmony_ci	*s = '\0';
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	ops->target.raw = strdup(target);
6248c2ecf20Sopenharmony_ci	*s = prev;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	if (ops->target.raw == NULL)
6278c2ecf20Sopenharmony_ci		return -1;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	comment = strchr(s, arch->objdump.comment_char);
6308c2ecf20Sopenharmony_ci	if (comment == NULL)
6318c2ecf20Sopenharmony_ci		return 0;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	comment = skip_spaces(comment);
6348c2ecf20Sopenharmony_ci	comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	return 0;
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_cistatic int dec__scnprintf(struct ins *ins, char *bf, size_t size,
6408c2ecf20Sopenharmony_ci			   struct ins_operands *ops, int max_ins_name)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name,
6438c2ecf20Sopenharmony_ci			 ops->target.name ?: ops->target.raw);
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_cistatic struct ins_ops dec_ops = {
6478c2ecf20Sopenharmony_ci	.parse	   = dec__parse,
6488c2ecf20Sopenharmony_ci	.scnprintf = dec__scnprintf,
6498c2ecf20Sopenharmony_ci};
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_cistatic int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size,
6528c2ecf20Sopenharmony_ci			  struct ins_operands *ops __maybe_unused, int max_ins_name)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "%-*s", max_ins_name, "nop");
6558c2ecf20Sopenharmony_ci}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_cistatic struct ins_ops nop_ops = {
6588c2ecf20Sopenharmony_ci	.scnprintf = nop__scnprintf,
6598c2ecf20Sopenharmony_ci};
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic struct ins_ops ret_ops = {
6628c2ecf20Sopenharmony_ci	.scnprintf = ins__raw_scnprintf,
6638c2ecf20Sopenharmony_ci};
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_cibool ins__is_ret(const struct ins *ins)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	return ins->ops == &ret_ops;
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_cibool ins__is_lock(const struct ins *ins)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	return ins->ops == &lock_ops;
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_cistatic int ins__key_cmp(const void *name, const void *insp)
6768c2ecf20Sopenharmony_ci{
6778c2ecf20Sopenharmony_ci	const struct ins *ins = insp;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	return strcmp(name, ins->name);
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic int ins__cmp(const void *a, const void *b)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	const struct ins *ia = a;
6858c2ecf20Sopenharmony_ci	const struct ins *ib = b;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	return strcmp(ia->name, ib->name);
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_cistatic void ins__sort(struct arch *arch)
6918c2ecf20Sopenharmony_ci{
6928c2ecf20Sopenharmony_ci	const int nmemb = arch->nr_instructions;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp);
6958c2ecf20Sopenharmony_ci}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_cistatic struct ins_ops *__ins__find(struct arch *arch, const char *name)
6988c2ecf20Sopenharmony_ci{
6998c2ecf20Sopenharmony_ci	struct ins *ins;
7008c2ecf20Sopenharmony_ci	const int nmemb = arch->nr_instructions;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	if (!arch->sorted_instructions) {
7038c2ecf20Sopenharmony_ci		ins__sort(arch);
7048c2ecf20Sopenharmony_ci		arch->sorted_instructions = true;
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	ins = bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp);
7088c2ecf20Sopenharmony_ci	return ins ? ins->ops : NULL;
7098c2ecf20Sopenharmony_ci}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_cistatic struct ins_ops *ins__find(struct arch *arch, const char *name)
7128c2ecf20Sopenharmony_ci{
7138c2ecf20Sopenharmony_ci	struct ins_ops *ops = __ins__find(arch, name);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	if (!ops && arch->associate_instruction_ops)
7168c2ecf20Sopenharmony_ci		ops = arch->associate_instruction_ops(arch, name);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	return ops;
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic int arch__key_cmp(const void *name, const void *archp)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	const struct arch *arch = archp;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	return strcmp(name, arch->name);
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_cistatic int arch__cmp(const void *a, const void *b)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	const struct arch *aa = a;
7318c2ecf20Sopenharmony_ci	const struct arch *ab = b;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	return strcmp(aa->name, ab->name);
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_cistatic void arch__sort(void)
7378c2ecf20Sopenharmony_ci{
7388c2ecf20Sopenharmony_ci	const int nmemb = ARRAY_SIZE(architectures);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	qsort(architectures, nmemb, sizeof(struct arch), arch__cmp);
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_cistatic struct arch *arch__find(const char *name)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci	const int nmemb = ARRAY_SIZE(architectures);
7468c2ecf20Sopenharmony_ci	static bool sorted;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	if (!sorted) {
7498c2ecf20Sopenharmony_ci		arch__sort();
7508c2ecf20Sopenharmony_ci		sorted = true;
7518c2ecf20Sopenharmony_ci	}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp);
7548c2ecf20Sopenharmony_ci}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic struct annotated_source *annotated_source__new(void)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	struct annotated_source *src = zalloc(sizeof(*src));
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	if (src != NULL)
7618c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&src->source);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	return src;
7648c2ecf20Sopenharmony_ci}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_cistatic __maybe_unused void annotated_source__delete(struct annotated_source *src)
7678c2ecf20Sopenharmony_ci{
7688c2ecf20Sopenharmony_ci	if (src == NULL)
7698c2ecf20Sopenharmony_ci		return;
7708c2ecf20Sopenharmony_ci	zfree(&src->histograms);
7718c2ecf20Sopenharmony_ci	zfree(&src->cycles_hist);
7728c2ecf20Sopenharmony_ci	free(src);
7738c2ecf20Sopenharmony_ci}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic int annotated_source__alloc_histograms(struct annotated_source *src,
7768c2ecf20Sopenharmony_ci					      size_t size, int nr_hists)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	size_t sizeof_sym_hist;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	/*
7818c2ecf20Sopenharmony_ci	 * Add buffer of one element for zero length symbol.
7828c2ecf20Sopenharmony_ci	 * When sample is taken from first instruction of
7838c2ecf20Sopenharmony_ci	 * zero length symbol, perf still resolves it and
7848c2ecf20Sopenharmony_ci	 * shows symbol name in perf report and allows to
7858c2ecf20Sopenharmony_ci	 * annotate it.
7868c2ecf20Sopenharmony_ci	 */
7878c2ecf20Sopenharmony_ci	if (size == 0)
7888c2ecf20Sopenharmony_ci		size = 1;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	/* Check for overflow when calculating sizeof_sym_hist */
7918c2ecf20Sopenharmony_ci	if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(struct sym_hist_entry))
7928c2ecf20Sopenharmony_ci		return -1;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(struct sym_hist_entry));
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	/* Check for overflow in zalloc argument */
7978c2ecf20Sopenharmony_ci	if (sizeof_sym_hist > SIZE_MAX / nr_hists)
7988c2ecf20Sopenharmony_ci		return -1;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	src->sizeof_sym_hist = sizeof_sym_hist;
8018c2ecf20Sopenharmony_ci	src->nr_histograms   = nr_hists;
8028c2ecf20Sopenharmony_ci	src->histograms	     = calloc(nr_hists, sizeof_sym_hist) ;
8038c2ecf20Sopenharmony_ci	return src->histograms ? 0 : -1;
8048c2ecf20Sopenharmony_ci}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci/* The cycles histogram is lazily allocated. */
8078c2ecf20Sopenharmony_cistatic int symbol__alloc_hist_cycles(struct symbol *sym)
8088c2ecf20Sopenharmony_ci{
8098c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
8108c2ecf20Sopenharmony_ci	const size_t size = symbol__size(sym);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	notes->src->cycles_hist = calloc(size, sizeof(struct cyc_hist));
8138c2ecf20Sopenharmony_ci	if (notes->src->cycles_hist == NULL)
8148c2ecf20Sopenharmony_ci		return -1;
8158c2ecf20Sopenharmony_ci	return 0;
8168c2ecf20Sopenharmony_ci}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_civoid symbol__annotate_zero_histograms(struct symbol *sym)
8198c2ecf20Sopenharmony_ci{
8208c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	pthread_mutex_lock(&notes->lock);
8238c2ecf20Sopenharmony_ci	if (notes->src != NULL) {
8248c2ecf20Sopenharmony_ci		memset(notes->src->histograms, 0,
8258c2ecf20Sopenharmony_ci		       notes->src->nr_histograms * notes->src->sizeof_sym_hist);
8268c2ecf20Sopenharmony_ci		if (notes->src->cycles_hist)
8278c2ecf20Sopenharmony_ci			memset(notes->src->cycles_hist, 0,
8288c2ecf20Sopenharmony_ci				symbol__size(sym) * sizeof(struct cyc_hist));
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&notes->lock);
8318c2ecf20Sopenharmony_ci}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_cistatic int __symbol__account_cycles(struct cyc_hist *ch,
8348c2ecf20Sopenharmony_ci				    u64 start,
8358c2ecf20Sopenharmony_ci				    unsigned offset, unsigned cycles,
8368c2ecf20Sopenharmony_ci				    unsigned have_start)
8378c2ecf20Sopenharmony_ci{
8388c2ecf20Sopenharmony_ci	/*
8398c2ecf20Sopenharmony_ci	 * For now we can only account one basic block per
8408c2ecf20Sopenharmony_ci	 * final jump. But multiple could be overlapping.
8418c2ecf20Sopenharmony_ci	 * Always account the longest one. So when
8428c2ecf20Sopenharmony_ci	 * a shorter one has been already seen throw it away.
8438c2ecf20Sopenharmony_ci	 *
8448c2ecf20Sopenharmony_ci	 * We separately always account the full cycles.
8458c2ecf20Sopenharmony_ci	 */
8468c2ecf20Sopenharmony_ci	ch[offset].num_aggr++;
8478c2ecf20Sopenharmony_ci	ch[offset].cycles_aggr += cycles;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	if (cycles > ch[offset].cycles_max)
8508c2ecf20Sopenharmony_ci		ch[offset].cycles_max = cycles;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (ch[offset].cycles_min) {
8538c2ecf20Sopenharmony_ci		if (cycles && cycles < ch[offset].cycles_min)
8548c2ecf20Sopenharmony_ci			ch[offset].cycles_min = cycles;
8558c2ecf20Sopenharmony_ci	} else
8568c2ecf20Sopenharmony_ci		ch[offset].cycles_min = cycles;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	if (!have_start && ch[offset].have_start)
8598c2ecf20Sopenharmony_ci		return 0;
8608c2ecf20Sopenharmony_ci	if (ch[offset].num) {
8618c2ecf20Sopenharmony_ci		if (have_start && (!ch[offset].have_start ||
8628c2ecf20Sopenharmony_ci				   ch[offset].start > start)) {
8638c2ecf20Sopenharmony_ci			ch[offset].have_start = 0;
8648c2ecf20Sopenharmony_ci			ch[offset].cycles = 0;
8658c2ecf20Sopenharmony_ci			ch[offset].num = 0;
8668c2ecf20Sopenharmony_ci			if (ch[offset].reset < 0xffff)
8678c2ecf20Sopenharmony_ci				ch[offset].reset++;
8688c2ecf20Sopenharmony_ci		} else if (have_start &&
8698c2ecf20Sopenharmony_ci			   ch[offset].start < start)
8708c2ecf20Sopenharmony_ci			return 0;
8718c2ecf20Sopenharmony_ci	}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	if (ch[offset].num < NUM_SPARKS)
8748c2ecf20Sopenharmony_ci		ch[offset].cycles_spark[ch[offset].num] = cycles;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	ch[offset].have_start = have_start;
8778c2ecf20Sopenharmony_ci	ch[offset].start = start;
8788c2ecf20Sopenharmony_ci	ch[offset].cycles += cycles;
8798c2ecf20Sopenharmony_ci	ch[offset].num++;
8808c2ecf20Sopenharmony_ci	return 0;
8818c2ecf20Sopenharmony_ci}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cistatic int __symbol__inc_addr_samples(struct map_symbol *ms,
8848c2ecf20Sopenharmony_ci				      struct annotated_source *src, int evidx, u64 addr,
8858c2ecf20Sopenharmony_ci				      struct perf_sample *sample)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	struct symbol *sym = ms->sym;
8888c2ecf20Sopenharmony_ci	unsigned offset;
8898c2ecf20Sopenharmony_ci	struct sym_hist *h;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, ms->map->unmap_ip(ms->map, addr));
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	if ((addr < sym->start || addr >= sym->end) &&
8948c2ecf20Sopenharmony_ci	    (addr != sym->end || sym->start != sym->end)) {
8958c2ecf20Sopenharmony_ci		pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n",
8968c2ecf20Sopenharmony_ci		       __func__, __LINE__, sym->name, sym->start, addr, sym->end);
8978c2ecf20Sopenharmony_ci		return -ERANGE;
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	offset = addr - sym->start;
9018c2ecf20Sopenharmony_ci	h = annotated_source__histogram(src, evidx);
9028c2ecf20Sopenharmony_ci	if (h == NULL) {
9038c2ecf20Sopenharmony_ci		pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n",
9048c2ecf20Sopenharmony_ci			 __func__, __LINE__, sym->name, sym->start, addr, sym->end, sym->type == STT_FUNC);
9058c2ecf20Sopenharmony_ci		return -ENOMEM;
9068c2ecf20Sopenharmony_ci	}
9078c2ecf20Sopenharmony_ci	h->nr_samples++;
9088c2ecf20Sopenharmony_ci	h->addr[offset].nr_samples++;
9098c2ecf20Sopenharmony_ci	h->period += sample->period;
9108c2ecf20Sopenharmony_ci	h->addr[offset].period += sample->period;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
9138c2ecf20Sopenharmony_ci		  ", evidx=%d] => nr_samples: %" PRIu64 ", period: %" PRIu64 "\n",
9148c2ecf20Sopenharmony_ci		  sym->start, sym->name, addr, addr - sym->start, evidx,
9158c2ecf20Sopenharmony_ci		  h->addr[offset].nr_samples, h->addr[offset].period);
9168c2ecf20Sopenharmony_ci	return 0;
9178c2ecf20Sopenharmony_ci}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_cistatic struct cyc_hist *symbol__cycles_hist(struct symbol *sym)
9208c2ecf20Sopenharmony_ci{
9218c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	if (notes->src == NULL) {
9248c2ecf20Sopenharmony_ci		notes->src = annotated_source__new();
9258c2ecf20Sopenharmony_ci		if (notes->src == NULL)
9268c2ecf20Sopenharmony_ci			return NULL;
9278c2ecf20Sopenharmony_ci		goto alloc_cycles_hist;
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	if (!notes->src->cycles_hist) {
9318c2ecf20Sopenharmony_cialloc_cycles_hist:
9328c2ecf20Sopenharmony_ci		symbol__alloc_hist_cycles(sym);
9338c2ecf20Sopenharmony_ci	}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	return notes->src->cycles_hist;
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistruct annotated_source *symbol__hists(struct symbol *sym, int nr_hists)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	if (notes->src == NULL) {
9438c2ecf20Sopenharmony_ci		notes->src = annotated_source__new();
9448c2ecf20Sopenharmony_ci		if (notes->src == NULL)
9458c2ecf20Sopenharmony_ci			return NULL;
9468c2ecf20Sopenharmony_ci		goto alloc_histograms;
9478c2ecf20Sopenharmony_ci	}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	if (notes->src->histograms == NULL) {
9508c2ecf20Sopenharmony_cialloc_histograms:
9518c2ecf20Sopenharmony_ci		annotated_source__alloc_histograms(notes->src, symbol__size(sym),
9528c2ecf20Sopenharmony_ci						   nr_hists);
9538c2ecf20Sopenharmony_ci	}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	return notes->src;
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_cistatic int symbol__inc_addr_samples(struct map_symbol *ms,
9598c2ecf20Sopenharmony_ci				    struct evsel *evsel, u64 addr,
9608c2ecf20Sopenharmony_ci				    struct perf_sample *sample)
9618c2ecf20Sopenharmony_ci{
9628c2ecf20Sopenharmony_ci	struct symbol *sym = ms->sym;
9638c2ecf20Sopenharmony_ci	struct annotated_source *src;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (sym == NULL)
9668c2ecf20Sopenharmony_ci		return 0;
9678c2ecf20Sopenharmony_ci	src = symbol__hists(sym, evsel->evlist->core.nr_entries);
9688c2ecf20Sopenharmony_ci	return src ? __symbol__inc_addr_samples(ms, src, evsel->idx, addr, sample) : 0;
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_cistatic int symbol__account_cycles(u64 addr, u64 start,
9728c2ecf20Sopenharmony_ci				  struct symbol *sym, unsigned cycles)
9738c2ecf20Sopenharmony_ci{
9748c2ecf20Sopenharmony_ci	struct cyc_hist *cycles_hist;
9758c2ecf20Sopenharmony_ci	unsigned offset;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	if (sym == NULL)
9788c2ecf20Sopenharmony_ci		return 0;
9798c2ecf20Sopenharmony_ci	cycles_hist = symbol__cycles_hist(sym);
9808c2ecf20Sopenharmony_ci	if (cycles_hist == NULL)
9818c2ecf20Sopenharmony_ci		return -ENOMEM;
9828c2ecf20Sopenharmony_ci	if (addr < sym->start || addr >= sym->end)
9838c2ecf20Sopenharmony_ci		return -ERANGE;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (start) {
9868c2ecf20Sopenharmony_ci		if (start < sym->start || start >= sym->end)
9878c2ecf20Sopenharmony_ci			return -ERANGE;
9888c2ecf20Sopenharmony_ci		if (start >= addr)
9898c2ecf20Sopenharmony_ci			start = 0;
9908c2ecf20Sopenharmony_ci	}
9918c2ecf20Sopenharmony_ci	offset = addr - sym->start;
9928c2ecf20Sopenharmony_ci	return __symbol__account_cycles(cycles_hist,
9938c2ecf20Sopenharmony_ci					start ? start - sym->start : 0,
9948c2ecf20Sopenharmony_ci					offset, cycles,
9958c2ecf20Sopenharmony_ci					!!start);
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ciint addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
9998c2ecf20Sopenharmony_ci				    struct addr_map_symbol *start,
10008c2ecf20Sopenharmony_ci				    unsigned cycles)
10018c2ecf20Sopenharmony_ci{
10028c2ecf20Sopenharmony_ci	u64 saddr = 0;
10038c2ecf20Sopenharmony_ci	int err;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (!cycles)
10068c2ecf20Sopenharmony_ci		return 0;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/*
10098c2ecf20Sopenharmony_ci	 * Only set start when IPC can be computed. We can only
10108c2ecf20Sopenharmony_ci	 * compute it when the basic block is completely in a single
10118c2ecf20Sopenharmony_ci	 * function.
10128c2ecf20Sopenharmony_ci	 * Special case the case when the jump is elsewhere, but
10138c2ecf20Sopenharmony_ci	 * it starts on the function start.
10148c2ecf20Sopenharmony_ci	 */
10158c2ecf20Sopenharmony_ci	if (start &&
10168c2ecf20Sopenharmony_ci		(start->ms.sym == ams->ms.sym ||
10178c2ecf20Sopenharmony_ci		 (ams->ms.sym &&
10188c2ecf20Sopenharmony_ci		   start->addr == ams->ms.sym->start + ams->ms.map->start)))
10198c2ecf20Sopenharmony_ci		saddr = start->al_addr;
10208c2ecf20Sopenharmony_ci	if (saddr == 0)
10218c2ecf20Sopenharmony_ci		pr_debug2("BB with bad start: addr %"PRIx64" start %"PRIx64" sym %"PRIx64" saddr %"PRIx64"\n",
10228c2ecf20Sopenharmony_ci			ams->addr,
10238c2ecf20Sopenharmony_ci			start ? start->addr : 0,
10248c2ecf20Sopenharmony_ci			ams->ms.sym ? ams->ms.sym->start + ams->ms.map->start : 0,
10258c2ecf20Sopenharmony_ci			saddr);
10268c2ecf20Sopenharmony_ci	err = symbol__account_cycles(ams->al_addr, saddr, ams->ms.sym, cycles);
10278c2ecf20Sopenharmony_ci	if (err)
10288c2ecf20Sopenharmony_ci		pr_debug2("account_cycles failed %d\n", err);
10298c2ecf20Sopenharmony_ci	return err;
10308c2ecf20Sopenharmony_ci}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_cistatic unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 end)
10338c2ecf20Sopenharmony_ci{
10348c2ecf20Sopenharmony_ci	unsigned n_insn = 0;
10358c2ecf20Sopenharmony_ci	u64 offset;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	for (offset = start; offset <= end; offset++) {
10388c2ecf20Sopenharmony_ci		if (notes->offsets[offset])
10398c2ecf20Sopenharmony_ci			n_insn++;
10408c2ecf20Sopenharmony_ci	}
10418c2ecf20Sopenharmony_ci	return n_insn;
10428c2ecf20Sopenharmony_ci}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_cistatic void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	unsigned n_insn;
10478c2ecf20Sopenharmony_ci	unsigned int cover_insn = 0;
10488c2ecf20Sopenharmony_ci	u64 offset;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	n_insn = annotation__count_insn(notes, start, end);
10518c2ecf20Sopenharmony_ci	if (n_insn && ch->num && ch->cycles) {
10528c2ecf20Sopenharmony_ci		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci		/* Hide data when there are too many overlaps. */
10558c2ecf20Sopenharmony_ci		if (ch->reset >= 0x7fff)
10568c2ecf20Sopenharmony_ci			return;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci		for (offset = start; offset <= end; offset++) {
10598c2ecf20Sopenharmony_ci			struct annotation_line *al = notes->offsets[offset];
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci			if (al && al->ipc == 0.0) {
10628c2ecf20Sopenharmony_ci				al->ipc = ipc;
10638c2ecf20Sopenharmony_ci				cover_insn++;
10648c2ecf20Sopenharmony_ci			}
10658c2ecf20Sopenharmony_ci		}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci		if (cover_insn) {
10688c2ecf20Sopenharmony_ci			notes->hit_cycles += ch->cycles;
10698c2ecf20Sopenharmony_ci			notes->hit_insn += n_insn * ch->num;
10708c2ecf20Sopenharmony_ci			notes->cover_insn += cover_insn;
10718c2ecf20Sopenharmony_ci		}
10728c2ecf20Sopenharmony_ci	}
10738c2ecf20Sopenharmony_ci}
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_civoid annotation__compute_ipc(struct annotation *notes, size_t size)
10768c2ecf20Sopenharmony_ci{
10778c2ecf20Sopenharmony_ci	s64 offset;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	if (!notes->src || !notes->src->cycles_hist)
10808c2ecf20Sopenharmony_ci		return;
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	notes->total_insn = annotation__count_insn(notes, 0, size - 1);
10838c2ecf20Sopenharmony_ci	notes->hit_cycles = 0;
10848c2ecf20Sopenharmony_ci	notes->hit_insn = 0;
10858c2ecf20Sopenharmony_ci	notes->cover_insn = 0;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	pthread_mutex_lock(&notes->lock);
10888c2ecf20Sopenharmony_ci	for (offset = size - 1; offset >= 0; --offset) {
10898c2ecf20Sopenharmony_ci		struct cyc_hist *ch;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci		ch = &notes->src->cycles_hist[offset];
10928c2ecf20Sopenharmony_ci		if (ch && ch->cycles) {
10938c2ecf20Sopenharmony_ci			struct annotation_line *al;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci			if (ch->have_start)
10968c2ecf20Sopenharmony_ci				annotation__count_and_fill(notes, ch->start, offset, ch);
10978c2ecf20Sopenharmony_ci			al = notes->offsets[offset];
10988c2ecf20Sopenharmony_ci			if (al && ch->num_aggr) {
10998c2ecf20Sopenharmony_ci				al->cycles = ch->cycles_aggr / ch->num_aggr;
11008c2ecf20Sopenharmony_ci				al->cycles_max = ch->cycles_max;
11018c2ecf20Sopenharmony_ci				al->cycles_min = ch->cycles_min;
11028c2ecf20Sopenharmony_ci			}
11038c2ecf20Sopenharmony_ci			notes->have_cycles = true;
11048c2ecf20Sopenharmony_ci		}
11058c2ecf20Sopenharmony_ci	}
11068c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&notes->lock);
11078c2ecf20Sopenharmony_ci}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ciint addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,
11108c2ecf20Sopenharmony_ci				 struct evsel *evsel)
11118c2ecf20Sopenharmony_ci{
11128c2ecf20Sopenharmony_ci	return symbol__inc_addr_samples(&ams->ms, evsel, ams->al_addr, sample);
11138c2ecf20Sopenharmony_ci}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ciint hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample,
11168c2ecf20Sopenharmony_ci				 struct evsel *evsel, u64 ip)
11178c2ecf20Sopenharmony_ci{
11188c2ecf20Sopenharmony_ci	return symbol__inc_addr_samples(&he->ms, evsel, ip, sample);
11198c2ecf20Sopenharmony_ci}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_cistatic void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	dl->ins.ops = ins__find(arch, dl->ins.name);
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	if (!dl->ins.ops)
11268c2ecf20Sopenharmony_ci		return;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, ms) < 0)
11298c2ecf20Sopenharmony_ci		dl->ins.ops = NULL;
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_cistatic int disasm_line__parse(char *line, const char **namep, char **rawp)
11338c2ecf20Sopenharmony_ci{
11348c2ecf20Sopenharmony_ci	char tmp, *name = skip_spaces(line);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	if (name[0] == '\0')
11378c2ecf20Sopenharmony_ci		return -1;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	*rawp = name + 1;
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
11428c2ecf20Sopenharmony_ci		++*rawp;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	tmp = (*rawp)[0];
11458c2ecf20Sopenharmony_ci	(*rawp)[0] = '\0';
11468c2ecf20Sopenharmony_ci	*namep = strdup(name);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	if (*namep == NULL)
11498c2ecf20Sopenharmony_ci		goto out;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	(*rawp)[0] = tmp;
11528c2ecf20Sopenharmony_ci	*rawp = strim(*rawp);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	return 0;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ciout:
11578c2ecf20Sopenharmony_ci	return -1;
11588c2ecf20Sopenharmony_ci}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_cistruct annotate_args {
11618c2ecf20Sopenharmony_ci	struct arch		  *arch;
11628c2ecf20Sopenharmony_ci	struct map_symbol	  ms;
11638c2ecf20Sopenharmony_ci	struct evsel		  *evsel;
11648c2ecf20Sopenharmony_ci	struct annotation_options *options;
11658c2ecf20Sopenharmony_ci	s64			  offset;
11668c2ecf20Sopenharmony_ci	char			  *line;
11678c2ecf20Sopenharmony_ci	int			  line_nr;
11688c2ecf20Sopenharmony_ci};
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_cistatic void annotation_line__init(struct annotation_line *al,
11718c2ecf20Sopenharmony_ci				  struct annotate_args *args,
11728c2ecf20Sopenharmony_ci				  int nr)
11738c2ecf20Sopenharmony_ci{
11748c2ecf20Sopenharmony_ci	al->offset = args->offset;
11758c2ecf20Sopenharmony_ci	al->line = strdup(args->line);
11768c2ecf20Sopenharmony_ci	al->line_nr = args->line_nr;
11778c2ecf20Sopenharmony_ci	al->data_nr = nr;
11788c2ecf20Sopenharmony_ci}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_cistatic void annotation_line__exit(struct annotation_line *al)
11818c2ecf20Sopenharmony_ci{
11828c2ecf20Sopenharmony_ci	free_srcline(al->path);
11838c2ecf20Sopenharmony_ci	zfree(&al->line);
11848c2ecf20Sopenharmony_ci}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_cistatic size_t disasm_line_size(int nr)
11878c2ecf20Sopenharmony_ci{
11888c2ecf20Sopenharmony_ci	struct annotation_line *al;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	return (sizeof(struct disasm_line) + (sizeof(al->data[0]) * nr));
11918c2ecf20Sopenharmony_ci}
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci/*
11948c2ecf20Sopenharmony_ci * Allocating the disasm annotation line data with
11958c2ecf20Sopenharmony_ci * following structure:
11968c2ecf20Sopenharmony_ci *
11978c2ecf20Sopenharmony_ci *    -------------------------------------------
11988c2ecf20Sopenharmony_ci *    struct disasm_line | struct annotation_line
11998c2ecf20Sopenharmony_ci *    -------------------------------------------
12008c2ecf20Sopenharmony_ci *
12018c2ecf20Sopenharmony_ci * We have 'struct annotation_line' member as last member
12028c2ecf20Sopenharmony_ci * of 'struct disasm_line' to have an easy access.
12038c2ecf20Sopenharmony_ci */
12048c2ecf20Sopenharmony_cistatic struct disasm_line *disasm_line__new(struct annotate_args *args)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	struct disasm_line *dl = NULL;
12078c2ecf20Sopenharmony_ci	int nr = 1;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	if (evsel__is_group_event(args->evsel))
12108c2ecf20Sopenharmony_ci		nr = args->evsel->core.nr_members;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	dl = zalloc(disasm_line_size(nr));
12138c2ecf20Sopenharmony_ci	if (!dl)
12148c2ecf20Sopenharmony_ci		return NULL;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	annotation_line__init(&dl->al, args, nr);
12178c2ecf20Sopenharmony_ci	if (dl->al.line == NULL)
12188c2ecf20Sopenharmony_ci		goto out_delete;
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	if (args->offset != -1) {
12218c2ecf20Sopenharmony_ci		if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
12228c2ecf20Sopenharmony_ci			goto out_free_line;
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci		disasm_line__init_ins(dl, args->arch, &args->ms);
12258c2ecf20Sopenharmony_ci	}
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	return dl;
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ciout_free_line:
12308c2ecf20Sopenharmony_ci	zfree(&dl->al.line);
12318c2ecf20Sopenharmony_ciout_delete:
12328c2ecf20Sopenharmony_ci	free(dl);
12338c2ecf20Sopenharmony_ci	return NULL;
12348c2ecf20Sopenharmony_ci}
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_civoid disasm_line__free(struct disasm_line *dl)
12378c2ecf20Sopenharmony_ci{
12388c2ecf20Sopenharmony_ci	if (dl->ins.ops && dl->ins.ops->free)
12398c2ecf20Sopenharmony_ci		dl->ins.ops->free(&dl->ops);
12408c2ecf20Sopenharmony_ci	else
12418c2ecf20Sopenharmony_ci		ins__delete(&dl->ops);
12428c2ecf20Sopenharmony_ci	zfree(&dl->ins.name);
12438c2ecf20Sopenharmony_ci	annotation_line__exit(&dl->al);
12448c2ecf20Sopenharmony_ci	free(dl);
12458c2ecf20Sopenharmony_ci}
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ciint disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	if (raw || !dl->ins.ops)
12508c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "%-*s %s", max_ins_name, dl->ins.name, dl->ops.raw);
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	return ins__scnprintf(&dl->ins, bf, size, &dl->ops, max_ins_name);
12538c2ecf20Sopenharmony_ci}
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_cistatic void annotation_line__add(struct annotation_line *al, struct list_head *head)
12568c2ecf20Sopenharmony_ci{
12578c2ecf20Sopenharmony_ci	list_add_tail(&al->node, head);
12588c2ecf20Sopenharmony_ci}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cistruct annotation_line *
12618c2ecf20Sopenharmony_ciannotation_line__next(struct annotation_line *pos, struct list_head *head)
12628c2ecf20Sopenharmony_ci{
12638c2ecf20Sopenharmony_ci	list_for_each_entry_continue(pos, head, node)
12648c2ecf20Sopenharmony_ci		if (pos->offset >= 0)
12658c2ecf20Sopenharmony_ci			return pos;
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	return NULL;
12688c2ecf20Sopenharmony_ci}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_cistatic const char *annotate__address_color(struct block_range *br)
12718c2ecf20Sopenharmony_ci{
12728c2ecf20Sopenharmony_ci	double cov = block_range__coverage(br);
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	if (cov >= 0) {
12758c2ecf20Sopenharmony_ci		/* mark red for >75% coverage */
12768c2ecf20Sopenharmony_ci		if (cov > 0.75)
12778c2ecf20Sopenharmony_ci			return PERF_COLOR_RED;
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci		/* mark dull for <1% coverage */
12808c2ecf20Sopenharmony_ci		if (cov < 0.01)
12818c2ecf20Sopenharmony_ci			return PERF_COLOR_NORMAL;
12828c2ecf20Sopenharmony_ci	}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	return PERF_COLOR_MAGENTA;
12858c2ecf20Sopenharmony_ci}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_cistatic const char *annotate__asm_color(struct block_range *br)
12888c2ecf20Sopenharmony_ci{
12898c2ecf20Sopenharmony_ci	double cov = block_range__coverage(br);
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	if (cov >= 0) {
12928c2ecf20Sopenharmony_ci		/* mark dull for <1% coverage */
12938c2ecf20Sopenharmony_ci		if (cov < 0.01)
12948c2ecf20Sopenharmony_ci			return PERF_COLOR_NORMAL;
12958c2ecf20Sopenharmony_ci	}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	return PERF_COLOR_BLUE;
12988c2ecf20Sopenharmony_ci}
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_cistatic void annotate__branch_printf(struct block_range *br, u64 addr)
13018c2ecf20Sopenharmony_ci{
13028c2ecf20Sopenharmony_ci	bool emit_comment = true;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	if (!br)
13058c2ecf20Sopenharmony_ci		return;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci#if 1
13088c2ecf20Sopenharmony_ci	if (br->is_target && br->start == addr) {
13098c2ecf20Sopenharmony_ci		struct block_range *branch = br;
13108c2ecf20Sopenharmony_ci		double p;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci		/*
13138c2ecf20Sopenharmony_ci		 * Find matching branch to our target.
13148c2ecf20Sopenharmony_ci		 */
13158c2ecf20Sopenharmony_ci		while (!branch->is_branch)
13168c2ecf20Sopenharmony_ci			branch = block_range__next(branch);
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci		p = 100 *(double)br->entry / branch->coverage;
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci		if (p > 0.1) {
13218c2ecf20Sopenharmony_ci			if (emit_comment) {
13228c2ecf20Sopenharmony_ci				emit_comment = false;
13238c2ecf20Sopenharmony_ci				printf("\t#");
13248c2ecf20Sopenharmony_ci			}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci			/*
13278c2ecf20Sopenharmony_ci			 * The percentage of coverage joined at this target in relation
13288c2ecf20Sopenharmony_ci			 * to the next branch.
13298c2ecf20Sopenharmony_ci			 */
13308c2ecf20Sopenharmony_ci			printf(" +%.2f%%", p);
13318c2ecf20Sopenharmony_ci		}
13328c2ecf20Sopenharmony_ci	}
13338c2ecf20Sopenharmony_ci#endif
13348c2ecf20Sopenharmony_ci	if (br->is_branch && br->end == addr) {
13358c2ecf20Sopenharmony_ci		double p = 100*(double)br->taken / br->coverage;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci		if (p > 0.1) {
13388c2ecf20Sopenharmony_ci			if (emit_comment) {
13398c2ecf20Sopenharmony_ci				emit_comment = false;
13408c2ecf20Sopenharmony_ci				printf("\t#");
13418c2ecf20Sopenharmony_ci			}
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci			/*
13448c2ecf20Sopenharmony_ci			 * The percentage of coverage leaving at this branch, and
13458c2ecf20Sopenharmony_ci			 * its prediction ratio.
13468c2ecf20Sopenharmony_ci			 */
13478c2ecf20Sopenharmony_ci			printf(" -%.2f%% (p:%.2f%%)", p, 100*(double)br->pred  / br->taken);
13488c2ecf20Sopenharmony_ci		}
13498c2ecf20Sopenharmony_ci	}
13508c2ecf20Sopenharmony_ci}
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_cistatic int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_width)
13538c2ecf20Sopenharmony_ci{
13548c2ecf20Sopenharmony_ci	s64 offset = dl->al.offset;
13558c2ecf20Sopenharmony_ci	const u64 addr = start + offset;
13568c2ecf20Sopenharmony_ci	struct block_range *br;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	br = block_range__find(addr);
13598c2ecf20Sopenharmony_ci	color_fprintf(stdout, annotate__address_color(br), "  %*" PRIx64 ":", addr_fmt_width, addr);
13608c2ecf20Sopenharmony_ci	color_fprintf(stdout, annotate__asm_color(br), "%s", dl->al.line);
13618c2ecf20Sopenharmony_ci	annotate__branch_printf(br, addr);
13628c2ecf20Sopenharmony_ci	return 0;
13638c2ecf20Sopenharmony_ci}
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_cistatic int
13668c2ecf20Sopenharmony_ciannotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start,
13678c2ecf20Sopenharmony_ci		       struct evsel *evsel, u64 len, int min_pcnt, int printed,
13688c2ecf20Sopenharmony_ci		       int max_lines, struct annotation_line *queue, int addr_fmt_width,
13698c2ecf20Sopenharmony_ci		       int percent_type)
13708c2ecf20Sopenharmony_ci{
13718c2ecf20Sopenharmony_ci	struct disasm_line *dl = container_of(al, struct disasm_line, al);
13728c2ecf20Sopenharmony_ci	static const char *prev_line;
13738c2ecf20Sopenharmony_ci	static const char *prev_color;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	if (al->offset != -1) {
13768c2ecf20Sopenharmony_ci		double max_percent = 0.0;
13778c2ecf20Sopenharmony_ci		int i, nr_percent = 1;
13788c2ecf20Sopenharmony_ci		const char *color;
13798c2ecf20Sopenharmony_ci		struct annotation *notes = symbol__annotation(sym);
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci		for (i = 0; i < al->data_nr; i++) {
13828c2ecf20Sopenharmony_ci			double percent;
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci			percent = annotation_data__percent(&al->data[i],
13858c2ecf20Sopenharmony_ci							   percent_type);
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci			if (percent > max_percent)
13888c2ecf20Sopenharmony_ci				max_percent = percent;
13898c2ecf20Sopenharmony_ci		}
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci		if (al->data_nr > nr_percent)
13928c2ecf20Sopenharmony_ci			nr_percent = al->data_nr;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci		if (max_percent < min_pcnt)
13958c2ecf20Sopenharmony_ci			return -1;
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci		if (max_lines && printed >= max_lines)
13988c2ecf20Sopenharmony_ci			return 1;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci		if (queue != NULL) {
14018c2ecf20Sopenharmony_ci			list_for_each_entry_from(queue, &notes->src->source, node) {
14028c2ecf20Sopenharmony_ci				if (queue == al)
14038c2ecf20Sopenharmony_ci					break;
14048c2ecf20Sopenharmony_ci				annotation_line__print(queue, sym, start, evsel, len,
14058c2ecf20Sopenharmony_ci						       0, 0, 1, NULL, addr_fmt_width,
14068c2ecf20Sopenharmony_ci						       percent_type);
14078c2ecf20Sopenharmony_ci			}
14088c2ecf20Sopenharmony_ci		}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci		color = get_percent_color(max_percent);
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci		/*
14138c2ecf20Sopenharmony_ci		 * Also color the filename and line if needed, with
14148c2ecf20Sopenharmony_ci		 * the same color than the percentage. Don't print it
14158c2ecf20Sopenharmony_ci		 * twice for close colored addr with the same filename:line
14168c2ecf20Sopenharmony_ci		 */
14178c2ecf20Sopenharmony_ci		if (al->path) {
14188c2ecf20Sopenharmony_ci			if (!prev_line || strcmp(prev_line, al->path)
14198c2ecf20Sopenharmony_ci				       || color != prev_color) {
14208c2ecf20Sopenharmony_ci				color_fprintf(stdout, color, " %s", al->path);
14218c2ecf20Sopenharmony_ci				prev_line = al->path;
14228c2ecf20Sopenharmony_ci				prev_color = color;
14238c2ecf20Sopenharmony_ci			}
14248c2ecf20Sopenharmony_ci		}
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci		for (i = 0; i < nr_percent; i++) {
14278c2ecf20Sopenharmony_ci			struct annotation_data *data = &al->data[i];
14288c2ecf20Sopenharmony_ci			double percent;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci			percent = annotation_data__percent(data, percent_type);
14318c2ecf20Sopenharmony_ci			color = get_percent_color(percent);
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci			if (symbol_conf.show_total_period)
14348c2ecf20Sopenharmony_ci				color_fprintf(stdout, color, " %11" PRIu64,
14358c2ecf20Sopenharmony_ci					      data->he.period);
14368c2ecf20Sopenharmony_ci			else if (symbol_conf.show_nr_samples)
14378c2ecf20Sopenharmony_ci				color_fprintf(stdout, color, " %7" PRIu64,
14388c2ecf20Sopenharmony_ci					      data->he.nr_samples);
14398c2ecf20Sopenharmony_ci			else
14408c2ecf20Sopenharmony_ci				color_fprintf(stdout, color, " %7.2f", percent);
14418c2ecf20Sopenharmony_ci		}
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci		printf(" : ");
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci		disasm_line__print(dl, start, addr_fmt_width);
14468c2ecf20Sopenharmony_ci		printf("\n");
14478c2ecf20Sopenharmony_ci	} else if (max_lines && printed >= max_lines)
14488c2ecf20Sopenharmony_ci		return 1;
14498c2ecf20Sopenharmony_ci	else {
14508c2ecf20Sopenharmony_ci		int width = symbol_conf.show_total_period ? 12 : 8;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci		if (queue)
14538c2ecf20Sopenharmony_ci			return -1;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci		if (evsel__is_group_event(evsel))
14568c2ecf20Sopenharmony_ci			width *= evsel->core.nr_members;
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci		if (!*al->line)
14598c2ecf20Sopenharmony_ci			printf(" %*s:\n", width, " ");
14608c2ecf20Sopenharmony_ci		else
14618c2ecf20Sopenharmony_ci			printf(" %*s:     %*s %s\n", width, " ", addr_fmt_width, " ", al->line);
14628c2ecf20Sopenharmony_ci	}
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	return 0;
14658c2ecf20Sopenharmony_ci}
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci/*
14688c2ecf20Sopenharmony_ci * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw)
14698c2ecf20Sopenharmony_ci * which looks like following
14708c2ecf20Sopenharmony_ci *
14718c2ecf20Sopenharmony_ci *  0000000000415500 <_init>:
14728c2ecf20Sopenharmony_ci *    415500:       sub    $0x8,%rsp
14738c2ecf20Sopenharmony_ci *    415504:       mov    0x2f5ad5(%rip),%rax        # 70afe0 <_DYNAMIC+0x2f8>
14748c2ecf20Sopenharmony_ci *    41550b:       test   %rax,%rax
14758c2ecf20Sopenharmony_ci *    41550e:       je     415515 <_init+0x15>
14768c2ecf20Sopenharmony_ci *    415510:       callq  416e70 <__gmon_start__@plt>
14778c2ecf20Sopenharmony_ci *    415515:       add    $0x8,%rsp
14788c2ecf20Sopenharmony_ci *    415519:       retq
14798c2ecf20Sopenharmony_ci *
14808c2ecf20Sopenharmony_ci * it will be parsed and saved into struct disasm_line as
14818c2ecf20Sopenharmony_ci *  <offset>       <name>  <ops.raw>
14828c2ecf20Sopenharmony_ci *
14838c2ecf20Sopenharmony_ci * The offset will be a relative offset from the start of the symbol and -1
14848c2ecf20Sopenharmony_ci * means that it's not a disassembly line so should be treated differently.
14858c2ecf20Sopenharmony_ci * The ops.raw part will be parsed further according to type of the instruction.
14868c2ecf20Sopenharmony_ci */
14878c2ecf20Sopenharmony_cistatic int symbol__parse_objdump_line(struct symbol *sym,
14888c2ecf20Sopenharmony_ci				      struct annotate_args *args,
14898c2ecf20Sopenharmony_ci				      char *parsed_line, int *line_nr)
14908c2ecf20Sopenharmony_ci{
14918c2ecf20Sopenharmony_ci	struct map *map = args->ms.map;
14928c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
14938c2ecf20Sopenharmony_ci	struct disasm_line *dl;
14948c2ecf20Sopenharmony_ci	char *tmp;
14958c2ecf20Sopenharmony_ci	s64 line_ip, offset = -1;
14968c2ecf20Sopenharmony_ci	regmatch_t match[2];
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	/* /filename:linenr ? Save line number and ignore. */
14998c2ecf20Sopenharmony_ci	if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) {
15008c2ecf20Sopenharmony_ci		*line_nr = atoi(parsed_line + match[1].rm_so);
15018c2ecf20Sopenharmony_ci		return 0;
15028c2ecf20Sopenharmony_ci	}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	/* Process hex address followed by ':'. */
15058c2ecf20Sopenharmony_ci	line_ip = strtoull(parsed_line, &tmp, 16);
15068c2ecf20Sopenharmony_ci	if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') {
15078c2ecf20Sopenharmony_ci		u64 start = map__rip_2objdump(map, sym->start),
15088c2ecf20Sopenharmony_ci		    end = map__rip_2objdump(map, sym->end);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci		offset = line_ip - start;
15118c2ecf20Sopenharmony_ci		if ((u64)line_ip < start || (u64)line_ip >= end)
15128c2ecf20Sopenharmony_ci			offset = -1;
15138c2ecf20Sopenharmony_ci		else
15148c2ecf20Sopenharmony_ci			parsed_line = tmp + 1;
15158c2ecf20Sopenharmony_ci	}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	args->offset  = offset;
15188c2ecf20Sopenharmony_ci	args->line    = parsed_line;
15198c2ecf20Sopenharmony_ci	args->line_nr = *line_nr;
15208c2ecf20Sopenharmony_ci	args->ms.sym  = sym;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	dl = disasm_line__new(args);
15238c2ecf20Sopenharmony_ci	(*line_nr)++;
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	if (dl == NULL)
15268c2ecf20Sopenharmony_ci		return -1;
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	if (!disasm_line__has_local_offset(dl)) {
15298c2ecf20Sopenharmony_ci		dl->ops.target.offset = dl->ops.target.addr -
15308c2ecf20Sopenharmony_ci					map__rip_2objdump(map, sym->start);
15318c2ecf20Sopenharmony_ci		dl->ops.target.offset_avail = true;
15328c2ecf20Sopenharmony_ci	}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	/* kcore has no symbols, so add the call target symbol */
15358c2ecf20Sopenharmony_ci	if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.sym) {
15368c2ecf20Sopenharmony_ci		struct addr_map_symbol target = {
15378c2ecf20Sopenharmony_ci			.addr = dl->ops.target.addr,
15388c2ecf20Sopenharmony_ci			.ms = { .map = map, },
15398c2ecf20Sopenharmony_ci		};
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci		if (!maps__find_ams(args->ms.maps, &target) &&
15428c2ecf20Sopenharmony_ci		    target.ms.sym->start == target.al_addr)
15438c2ecf20Sopenharmony_ci			dl->ops.target.sym = target.ms.sym;
15448c2ecf20Sopenharmony_ci	}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	annotation_line__add(&dl->al, &notes->src->source);
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	return 0;
15498c2ecf20Sopenharmony_ci}
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_cistatic __attribute__((constructor)) void symbol__init_regexpr(void)
15528c2ecf20Sopenharmony_ci{
15538c2ecf20Sopenharmony_ci	regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED);
15548c2ecf20Sopenharmony_ci}
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_cistatic void delete_last_nop(struct symbol *sym)
15578c2ecf20Sopenharmony_ci{
15588c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
15598c2ecf20Sopenharmony_ci	struct list_head *list = &notes->src->source;
15608c2ecf20Sopenharmony_ci	struct disasm_line *dl;
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	while (!list_empty(list)) {
15638c2ecf20Sopenharmony_ci		dl = list_entry(list->prev, struct disasm_line, al.node);
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci		if (dl->ins.ops) {
15668c2ecf20Sopenharmony_ci			if (dl->ins.ops != &nop_ops)
15678c2ecf20Sopenharmony_ci				return;
15688c2ecf20Sopenharmony_ci		} else {
15698c2ecf20Sopenharmony_ci			if (!strstr(dl->al.line, " nop ") &&
15708c2ecf20Sopenharmony_ci			    !strstr(dl->al.line, " nopl ") &&
15718c2ecf20Sopenharmony_ci			    !strstr(dl->al.line, " nopw "))
15728c2ecf20Sopenharmony_ci				return;
15738c2ecf20Sopenharmony_ci		}
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci		list_del_init(&dl->al.node);
15768c2ecf20Sopenharmony_ci		disasm_line__free(dl);
15778c2ecf20Sopenharmony_ci	}
15788c2ecf20Sopenharmony_ci}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ciint symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen)
15818c2ecf20Sopenharmony_ci{
15828c2ecf20Sopenharmony_ci	struct dso *dso = ms->map->dso;
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	BUG_ON(buflen == 0);
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	if (errnum >= 0) {
15878c2ecf20Sopenharmony_ci		str_error_r(errnum, buf, buflen);
15888c2ecf20Sopenharmony_ci		return 0;
15898c2ecf20Sopenharmony_ci	}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	switch (errnum) {
15928c2ecf20Sopenharmony_ci	case SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX: {
15938c2ecf20Sopenharmony_ci		char bf[SBUILD_ID_SIZE + 15] = " with build id ";
15948c2ecf20Sopenharmony_ci		char *build_id_msg = NULL;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci		if (dso->has_build_id) {
15978c2ecf20Sopenharmony_ci			build_id__sprintf(&dso->bid, bf + 15);
15988c2ecf20Sopenharmony_ci			build_id_msg = bf;
15998c2ecf20Sopenharmony_ci		}
16008c2ecf20Sopenharmony_ci		scnprintf(buf, buflen,
16018c2ecf20Sopenharmony_ci			  "No vmlinux file%s\nwas found in the path.\n\n"
16028c2ecf20Sopenharmony_ci			  "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n"
16038c2ecf20Sopenharmony_ci			  "Please use:\n\n"
16048c2ecf20Sopenharmony_ci			  "  perf buildid-cache -vu vmlinux\n\n"
16058c2ecf20Sopenharmony_ci			  "or:\n\n"
16068c2ecf20Sopenharmony_ci			  "  --vmlinux vmlinux\n", build_id_msg ?: "");
16078c2ecf20Sopenharmony_ci	}
16088c2ecf20Sopenharmony_ci		break;
16098c2ecf20Sopenharmony_ci	case SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF:
16108c2ecf20Sopenharmony_ci		scnprintf(buf, buflen, "Please link with binutils's libopcode to enable BPF annotation");
16118c2ecf20Sopenharmony_ci		break;
16128c2ecf20Sopenharmony_ci	case SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_REGEXP:
16138c2ecf20Sopenharmony_ci		scnprintf(buf, buflen, "Problems with arch specific instruction name regular expressions.");
16148c2ecf20Sopenharmony_ci		break;
16158c2ecf20Sopenharmony_ci	case SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING:
16168c2ecf20Sopenharmony_ci		scnprintf(buf, buflen, "Problems while parsing the CPUID in the arch specific initialization.");
16178c2ecf20Sopenharmony_ci		break;
16188c2ecf20Sopenharmony_ci	case SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE:
16198c2ecf20Sopenharmony_ci		scnprintf(buf, buflen, "Invalid BPF file: %s.", dso->long_name);
16208c2ecf20Sopenharmony_ci		break;
16218c2ecf20Sopenharmony_ci	case SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF:
16228c2ecf20Sopenharmony_ci		scnprintf(buf, buflen, "The %s BPF file has no BTF section, compile with -g or use pahole -J.",
16238c2ecf20Sopenharmony_ci			  dso->long_name);
16248c2ecf20Sopenharmony_ci		break;
16258c2ecf20Sopenharmony_ci	default:
16268c2ecf20Sopenharmony_ci		scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum);
16278c2ecf20Sopenharmony_ci		break;
16288c2ecf20Sopenharmony_ci	}
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	return 0;
16318c2ecf20Sopenharmony_ci}
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_cistatic int dso__disassemble_filename(struct dso *dso, char *filename, size_t filename_size)
16348c2ecf20Sopenharmony_ci{
16358c2ecf20Sopenharmony_ci	char linkname[PATH_MAX];
16368c2ecf20Sopenharmony_ci	char *build_id_filename;
16378c2ecf20Sopenharmony_ci	char *build_id_path = NULL;
16388c2ecf20Sopenharmony_ci	char *pos;
16398c2ecf20Sopenharmony_ci	int len;
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
16428c2ecf20Sopenharmony_ci	    !dso__is_kcore(dso))
16438c2ecf20Sopenharmony_ci		return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	build_id_filename = dso__build_id_filename(dso, NULL, 0, false);
16468c2ecf20Sopenharmony_ci	if (build_id_filename) {
16478c2ecf20Sopenharmony_ci		__symbol__join_symfs(filename, filename_size, build_id_filename);
16488c2ecf20Sopenharmony_ci		free(build_id_filename);
16498c2ecf20Sopenharmony_ci	} else {
16508c2ecf20Sopenharmony_ci		if (dso->has_build_id)
16518c2ecf20Sopenharmony_ci			return ENOMEM;
16528c2ecf20Sopenharmony_ci		goto fallback;
16538c2ecf20Sopenharmony_ci	}
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	build_id_path = strdup(filename);
16568c2ecf20Sopenharmony_ci	if (!build_id_path)
16578c2ecf20Sopenharmony_ci		return ENOMEM;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	/*
16608c2ecf20Sopenharmony_ci	 * old style build-id cache has name of XX/XXXXXXX.. while
16618c2ecf20Sopenharmony_ci	 * new style has XX/XXXXXXX../{elf,kallsyms,vdso}.
16628c2ecf20Sopenharmony_ci	 * extract the build-id part of dirname in the new style only.
16638c2ecf20Sopenharmony_ci	 */
16648c2ecf20Sopenharmony_ci	pos = strrchr(build_id_path, '/');
16658c2ecf20Sopenharmony_ci	if (pos && strlen(pos) < SBUILD_ID_SIZE - 2)
16668c2ecf20Sopenharmony_ci		dirname(build_id_path);
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	if (dso__is_kcore(dso))
16698c2ecf20Sopenharmony_ci		goto fallback;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	len = readlink(build_id_path, linkname, sizeof(linkname) - 1);
16728c2ecf20Sopenharmony_ci	if (len < 0)
16738c2ecf20Sopenharmony_ci		goto fallback;
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	linkname[len] = '\0';
16768c2ecf20Sopenharmony_ci	if (strstr(linkname, DSO__NAME_KALLSYMS) ||
16778c2ecf20Sopenharmony_ci		access(filename, R_OK)) {
16788c2ecf20Sopenharmony_cifallback:
16798c2ecf20Sopenharmony_ci		/*
16808c2ecf20Sopenharmony_ci		 * If we don't have build-ids or the build-id file isn't in the
16818c2ecf20Sopenharmony_ci		 * cache, or is just a kallsyms file, well, lets hope that this
16828c2ecf20Sopenharmony_ci		 * DSO is the same as when 'perf record' ran.
16838c2ecf20Sopenharmony_ci		 */
16848c2ecf20Sopenharmony_ci		__symbol__join_symfs(filename, filename_size, dso->long_name);
16858c2ecf20Sopenharmony_ci	}
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	free(build_id_path);
16888c2ecf20Sopenharmony_ci	return 0;
16898c2ecf20Sopenharmony_ci}
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci#if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
16928c2ecf20Sopenharmony_ci#define PACKAGE "perf"
16938c2ecf20Sopenharmony_ci#include <bfd.h>
16948c2ecf20Sopenharmony_ci#include <dis-asm.h>
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_cistatic int symbol__disassemble_bpf(struct symbol *sym,
16978c2ecf20Sopenharmony_ci				   struct annotate_args *args)
16988c2ecf20Sopenharmony_ci{
16998c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
17008c2ecf20Sopenharmony_ci	struct annotation_options *opts = args->options;
17018c2ecf20Sopenharmony_ci	struct bpf_prog_info_linear *info_linear;
17028c2ecf20Sopenharmony_ci	struct bpf_prog_linfo *prog_linfo = NULL;
17038c2ecf20Sopenharmony_ci	struct bpf_prog_info_node *info_node;
17048c2ecf20Sopenharmony_ci	int len = sym->end - sym->start;
17058c2ecf20Sopenharmony_ci	disassembler_ftype disassemble;
17068c2ecf20Sopenharmony_ci	struct map *map = args->ms.map;
17078c2ecf20Sopenharmony_ci	struct disassemble_info info;
17088c2ecf20Sopenharmony_ci	struct dso *dso = map->dso;
17098c2ecf20Sopenharmony_ci	int pc = 0, count, sub_id;
17108c2ecf20Sopenharmony_ci	struct btf *btf = NULL;
17118c2ecf20Sopenharmony_ci	char tpath[PATH_MAX];
17128c2ecf20Sopenharmony_ci	size_t buf_size;
17138c2ecf20Sopenharmony_ci	int nr_skip = 0;
17148c2ecf20Sopenharmony_ci	char *buf;
17158c2ecf20Sopenharmony_ci	bfd *bfdf;
17168c2ecf20Sopenharmony_ci	int ret;
17178c2ecf20Sopenharmony_ci	FILE *s;
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
17208c2ecf20Sopenharmony_ci		return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE;
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func__,
17238c2ecf20Sopenharmony_ci		  sym->name, sym->start, sym->end - sym->start);
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	memset(tpath, 0, sizeof(tpath));
17268c2ecf20Sopenharmony_ci	perf_exe(tpath, sizeof(tpath));
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	bfdf = bfd_openr(tpath, NULL);
17298c2ecf20Sopenharmony_ci	if (bfdf == NULL)
17308c2ecf20Sopenharmony_ci		abort();
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	if (!bfd_check_format(bfdf, bfd_object))
17338c2ecf20Sopenharmony_ci		abort();
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	s = open_memstream(&buf, &buf_size);
17368c2ecf20Sopenharmony_ci	if (!s) {
17378c2ecf20Sopenharmony_ci		ret = errno;
17388c2ecf20Sopenharmony_ci		goto out;
17398c2ecf20Sopenharmony_ci	}
17408c2ecf20Sopenharmony_ci	init_disassemble_info(&info, s,
17418c2ecf20Sopenharmony_ci			      (fprintf_ftype) fprintf);
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	info.arch = bfd_get_arch(bfdf);
17448c2ecf20Sopenharmony_ci	info.mach = bfd_get_mach(bfdf);
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
17478c2ecf20Sopenharmony_ci						 dso->bpf_prog.id);
17488c2ecf20Sopenharmony_ci	if (!info_node) {
17498c2ecf20Sopenharmony_ci		ret = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF;
17508c2ecf20Sopenharmony_ci		goto out;
17518c2ecf20Sopenharmony_ci	}
17528c2ecf20Sopenharmony_ci	info_linear = info_node->info_linear;
17538c2ecf20Sopenharmony_ci	sub_id = dso->bpf_prog.sub_id;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	info.buffer = (void *)(uintptr_t)(info_linear->info.jited_prog_insns);
17568c2ecf20Sopenharmony_ci	info.buffer_length = info_linear->info.jited_prog_len;
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	if (info_linear->info.nr_line_info)
17598c2ecf20Sopenharmony_ci		prog_linfo = bpf_prog_linfo__new(&info_linear->info);
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	if (info_linear->info.btf_id) {
17628c2ecf20Sopenharmony_ci		struct btf_node *node;
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci		node = perf_env__find_btf(dso->bpf_prog.env,
17658c2ecf20Sopenharmony_ci					  info_linear->info.btf_id);
17668c2ecf20Sopenharmony_ci		if (node)
17678c2ecf20Sopenharmony_ci			btf = btf__new((__u8 *)(node->data),
17688c2ecf20Sopenharmony_ci				       node->data_size);
17698c2ecf20Sopenharmony_ci	}
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	disassemble_init_for_target(&info);
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci#ifdef DISASM_FOUR_ARGS_SIGNATURE
17748c2ecf20Sopenharmony_ci	disassemble = disassembler(info.arch,
17758c2ecf20Sopenharmony_ci				   bfd_big_endian(bfdf),
17768c2ecf20Sopenharmony_ci				   info.mach,
17778c2ecf20Sopenharmony_ci				   bfdf);
17788c2ecf20Sopenharmony_ci#else
17798c2ecf20Sopenharmony_ci	disassemble = disassembler(bfdf);
17808c2ecf20Sopenharmony_ci#endif
17818c2ecf20Sopenharmony_ci	if (disassemble == NULL)
17828c2ecf20Sopenharmony_ci		abort();
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	fflush(s);
17858c2ecf20Sopenharmony_ci	do {
17868c2ecf20Sopenharmony_ci		const struct bpf_line_info *linfo = NULL;
17878c2ecf20Sopenharmony_ci		struct disasm_line *dl;
17888c2ecf20Sopenharmony_ci		size_t prev_buf_size;
17898c2ecf20Sopenharmony_ci		const char *srcline;
17908c2ecf20Sopenharmony_ci		u64 addr;
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci		addr = pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id];
17938c2ecf20Sopenharmony_ci		count = disassemble(pc, &info);
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci		if (prog_linfo)
17968c2ecf20Sopenharmony_ci			linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
17978c2ecf20Sopenharmony_ci								addr, sub_id,
17988c2ecf20Sopenharmony_ci								nr_skip);
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci		if (linfo && btf) {
18018c2ecf20Sopenharmony_ci			srcline = btf__name_by_offset(btf, linfo->line_off);
18028c2ecf20Sopenharmony_ci			nr_skip++;
18038c2ecf20Sopenharmony_ci		} else
18048c2ecf20Sopenharmony_ci			srcline = NULL;
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci		fprintf(s, "\n");
18078c2ecf20Sopenharmony_ci		prev_buf_size = buf_size;
18088c2ecf20Sopenharmony_ci		fflush(s);
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci		if (!opts->hide_src_code && srcline) {
18118c2ecf20Sopenharmony_ci			args->offset = -1;
18128c2ecf20Sopenharmony_ci			args->line = strdup(srcline);
18138c2ecf20Sopenharmony_ci			args->line_nr = 0;
18148c2ecf20Sopenharmony_ci			args->ms.sym  = sym;
18158c2ecf20Sopenharmony_ci			dl = disasm_line__new(args);
18168c2ecf20Sopenharmony_ci			if (dl) {
18178c2ecf20Sopenharmony_ci				annotation_line__add(&dl->al,
18188c2ecf20Sopenharmony_ci						     &notes->src->source);
18198c2ecf20Sopenharmony_ci			}
18208c2ecf20Sopenharmony_ci		}
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci		args->offset = pc;
18238c2ecf20Sopenharmony_ci		args->line = buf + prev_buf_size;
18248c2ecf20Sopenharmony_ci		args->line_nr = 0;
18258c2ecf20Sopenharmony_ci		args->ms.sym  = sym;
18268c2ecf20Sopenharmony_ci		dl = disasm_line__new(args);
18278c2ecf20Sopenharmony_ci		if (dl)
18288c2ecf20Sopenharmony_ci			annotation_line__add(&dl->al, &notes->src->source);
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci		pc += count;
18318c2ecf20Sopenharmony_ci	} while (count > 0 && pc < len);
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	ret = 0;
18348c2ecf20Sopenharmony_ciout:
18358c2ecf20Sopenharmony_ci	free(prog_linfo);
18368c2ecf20Sopenharmony_ci	free(btf);
18378c2ecf20Sopenharmony_ci	fclose(s);
18388c2ecf20Sopenharmony_ci	bfd_close(bfdf);
18398c2ecf20Sopenharmony_ci	return ret;
18408c2ecf20Sopenharmony_ci}
18418c2ecf20Sopenharmony_ci#else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
18428c2ecf20Sopenharmony_cistatic int symbol__disassemble_bpf(struct symbol *sym __maybe_unused,
18438c2ecf20Sopenharmony_ci				   struct annotate_args *args __maybe_unused)
18448c2ecf20Sopenharmony_ci{
18458c2ecf20Sopenharmony_ci	return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF;
18468c2ecf20Sopenharmony_ci}
18478c2ecf20Sopenharmony_ci#endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_cistatic int
18508c2ecf20Sopenharmony_cisymbol__disassemble_bpf_image(struct symbol *sym,
18518c2ecf20Sopenharmony_ci			      struct annotate_args *args)
18528c2ecf20Sopenharmony_ci{
18538c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
18548c2ecf20Sopenharmony_ci	struct disasm_line *dl;
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	args->offset = -1;
18578c2ecf20Sopenharmony_ci	args->line = strdup("to be implemented");
18588c2ecf20Sopenharmony_ci	args->line_nr = 0;
18598c2ecf20Sopenharmony_ci	dl = disasm_line__new(args);
18608c2ecf20Sopenharmony_ci	if (dl)
18618c2ecf20Sopenharmony_ci		annotation_line__add(&dl->al, &notes->src->source);
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci	free(args->line);
18648c2ecf20Sopenharmony_ci	return 0;
18658c2ecf20Sopenharmony_ci}
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci/*
18688c2ecf20Sopenharmony_ci * Possibly create a new version of line with tabs expanded. Returns the
18698c2ecf20Sopenharmony_ci * existing or new line, storage is updated if a new line is allocated. If
18708c2ecf20Sopenharmony_ci * allocation fails then NULL is returned.
18718c2ecf20Sopenharmony_ci */
18728c2ecf20Sopenharmony_cistatic char *expand_tabs(char *line, char **storage, size_t *storage_len)
18738c2ecf20Sopenharmony_ci{
18748c2ecf20Sopenharmony_ci	size_t i, src, dst, len, new_storage_len, num_tabs;
18758c2ecf20Sopenharmony_ci	char *new_line;
18768c2ecf20Sopenharmony_ci	size_t line_len = strlen(line);
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	for (num_tabs = 0, i = 0; i < line_len; i++)
18798c2ecf20Sopenharmony_ci		if (line[i] == '\t')
18808c2ecf20Sopenharmony_ci			num_tabs++;
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	if (num_tabs == 0)
18838c2ecf20Sopenharmony_ci		return line;
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	/*
18868c2ecf20Sopenharmony_ci	 * Space for the line and '\0', less the leading and trailing
18878c2ecf20Sopenharmony_ci	 * spaces. Each tab may introduce 7 additional spaces.
18888c2ecf20Sopenharmony_ci	 */
18898c2ecf20Sopenharmony_ci	new_storage_len = line_len + 1 + (num_tabs * 7);
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	new_line = malloc(new_storage_len);
18928c2ecf20Sopenharmony_ci	if (new_line == NULL) {
18938c2ecf20Sopenharmony_ci		pr_err("Failure allocating memory for tab expansion\n");
18948c2ecf20Sopenharmony_ci		return NULL;
18958c2ecf20Sopenharmony_ci	}
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	/*
18988c2ecf20Sopenharmony_ci	 * Copy regions starting at src and expand tabs. If there are two
18998c2ecf20Sopenharmony_ci	 * adjacent tabs then 'src == i', the memcpy is of size 0 and the spaces
19008c2ecf20Sopenharmony_ci	 * are inserted.
19018c2ecf20Sopenharmony_ci	 */
19028c2ecf20Sopenharmony_ci	for (i = 0, src = 0, dst = 0; i < line_len && num_tabs; i++) {
19038c2ecf20Sopenharmony_ci		if (line[i] == '\t') {
19048c2ecf20Sopenharmony_ci			len = i - src;
19058c2ecf20Sopenharmony_ci			memcpy(&new_line[dst], &line[src], len);
19068c2ecf20Sopenharmony_ci			dst += len;
19078c2ecf20Sopenharmony_ci			new_line[dst++] = ' ';
19088c2ecf20Sopenharmony_ci			while (dst % 8 != 0)
19098c2ecf20Sopenharmony_ci				new_line[dst++] = ' ';
19108c2ecf20Sopenharmony_ci			src = i + 1;
19118c2ecf20Sopenharmony_ci			num_tabs--;
19128c2ecf20Sopenharmony_ci		}
19138c2ecf20Sopenharmony_ci	}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	/* Expand the last region. */
19168c2ecf20Sopenharmony_ci	len = line_len - src;
19178c2ecf20Sopenharmony_ci	memcpy(&new_line[dst], &line[src], len);
19188c2ecf20Sopenharmony_ci	dst += len;
19198c2ecf20Sopenharmony_ci	new_line[dst] = '\0';
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci	free(*storage);
19228c2ecf20Sopenharmony_ci	*storage = new_line;
19238c2ecf20Sopenharmony_ci	*storage_len = new_storage_len;
19248c2ecf20Sopenharmony_ci	return new_line;
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci}
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_cistatic int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
19298c2ecf20Sopenharmony_ci{
19308c2ecf20Sopenharmony_ci	struct annotation_options *opts = args->options;
19318c2ecf20Sopenharmony_ci	struct map *map = args->ms.map;
19328c2ecf20Sopenharmony_ci	struct dso *dso = map->dso;
19338c2ecf20Sopenharmony_ci	char *command;
19348c2ecf20Sopenharmony_ci	FILE *file;
19358c2ecf20Sopenharmony_ci	char symfs_filename[PATH_MAX];
19368c2ecf20Sopenharmony_ci	struct kcore_extract kce;
19378c2ecf20Sopenharmony_ci	bool delete_extract = false;
19388c2ecf20Sopenharmony_ci	bool decomp = false;
19398c2ecf20Sopenharmony_ci	int lineno = 0;
19408c2ecf20Sopenharmony_ci	int nline;
19418c2ecf20Sopenharmony_ci	char *line;
19428c2ecf20Sopenharmony_ci	size_t line_len;
19438c2ecf20Sopenharmony_ci	const char *objdump_argv[] = {
19448c2ecf20Sopenharmony_ci		"/bin/sh",
19458c2ecf20Sopenharmony_ci		"-c",
19468c2ecf20Sopenharmony_ci		NULL, /* Will be the objdump command to run. */
19478c2ecf20Sopenharmony_ci		"--",
19488c2ecf20Sopenharmony_ci		NULL, /* Will be the symfs path. */
19498c2ecf20Sopenharmony_ci		NULL,
19508c2ecf20Sopenharmony_ci	};
19518c2ecf20Sopenharmony_ci	struct child_process objdump_process;
19528c2ecf20Sopenharmony_ci	int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	if (err)
19558c2ecf20Sopenharmony_ci		return err;
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
19588c2ecf20Sopenharmony_ci		 symfs_filename, sym->name, map->unmap_ip(map, sym->start),
19598c2ecf20Sopenharmony_ci		 map->unmap_ip(map, sym->end));
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	pr_debug("annotating [%p] %30s : [%p] %30s\n",
19628c2ecf20Sopenharmony_ci		 dso, dso->long_name, sym, sym->name);
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci	if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
19658c2ecf20Sopenharmony_ci		return symbol__disassemble_bpf(sym, args);
19668c2ecf20Sopenharmony_ci	} else if (dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) {
19678c2ecf20Sopenharmony_ci		return symbol__disassemble_bpf_image(sym, args);
19688c2ecf20Sopenharmony_ci	} else if (dso__is_kcore(dso)) {
19698c2ecf20Sopenharmony_ci		kce.kcore_filename = symfs_filename;
19708c2ecf20Sopenharmony_ci		kce.addr = map__rip_2objdump(map, sym->start);
19718c2ecf20Sopenharmony_ci		kce.offs = sym->start;
19728c2ecf20Sopenharmony_ci		kce.len = sym->end - sym->start;
19738c2ecf20Sopenharmony_ci		if (!kcore_extract__create(&kce)) {
19748c2ecf20Sopenharmony_ci			delete_extract = true;
19758c2ecf20Sopenharmony_ci			strlcpy(symfs_filename, kce.extract_filename,
19768c2ecf20Sopenharmony_ci				sizeof(symfs_filename));
19778c2ecf20Sopenharmony_ci		}
19788c2ecf20Sopenharmony_ci	} else if (dso__needs_decompress(dso)) {
19798c2ecf20Sopenharmony_ci		char tmp[KMOD_DECOMP_LEN];
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci		if (dso__decompress_kmodule_path(dso, symfs_filename,
19828c2ecf20Sopenharmony_ci						 tmp, sizeof(tmp)) < 0)
19838c2ecf20Sopenharmony_ci			return -1;
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci		decomp = true;
19868c2ecf20Sopenharmony_ci		strcpy(symfs_filename, tmp);
19878c2ecf20Sopenharmony_ci	}
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	err = asprintf(&command,
19908c2ecf20Sopenharmony_ci		 "%s %s%s --start-address=0x%016" PRIx64
19918c2ecf20Sopenharmony_ci		 " --stop-address=0x%016" PRIx64
19928c2ecf20Sopenharmony_ci		 " -l -d %s %s %s %c%s%c %s%s -C \"$1\"",
19938c2ecf20Sopenharmony_ci		 opts->objdump_path ?: "objdump",
19948c2ecf20Sopenharmony_ci		 opts->disassembler_style ? "-M " : "",
19958c2ecf20Sopenharmony_ci		 opts->disassembler_style ?: "",
19968c2ecf20Sopenharmony_ci		 map__rip_2objdump(map, sym->start),
19978c2ecf20Sopenharmony_ci		 map__rip_2objdump(map, sym->end),
19988c2ecf20Sopenharmony_ci		 opts->show_asm_raw ? "" : "--no-show-raw-insn",
19998c2ecf20Sopenharmony_ci		 opts->annotate_src ? "-S" : "",
20008c2ecf20Sopenharmony_ci		 opts->prefix ? "--prefix " : "",
20018c2ecf20Sopenharmony_ci		 opts->prefix ? '"' : ' ',
20028c2ecf20Sopenharmony_ci		 opts->prefix ?: "",
20038c2ecf20Sopenharmony_ci		 opts->prefix ? '"' : ' ',
20048c2ecf20Sopenharmony_ci		 opts->prefix_strip ? "--prefix-strip=" : "",
20058c2ecf20Sopenharmony_ci		 opts->prefix_strip ?: "");
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci	if (err < 0) {
20088c2ecf20Sopenharmony_ci		pr_err("Failure allocating memory for the command to run\n");
20098c2ecf20Sopenharmony_ci		goto out_remove_tmp;
20108c2ecf20Sopenharmony_ci	}
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci	pr_debug("Executing: %s\n", command);
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci	objdump_argv[2] = command;
20158c2ecf20Sopenharmony_ci	objdump_argv[4] = symfs_filename;
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci	/* Create a pipe to read from for stdout */
20188c2ecf20Sopenharmony_ci	memset(&objdump_process, 0, sizeof(objdump_process));
20198c2ecf20Sopenharmony_ci	objdump_process.argv = objdump_argv;
20208c2ecf20Sopenharmony_ci	objdump_process.out = -1;
20218c2ecf20Sopenharmony_ci	if (start_command(&objdump_process)) {
20228c2ecf20Sopenharmony_ci		pr_err("Failure starting to run %s\n", command);
20238c2ecf20Sopenharmony_ci		err = -1;
20248c2ecf20Sopenharmony_ci		goto out_free_command;
20258c2ecf20Sopenharmony_ci	}
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci	file = fdopen(objdump_process.out, "r");
20288c2ecf20Sopenharmony_ci	if (!file) {
20298c2ecf20Sopenharmony_ci		pr_err("Failure creating FILE stream for %s\n", command);
20308c2ecf20Sopenharmony_ci		/*
20318c2ecf20Sopenharmony_ci		 * If we were using debug info should retry with
20328c2ecf20Sopenharmony_ci		 * original binary.
20338c2ecf20Sopenharmony_ci		 */
20348c2ecf20Sopenharmony_ci		err = -1;
20358c2ecf20Sopenharmony_ci		goto out_close_stdout;
20368c2ecf20Sopenharmony_ci	}
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	/* Storage for getline. */
20398c2ecf20Sopenharmony_ci	line = NULL;
20408c2ecf20Sopenharmony_ci	line_len = 0;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	nline = 0;
20438c2ecf20Sopenharmony_ci	while (!feof(file)) {
20448c2ecf20Sopenharmony_ci		const char *match;
20458c2ecf20Sopenharmony_ci		char *expanded_line;
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci		if (getline(&line, &line_len, file) < 0 || !line)
20488c2ecf20Sopenharmony_ci			break;
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci		/* Skip lines containing "filename:" */
20518c2ecf20Sopenharmony_ci		match = strstr(line, symfs_filename);
20528c2ecf20Sopenharmony_ci		if (match && match[strlen(symfs_filename)] == ':')
20538c2ecf20Sopenharmony_ci			continue;
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci		expanded_line = strim(line);
20568c2ecf20Sopenharmony_ci		expanded_line = expand_tabs(expanded_line, &line, &line_len);
20578c2ecf20Sopenharmony_ci		if (!expanded_line)
20588c2ecf20Sopenharmony_ci			break;
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci		/*
20618c2ecf20Sopenharmony_ci		 * The source code line number (lineno) needs to be kept in
20628c2ecf20Sopenharmony_ci		 * across calls to symbol__parse_objdump_line(), so that it
20638c2ecf20Sopenharmony_ci		 * can associate it with the instructions till the next one.
20648c2ecf20Sopenharmony_ci		 * See disasm_line__new() and struct disasm_line::line_nr.
20658c2ecf20Sopenharmony_ci		 */
20668c2ecf20Sopenharmony_ci		if (symbol__parse_objdump_line(sym, args, expanded_line,
20678c2ecf20Sopenharmony_ci					       &lineno) < 0)
20688c2ecf20Sopenharmony_ci			break;
20698c2ecf20Sopenharmony_ci		nline++;
20708c2ecf20Sopenharmony_ci	}
20718c2ecf20Sopenharmony_ci	free(line);
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci	err = finish_command(&objdump_process);
20748c2ecf20Sopenharmony_ci	if (err)
20758c2ecf20Sopenharmony_ci		pr_err("Error running %s\n", command);
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	if (nline == 0) {
20788c2ecf20Sopenharmony_ci		err = -1;
20798c2ecf20Sopenharmony_ci		pr_err("No output from %s\n", command);
20808c2ecf20Sopenharmony_ci	}
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	/*
20838c2ecf20Sopenharmony_ci	 * kallsyms does not have symbol sizes so there may a nop at the end.
20848c2ecf20Sopenharmony_ci	 * Remove it.
20858c2ecf20Sopenharmony_ci	 */
20868c2ecf20Sopenharmony_ci	if (dso__is_kcore(dso))
20878c2ecf20Sopenharmony_ci		delete_last_nop(sym);
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	fclose(file);
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_ciout_close_stdout:
20928c2ecf20Sopenharmony_ci	close(objdump_process.out);
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ciout_free_command:
20958c2ecf20Sopenharmony_ci	free(command);
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ciout_remove_tmp:
20988c2ecf20Sopenharmony_ci	if (decomp)
20998c2ecf20Sopenharmony_ci		unlink(symfs_filename);
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	if (delete_extract)
21028c2ecf20Sopenharmony_ci		kcore_extract__delete(&kce);
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	return err;
21058c2ecf20Sopenharmony_ci}
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_cistatic void calc_percent(struct sym_hist *sym_hist,
21088c2ecf20Sopenharmony_ci			 struct hists *hists,
21098c2ecf20Sopenharmony_ci			 struct annotation_data *data,
21108c2ecf20Sopenharmony_ci			 s64 offset, s64 end)
21118c2ecf20Sopenharmony_ci{
21128c2ecf20Sopenharmony_ci	unsigned int hits = 0;
21138c2ecf20Sopenharmony_ci	u64 period = 0;
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	while (offset < end) {
21168c2ecf20Sopenharmony_ci		hits   += sym_hist->addr[offset].nr_samples;
21178c2ecf20Sopenharmony_ci		period += sym_hist->addr[offset].period;
21188c2ecf20Sopenharmony_ci		++offset;
21198c2ecf20Sopenharmony_ci	}
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	if (sym_hist->nr_samples) {
21228c2ecf20Sopenharmony_ci		data->he.period     = period;
21238c2ecf20Sopenharmony_ci		data->he.nr_samples = hits;
21248c2ecf20Sopenharmony_ci		data->percent[PERCENT_HITS_LOCAL] = 100.0 * hits / sym_hist->nr_samples;
21258c2ecf20Sopenharmony_ci	}
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	if (hists->stats.nr_non_filtered_samples)
21288c2ecf20Sopenharmony_ci		data->percent[PERCENT_HITS_GLOBAL] = 100.0 * hits / hists->stats.nr_non_filtered_samples;
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci	if (sym_hist->period)
21318c2ecf20Sopenharmony_ci		data->percent[PERCENT_PERIOD_LOCAL] = 100.0 * period / sym_hist->period;
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	if (hists->stats.total_period)
21348c2ecf20Sopenharmony_ci		data->percent[PERCENT_PERIOD_GLOBAL] = 100.0 * period / hists->stats.total_period;
21358c2ecf20Sopenharmony_ci}
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_cistatic void annotation__calc_percent(struct annotation *notes,
21388c2ecf20Sopenharmony_ci				     struct evsel *leader, s64 len)
21398c2ecf20Sopenharmony_ci{
21408c2ecf20Sopenharmony_ci	struct annotation_line *al, *next;
21418c2ecf20Sopenharmony_ci	struct evsel *evsel;
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci	list_for_each_entry(al, &notes->src->source, node) {
21448c2ecf20Sopenharmony_ci		s64 end;
21458c2ecf20Sopenharmony_ci		int i = 0;
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_ci		if (al->offset == -1)
21488c2ecf20Sopenharmony_ci			continue;
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci		next = annotation_line__next(al, &notes->src->source);
21518c2ecf20Sopenharmony_ci		end  = next ? next->offset : len;
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci		for_each_group_evsel(evsel, leader) {
21548c2ecf20Sopenharmony_ci			struct hists *hists = evsel__hists(evsel);
21558c2ecf20Sopenharmony_ci			struct annotation_data *data;
21568c2ecf20Sopenharmony_ci			struct sym_hist *sym_hist;
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci			BUG_ON(i >= al->data_nr);
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci			sym_hist = annotation__histogram(notes, evsel->idx);
21618c2ecf20Sopenharmony_ci			data = &al->data[i++];
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci			calc_percent(sym_hist, hists, data, al->offset, end);
21648c2ecf20Sopenharmony_ci		}
21658c2ecf20Sopenharmony_ci	}
21668c2ecf20Sopenharmony_ci}
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_civoid symbol__calc_percent(struct symbol *sym, struct evsel *evsel)
21698c2ecf20Sopenharmony_ci{
21708c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	annotation__calc_percent(notes, evsel, symbol__size(sym));
21738c2ecf20Sopenharmony_ci}
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ciint symbol__annotate(struct map_symbol *ms, struct evsel *evsel,
21768c2ecf20Sopenharmony_ci		     struct annotation_options *options, struct arch **parch)
21778c2ecf20Sopenharmony_ci{
21788c2ecf20Sopenharmony_ci	struct symbol *sym = ms->sym;
21798c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
21808c2ecf20Sopenharmony_ci	struct annotate_args args = {
21818c2ecf20Sopenharmony_ci		.evsel		= evsel,
21828c2ecf20Sopenharmony_ci		.options	= options,
21838c2ecf20Sopenharmony_ci	};
21848c2ecf20Sopenharmony_ci	struct perf_env *env = evsel__env(evsel);
21858c2ecf20Sopenharmony_ci	const char *arch_name = perf_env__arch(env);
21868c2ecf20Sopenharmony_ci	struct arch *arch;
21878c2ecf20Sopenharmony_ci	int err;
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	if (!arch_name)
21908c2ecf20Sopenharmony_ci		return errno;
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	args.arch = arch = arch__find(arch_name);
21938c2ecf20Sopenharmony_ci	if (arch == NULL) {
21948c2ecf20Sopenharmony_ci		pr_err("%s: unsupported arch %s\n", __func__, arch_name);
21958c2ecf20Sopenharmony_ci		return ENOTSUP;
21968c2ecf20Sopenharmony_ci	}
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	if (parch)
21998c2ecf20Sopenharmony_ci		*parch = arch;
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci	if (arch->init) {
22028c2ecf20Sopenharmony_ci		err = arch->init(arch, env ? env->cpuid : NULL);
22038c2ecf20Sopenharmony_ci		if (err) {
22048c2ecf20Sopenharmony_ci			pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name);
22058c2ecf20Sopenharmony_ci			return err;
22068c2ecf20Sopenharmony_ci		}
22078c2ecf20Sopenharmony_ci	}
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	args.ms = *ms;
22108c2ecf20Sopenharmony_ci	notes->start = map__rip_2objdump(ms->map, sym->start);
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_ci	return symbol__disassemble(sym, &args);
22138c2ecf20Sopenharmony_ci}
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_cistatic void insert_source_line(struct rb_root *root, struct annotation_line *al,
22168c2ecf20Sopenharmony_ci			       struct annotation_options *opts)
22178c2ecf20Sopenharmony_ci{
22188c2ecf20Sopenharmony_ci	struct annotation_line *iter;
22198c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_node;
22208c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
22218c2ecf20Sopenharmony_ci	int i, ret;
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	while (*p != NULL) {
22248c2ecf20Sopenharmony_ci		parent = *p;
22258c2ecf20Sopenharmony_ci		iter = rb_entry(parent, struct annotation_line, rb_node);
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci		ret = strcmp(iter->path, al->path);
22288c2ecf20Sopenharmony_ci		if (ret == 0) {
22298c2ecf20Sopenharmony_ci			for (i = 0; i < al->data_nr; i++) {
22308c2ecf20Sopenharmony_ci				iter->data[i].percent_sum += annotation_data__percent(&al->data[i],
22318c2ecf20Sopenharmony_ci										      opts->percent_type);
22328c2ecf20Sopenharmony_ci			}
22338c2ecf20Sopenharmony_ci			return;
22348c2ecf20Sopenharmony_ci		}
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci		if (ret < 0)
22378c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
22388c2ecf20Sopenharmony_ci		else
22398c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
22408c2ecf20Sopenharmony_ci	}
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	for (i = 0; i < al->data_nr; i++) {
22438c2ecf20Sopenharmony_ci		al->data[i].percent_sum = annotation_data__percent(&al->data[i],
22448c2ecf20Sopenharmony_ci								   opts->percent_type);
22458c2ecf20Sopenharmony_ci	}
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	rb_link_node(&al->rb_node, parent, p);
22488c2ecf20Sopenharmony_ci	rb_insert_color(&al->rb_node, root);
22498c2ecf20Sopenharmony_ci}
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_cistatic int cmp_source_line(struct annotation_line *a, struct annotation_line *b)
22528c2ecf20Sopenharmony_ci{
22538c2ecf20Sopenharmony_ci	int i;
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	for (i = 0; i < a->data_nr; i++) {
22568c2ecf20Sopenharmony_ci		if (a->data[i].percent_sum == b->data[i].percent_sum)
22578c2ecf20Sopenharmony_ci			continue;
22588c2ecf20Sopenharmony_ci		return a->data[i].percent_sum > b->data[i].percent_sum;
22598c2ecf20Sopenharmony_ci	}
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci	return 0;
22628c2ecf20Sopenharmony_ci}
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_cistatic void __resort_source_line(struct rb_root *root, struct annotation_line *al)
22658c2ecf20Sopenharmony_ci{
22668c2ecf20Sopenharmony_ci	struct annotation_line *iter;
22678c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_node;
22688c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci	while (*p != NULL) {
22718c2ecf20Sopenharmony_ci		parent = *p;
22728c2ecf20Sopenharmony_ci		iter = rb_entry(parent, struct annotation_line, rb_node);
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci		if (cmp_source_line(al, iter))
22758c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
22768c2ecf20Sopenharmony_ci		else
22778c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
22788c2ecf20Sopenharmony_ci	}
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_ci	rb_link_node(&al->rb_node, parent, p);
22818c2ecf20Sopenharmony_ci	rb_insert_color(&al->rb_node, root);
22828c2ecf20Sopenharmony_ci}
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_cistatic void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
22858c2ecf20Sopenharmony_ci{
22868c2ecf20Sopenharmony_ci	struct annotation_line *al;
22878c2ecf20Sopenharmony_ci	struct rb_node *node;
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci	node = rb_first(src_root);
22908c2ecf20Sopenharmony_ci	while (node) {
22918c2ecf20Sopenharmony_ci		struct rb_node *next;
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci		al = rb_entry(node, struct annotation_line, rb_node);
22948c2ecf20Sopenharmony_ci		next = rb_next(node);
22958c2ecf20Sopenharmony_ci		rb_erase(node, src_root);
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci		__resort_source_line(dest_root, al);
22988c2ecf20Sopenharmony_ci		node = next;
22998c2ecf20Sopenharmony_ci	}
23008c2ecf20Sopenharmony_ci}
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_cistatic void print_summary(struct rb_root *root, const char *filename)
23038c2ecf20Sopenharmony_ci{
23048c2ecf20Sopenharmony_ci	struct annotation_line *al;
23058c2ecf20Sopenharmony_ci	struct rb_node *node;
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci	printf("\nSorted summary for file %s\n", filename);
23088c2ecf20Sopenharmony_ci	printf("----------------------------------------------\n\n");
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_ci	if (RB_EMPTY_ROOT(root)) {
23118c2ecf20Sopenharmony_ci		printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
23128c2ecf20Sopenharmony_ci		return;
23138c2ecf20Sopenharmony_ci	}
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_ci	node = rb_first(root);
23168c2ecf20Sopenharmony_ci	while (node) {
23178c2ecf20Sopenharmony_ci		double percent, percent_max = 0.0;
23188c2ecf20Sopenharmony_ci		const char *color;
23198c2ecf20Sopenharmony_ci		char *path;
23208c2ecf20Sopenharmony_ci		int i;
23218c2ecf20Sopenharmony_ci
23228c2ecf20Sopenharmony_ci		al = rb_entry(node, struct annotation_line, rb_node);
23238c2ecf20Sopenharmony_ci		for (i = 0; i < al->data_nr; i++) {
23248c2ecf20Sopenharmony_ci			percent = al->data[i].percent_sum;
23258c2ecf20Sopenharmony_ci			color = get_percent_color(percent);
23268c2ecf20Sopenharmony_ci			color_fprintf(stdout, color, " %7.2f", percent);
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci			if (percent > percent_max)
23298c2ecf20Sopenharmony_ci				percent_max = percent;
23308c2ecf20Sopenharmony_ci		}
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci		path = al->path;
23338c2ecf20Sopenharmony_ci		color = get_percent_color(percent_max);
23348c2ecf20Sopenharmony_ci		color_fprintf(stdout, color, " %s\n", path);
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci		node = rb_next(node);
23378c2ecf20Sopenharmony_ci	}
23388c2ecf20Sopenharmony_ci}
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_cistatic void symbol__annotate_hits(struct symbol *sym, struct evsel *evsel)
23418c2ecf20Sopenharmony_ci{
23428c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
23438c2ecf20Sopenharmony_ci	struct sym_hist *h = annotation__histogram(notes, evsel->idx);
23448c2ecf20Sopenharmony_ci	u64 len = symbol__size(sym), offset;
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	for (offset = 0; offset < len; ++offset)
23478c2ecf20Sopenharmony_ci		if (h->addr[offset].nr_samples != 0)
23488c2ecf20Sopenharmony_ci			printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
23498c2ecf20Sopenharmony_ci			       sym->start + offset, h->addr[offset].nr_samples);
23508c2ecf20Sopenharmony_ci	printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples);
23518c2ecf20Sopenharmony_ci}
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_cistatic int annotated_source__addr_fmt_width(struct list_head *lines, u64 start)
23548c2ecf20Sopenharmony_ci{
23558c2ecf20Sopenharmony_ci	char bf[32];
23568c2ecf20Sopenharmony_ci	struct annotation_line *line;
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	list_for_each_entry_reverse(line, lines, node) {
23598c2ecf20Sopenharmony_ci		if (line->offset != -1)
23608c2ecf20Sopenharmony_ci			return scnprintf(bf, sizeof(bf), "%" PRIx64, start + line->offset);
23618c2ecf20Sopenharmony_ci	}
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci	return 0;
23648c2ecf20Sopenharmony_ci}
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ciint symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel,
23678c2ecf20Sopenharmony_ci			    struct annotation_options *opts)
23688c2ecf20Sopenharmony_ci{
23698c2ecf20Sopenharmony_ci	struct map *map = ms->map;
23708c2ecf20Sopenharmony_ci	struct symbol *sym = ms->sym;
23718c2ecf20Sopenharmony_ci	struct dso *dso = map->dso;
23728c2ecf20Sopenharmony_ci	char *filename;
23738c2ecf20Sopenharmony_ci	const char *d_filename;
23748c2ecf20Sopenharmony_ci	const char *evsel_name = evsel__name(evsel);
23758c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
23768c2ecf20Sopenharmony_ci	struct sym_hist *h = annotation__histogram(notes, evsel->idx);
23778c2ecf20Sopenharmony_ci	struct annotation_line *pos, *queue = NULL;
23788c2ecf20Sopenharmony_ci	u64 start = map__rip_2objdump(map, sym->start);
23798c2ecf20Sopenharmony_ci	int printed = 2, queue_len = 0, addr_fmt_width;
23808c2ecf20Sopenharmony_ci	int more = 0;
23818c2ecf20Sopenharmony_ci	bool context = opts->context;
23828c2ecf20Sopenharmony_ci	u64 len;
23838c2ecf20Sopenharmony_ci	int width = symbol_conf.show_total_period ? 12 : 8;
23848c2ecf20Sopenharmony_ci	int graph_dotted_len;
23858c2ecf20Sopenharmony_ci	char buf[512];
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_ci	filename = strdup(dso->long_name);
23888c2ecf20Sopenharmony_ci	if (!filename)
23898c2ecf20Sopenharmony_ci		return -ENOMEM;
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci	if (opts->full_path)
23928c2ecf20Sopenharmony_ci		d_filename = filename;
23938c2ecf20Sopenharmony_ci	else
23948c2ecf20Sopenharmony_ci		d_filename = basename(filename);
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci	len = symbol__size(sym);
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci	if (evsel__is_group_event(evsel)) {
23998c2ecf20Sopenharmony_ci		width *= evsel->core.nr_members;
24008c2ecf20Sopenharmony_ci		evsel__group_desc(evsel, buf, sizeof(buf));
24018c2ecf20Sopenharmony_ci		evsel_name = buf;
24028c2ecf20Sopenharmony_ci	}
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	graph_dotted_len = printf(" %-*.*s|	Source code & Disassembly of %s for %s (%" PRIu64 " samples, "
24058c2ecf20Sopenharmony_ci				  "percent: %s)\n",
24068c2ecf20Sopenharmony_ci				  width, width, symbol_conf.show_total_period ? "Period" :
24078c2ecf20Sopenharmony_ci				  symbol_conf.show_nr_samples ? "Samples" : "Percent",
24088c2ecf20Sopenharmony_ci				  d_filename, evsel_name, h->nr_samples,
24098c2ecf20Sopenharmony_ci				  percent_type_str(opts->percent_type));
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	printf("%-*.*s----\n",
24128c2ecf20Sopenharmony_ci	       graph_dotted_len, graph_dotted_len, graph_dotted_line);
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	if (verbose > 0)
24158c2ecf20Sopenharmony_ci		symbol__annotate_hits(sym, evsel);
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	addr_fmt_width = annotated_source__addr_fmt_width(&notes->src->source, start);
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ci	list_for_each_entry(pos, &notes->src->source, node) {
24208c2ecf20Sopenharmony_ci		int err;
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci		if (context && queue == NULL) {
24238c2ecf20Sopenharmony_ci			queue = pos;
24248c2ecf20Sopenharmony_ci			queue_len = 0;
24258c2ecf20Sopenharmony_ci		}
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci		err = annotation_line__print(pos, sym, start, evsel, len,
24288c2ecf20Sopenharmony_ci					     opts->min_pcnt, printed, opts->max_lines,
24298c2ecf20Sopenharmony_ci					     queue, addr_fmt_width, opts->percent_type);
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci		switch (err) {
24328c2ecf20Sopenharmony_ci		case 0:
24338c2ecf20Sopenharmony_ci			++printed;
24348c2ecf20Sopenharmony_ci			if (context) {
24358c2ecf20Sopenharmony_ci				printed += queue_len;
24368c2ecf20Sopenharmony_ci				queue = NULL;
24378c2ecf20Sopenharmony_ci				queue_len = 0;
24388c2ecf20Sopenharmony_ci			}
24398c2ecf20Sopenharmony_ci			break;
24408c2ecf20Sopenharmony_ci		case 1:
24418c2ecf20Sopenharmony_ci			/* filtered by max_lines */
24428c2ecf20Sopenharmony_ci			++more;
24438c2ecf20Sopenharmony_ci			break;
24448c2ecf20Sopenharmony_ci		case -1:
24458c2ecf20Sopenharmony_ci		default:
24468c2ecf20Sopenharmony_ci			/*
24478c2ecf20Sopenharmony_ci			 * Filtered by min_pcnt or non IP lines when
24488c2ecf20Sopenharmony_ci			 * context != 0
24498c2ecf20Sopenharmony_ci			 */
24508c2ecf20Sopenharmony_ci			if (!context)
24518c2ecf20Sopenharmony_ci				break;
24528c2ecf20Sopenharmony_ci			if (queue_len == context)
24538c2ecf20Sopenharmony_ci				queue = list_entry(queue->node.next, typeof(*queue), node);
24548c2ecf20Sopenharmony_ci			else
24558c2ecf20Sopenharmony_ci				++queue_len;
24568c2ecf20Sopenharmony_ci			break;
24578c2ecf20Sopenharmony_ci		}
24588c2ecf20Sopenharmony_ci	}
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	free(filename);
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci	return more;
24638c2ecf20Sopenharmony_ci}
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_cistatic void FILE__set_percent_color(void *fp __maybe_unused,
24668c2ecf20Sopenharmony_ci				    double percent __maybe_unused,
24678c2ecf20Sopenharmony_ci				    bool current __maybe_unused)
24688c2ecf20Sopenharmony_ci{
24698c2ecf20Sopenharmony_ci}
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_cistatic int FILE__set_jumps_percent_color(void *fp __maybe_unused,
24728c2ecf20Sopenharmony_ci					 int nr __maybe_unused, bool current __maybe_unused)
24738c2ecf20Sopenharmony_ci{
24748c2ecf20Sopenharmony_ci	return 0;
24758c2ecf20Sopenharmony_ci}
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_cistatic int FILE__set_color(void *fp __maybe_unused, int color __maybe_unused)
24788c2ecf20Sopenharmony_ci{
24798c2ecf20Sopenharmony_ci	return 0;
24808c2ecf20Sopenharmony_ci}
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_cistatic void FILE__printf(void *fp, const char *fmt, ...)
24838c2ecf20Sopenharmony_ci{
24848c2ecf20Sopenharmony_ci	va_list args;
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci	va_start(args, fmt);
24878c2ecf20Sopenharmony_ci	vfprintf(fp, fmt, args);
24888c2ecf20Sopenharmony_ci	va_end(args);
24898c2ecf20Sopenharmony_ci}
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_cistatic void FILE__write_graph(void *fp, int graph)
24928c2ecf20Sopenharmony_ci{
24938c2ecf20Sopenharmony_ci	const char *s;
24948c2ecf20Sopenharmony_ci	switch (graph) {
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_ci	case DARROW_CHAR: s = "↓"; break;
24978c2ecf20Sopenharmony_ci	case UARROW_CHAR: s = "↑"; break;
24988c2ecf20Sopenharmony_ci	case LARROW_CHAR: s = "←"; break;
24998c2ecf20Sopenharmony_ci	case RARROW_CHAR: s = "→"; break;
25008c2ecf20Sopenharmony_ci	default:		s = "?"; break;
25018c2ecf20Sopenharmony_ci	}
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_ci	fputs(s, fp);
25048c2ecf20Sopenharmony_ci}
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_cistatic int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp,
25078c2ecf20Sopenharmony_ci				     struct annotation_options *opts)
25088c2ecf20Sopenharmony_ci{
25098c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
25108c2ecf20Sopenharmony_ci	struct annotation_write_ops wops = {
25118c2ecf20Sopenharmony_ci		.first_line		 = true,
25128c2ecf20Sopenharmony_ci		.obj			 = fp,
25138c2ecf20Sopenharmony_ci		.set_color		 = FILE__set_color,
25148c2ecf20Sopenharmony_ci		.set_percent_color	 = FILE__set_percent_color,
25158c2ecf20Sopenharmony_ci		.set_jumps_percent_color = FILE__set_jumps_percent_color,
25168c2ecf20Sopenharmony_ci		.printf			 = FILE__printf,
25178c2ecf20Sopenharmony_ci		.write_graph		 = FILE__write_graph,
25188c2ecf20Sopenharmony_ci	};
25198c2ecf20Sopenharmony_ci	struct annotation_line *al;
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	list_for_each_entry(al, &notes->src->source, node) {
25228c2ecf20Sopenharmony_ci		if (annotation_line__filter(al, notes))
25238c2ecf20Sopenharmony_ci			continue;
25248c2ecf20Sopenharmony_ci		annotation_line__write(al, notes, &wops, opts);
25258c2ecf20Sopenharmony_ci		fputc('\n', fp);
25268c2ecf20Sopenharmony_ci		wops.first_line = false;
25278c2ecf20Sopenharmony_ci	}
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci	return 0;
25308c2ecf20Sopenharmony_ci}
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ciint map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel,
25338c2ecf20Sopenharmony_ci				struct annotation_options *opts)
25348c2ecf20Sopenharmony_ci{
25358c2ecf20Sopenharmony_ci	const char *ev_name = evsel__name(evsel);
25368c2ecf20Sopenharmony_ci	char buf[1024];
25378c2ecf20Sopenharmony_ci	char *filename;
25388c2ecf20Sopenharmony_ci	int err = -1;
25398c2ecf20Sopenharmony_ci	FILE *fp;
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci	if (asprintf(&filename, "%s.annotation", ms->sym->name) < 0)
25428c2ecf20Sopenharmony_ci		return -1;
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci	fp = fopen(filename, "w");
25458c2ecf20Sopenharmony_ci	if (fp == NULL)
25468c2ecf20Sopenharmony_ci		goto out_free_filename;
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	if (evsel__is_group_event(evsel)) {
25498c2ecf20Sopenharmony_ci		evsel__group_desc(evsel, buf, sizeof(buf));
25508c2ecf20Sopenharmony_ci		ev_name = buf;
25518c2ecf20Sopenharmony_ci	}
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	fprintf(fp, "%s() %s\nEvent: %s\n\n",
25548c2ecf20Sopenharmony_ci		ms->sym->name, ms->map->dso->long_name, ev_name);
25558c2ecf20Sopenharmony_ci	symbol__annotate_fprintf2(ms->sym, fp, opts);
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_ci	fclose(fp);
25588c2ecf20Sopenharmony_ci	err = 0;
25598c2ecf20Sopenharmony_ciout_free_filename:
25608c2ecf20Sopenharmony_ci	free(filename);
25618c2ecf20Sopenharmony_ci	return err;
25628c2ecf20Sopenharmony_ci}
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_civoid symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
25658c2ecf20Sopenharmony_ci{
25668c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
25678c2ecf20Sopenharmony_ci	struct sym_hist *h = annotation__histogram(notes, evidx);
25688c2ecf20Sopenharmony_ci
25698c2ecf20Sopenharmony_ci	memset(h, 0, notes->src->sizeof_sym_hist);
25708c2ecf20Sopenharmony_ci}
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_civoid symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
25738c2ecf20Sopenharmony_ci{
25748c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
25758c2ecf20Sopenharmony_ci	struct sym_hist *h = annotation__histogram(notes, evidx);
25768c2ecf20Sopenharmony_ci	int len = symbol__size(sym), offset;
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	h->nr_samples = 0;
25798c2ecf20Sopenharmony_ci	for (offset = 0; offset < len; ++offset) {
25808c2ecf20Sopenharmony_ci		h->addr[offset].nr_samples = h->addr[offset].nr_samples * 7 / 8;
25818c2ecf20Sopenharmony_ci		h->nr_samples += h->addr[offset].nr_samples;
25828c2ecf20Sopenharmony_ci	}
25838c2ecf20Sopenharmony_ci}
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_civoid annotated_source__purge(struct annotated_source *as)
25868c2ecf20Sopenharmony_ci{
25878c2ecf20Sopenharmony_ci	struct annotation_line *al, *n;
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ci	list_for_each_entry_safe(al, n, &as->source, node) {
25908c2ecf20Sopenharmony_ci		list_del_init(&al->node);
25918c2ecf20Sopenharmony_ci		disasm_line__free(disasm_line(al));
25928c2ecf20Sopenharmony_ci	}
25938c2ecf20Sopenharmony_ci}
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_cistatic size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
25968c2ecf20Sopenharmony_ci{
25978c2ecf20Sopenharmony_ci	size_t printed;
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci	if (dl->al.offset == -1)
26008c2ecf20Sopenharmony_ci		return fprintf(fp, "%s\n", dl->al.line);
26018c2ecf20Sopenharmony_ci
26028c2ecf20Sopenharmony_ci	printed = fprintf(fp, "%#" PRIx64 " %s", dl->al.offset, dl->ins.name);
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_ci	if (dl->ops.raw[0] != '\0') {
26058c2ecf20Sopenharmony_ci		printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
26068c2ecf20Sopenharmony_ci				   dl->ops.raw);
26078c2ecf20Sopenharmony_ci	}
26088c2ecf20Sopenharmony_ci
26098c2ecf20Sopenharmony_ci	return printed + fprintf(fp, "\n");
26108c2ecf20Sopenharmony_ci}
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_cisize_t disasm__fprintf(struct list_head *head, FILE *fp)
26138c2ecf20Sopenharmony_ci{
26148c2ecf20Sopenharmony_ci	struct disasm_line *pos;
26158c2ecf20Sopenharmony_ci	size_t printed = 0;
26168c2ecf20Sopenharmony_ci
26178c2ecf20Sopenharmony_ci	list_for_each_entry(pos, head, al.node)
26188c2ecf20Sopenharmony_ci		printed += disasm_line__fprintf(pos, fp);
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	return printed;
26218c2ecf20Sopenharmony_ci}
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_cibool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym)
26248c2ecf20Sopenharmony_ci{
26258c2ecf20Sopenharmony_ci	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) ||
26268c2ecf20Sopenharmony_ci	    !disasm_line__has_local_offset(dl) || dl->ops.target.offset < 0 ||
26278c2ecf20Sopenharmony_ci	    dl->ops.target.offset >= (s64)symbol__size(sym))
26288c2ecf20Sopenharmony_ci		return false;
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	return true;
26318c2ecf20Sopenharmony_ci}
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_civoid annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym)
26348c2ecf20Sopenharmony_ci{
26358c2ecf20Sopenharmony_ci	u64 offset, size = symbol__size(sym);
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_ci	/* PLT symbols contain external offsets */
26388c2ecf20Sopenharmony_ci	if (strstr(sym->name, "@plt"))
26398c2ecf20Sopenharmony_ci		return;
26408c2ecf20Sopenharmony_ci
26418c2ecf20Sopenharmony_ci	for (offset = 0; offset < size; ++offset) {
26428c2ecf20Sopenharmony_ci		struct annotation_line *al = notes->offsets[offset];
26438c2ecf20Sopenharmony_ci		struct disasm_line *dl;
26448c2ecf20Sopenharmony_ci
26458c2ecf20Sopenharmony_ci		dl = disasm_line(al);
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ci		if (!disasm_line__is_valid_local_jump(dl, sym))
26488c2ecf20Sopenharmony_ci			continue;
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci		al = notes->offsets[dl->ops.target.offset];
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci		/*
26538c2ecf20Sopenharmony_ci		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
26548c2ecf20Sopenharmony_ci		 * have to adjust to the previous offset?
26558c2ecf20Sopenharmony_ci		 */
26568c2ecf20Sopenharmony_ci		if (al == NULL)
26578c2ecf20Sopenharmony_ci			continue;
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci		if (++al->jump_sources > notes->max_jump_sources)
26608c2ecf20Sopenharmony_ci			notes->max_jump_sources = al->jump_sources;
26618c2ecf20Sopenharmony_ci	}
26628c2ecf20Sopenharmony_ci}
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_civoid annotation__set_offsets(struct annotation *notes, s64 size)
26658c2ecf20Sopenharmony_ci{
26668c2ecf20Sopenharmony_ci	struct annotation_line *al;
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci	notes->max_line_len = 0;
26698c2ecf20Sopenharmony_ci	notes->nr_entries = 0;
26708c2ecf20Sopenharmony_ci	notes->nr_asm_entries = 0;
26718c2ecf20Sopenharmony_ci
26728c2ecf20Sopenharmony_ci	list_for_each_entry(al, &notes->src->source, node) {
26738c2ecf20Sopenharmony_ci		size_t line_len = strlen(al->line);
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_ci		if (notes->max_line_len < line_len)
26768c2ecf20Sopenharmony_ci			notes->max_line_len = line_len;
26778c2ecf20Sopenharmony_ci		al->idx = notes->nr_entries++;
26788c2ecf20Sopenharmony_ci		if (al->offset != -1) {
26798c2ecf20Sopenharmony_ci			al->idx_asm = notes->nr_asm_entries++;
26808c2ecf20Sopenharmony_ci			/*
26818c2ecf20Sopenharmony_ci			 * FIXME: short term bandaid to cope with assembly
26828c2ecf20Sopenharmony_ci			 * routines that comes with labels in the same column
26838c2ecf20Sopenharmony_ci			 * as the address in objdump, sigh.
26848c2ecf20Sopenharmony_ci			 *
26858c2ecf20Sopenharmony_ci			 * E.g. copy_user_generic_unrolled
26868c2ecf20Sopenharmony_ci 			 */
26878c2ecf20Sopenharmony_ci			if (al->offset < size)
26888c2ecf20Sopenharmony_ci				notes->offsets[al->offset] = al;
26898c2ecf20Sopenharmony_ci		} else
26908c2ecf20Sopenharmony_ci			al->idx_asm = -1;
26918c2ecf20Sopenharmony_ci	}
26928c2ecf20Sopenharmony_ci}
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_cistatic inline int width_jumps(int n)
26958c2ecf20Sopenharmony_ci{
26968c2ecf20Sopenharmony_ci	if (n >= 100)
26978c2ecf20Sopenharmony_ci		return 5;
26988c2ecf20Sopenharmony_ci	if (n / 10)
26998c2ecf20Sopenharmony_ci		return 2;
27008c2ecf20Sopenharmony_ci	return 1;
27018c2ecf20Sopenharmony_ci}
27028c2ecf20Sopenharmony_ci
27038c2ecf20Sopenharmony_cistatic int annotation__max_ins_name(struct annotation *notes)
27048c2ecf20Sopenharmony_ci{
27058c2ecf20Sopenharmony_ci	int max_name = 0, len;
27068c2ecf20Sopenharmony_ci	struct annotation_line *al;
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci        list_for_each_entry(al, &notes->src->source, node) {
27098c2ecf20Sopenharmony_ci		if (al->offset == -1)
27108c2ecf20Sopenharmony_ci			continue;
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_ci		len = strlen(disasm_line(al)->ins.name);
27138c2ecf20Sopenharmony_ci		if (max_name < len)
27148c2ecf20Sopenharmony_ci			max_name = len;
27158c2ecf20Sopenharmony_ci	}
27168c2ecf20Sopenharmony_ci
27178c2ecf20Sopenharmony_ci	return max_name;
27188c2ecf20Sopenharmony_ci}
27198c2ecf20Sopenharmony_ci
27208c2ecf20Sopenharmony_civoid annotation__init_column_widths(struct annotation *notes, struct symbol *sym)
27218c2ecf20Sopenharmony_ci{
27228c2ecf20Sopenharmony_ci	notes->widths.addr = notes->widths.target =
27238c2ecf20Sopenharmony_ci		notes->widths.min_addr = hex_width(symbol__size(sym));
27248c2ecf20Sopenharmony_ci	notes->widths.max_addr = hex_width(sym->end);
27258c2ecf20Sopenharmony_ci	notes->widths.jumps = width_jumps(notes->max_jump_sources);
27268c2ecf20Sopenharmony_ci	notes->widths.max_ins_name = annotation__max_ins_name(notes);
27278c2ecf20Sopenharmony_ci}
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_civoid annotation__update_column_widths(struct annotation *notes)
27308c2ecf20Sopenharmony_ci{
27318c2ecf20Sopenharmony_ci	if (notes->options->use_offset)
27328c2ecf20Sopenharmony_ci		notes->widths.target = notes->widths.min_addr;
27338c2ecf20Sopenharmony_ci	else
27348c2ecf20Sopenharmony_ci		notes->widths.target = notes->widths.max_addr;
27358c2ecf20Sopenharmony_ci
27368c2ecf20Sopenharmony_ci	notes->widths.addr = notes->widths.target;
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci	if (notes->options->show_nr_jumps)
27398c2ecf20Sopenharmony_ci		notes->widths.addr += notes->widths.jumps + 1;
27408c2ecf20Sopenharmony_ci}
27418c2ecf20Sopenharmony_ci
27428c2ecf20Sopenharmony_cistatic void annotation__calc_lines(struct annotation *notes, struct map *map,
27438c2ecf20Sopenharmony_ci				   struct rb_root *root,
27448c2ecf20Sopenharmony_ci				   struct annotation_options *opts)
27458c2ecf20Sopenharmony_ci{
27468c2ecf20Sopenharmony_ci	struct annotation_line *al;
27478c2ecf20Sopenharmony_ci	struct rb_root tmp_root = RB_ROOT;
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci	list_for_each_entry(al, &notes->src->source, node) {
27508c2ecf20Sopenharmony_ci		double percent_max = 0.0;
27518c2ecf20Sopenharmony_ci		int i;
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci		for (i = 0; i < al->data_nr; i++) {
27548c2ecf20Sopenharmony_ci			double percent;
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci			percent = annotation_data__percent(&al->data[i],
27578c2ecf20Sopenharmony_ci							   opts->percent_type);
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_ci			if (percent > percent_max)
27608c2ecf20Sopenharmony_ci				percent_max = percent;
27618c2ecf20Sopenharmony_ci		}
27628c2ecf20Sopenharmony_ci
27638c2ecf20Sopenharmony_ci		if (percent_max <= 0.5)
27648c2ecf20Sopenharmony_ci			continue;
27658c2ecf20Sopenharmony_ci
27668c2ecf20Sopenharmony_ci		al->path = get_srcline(map->dso, notes->start + al->offset, NULL,
27678c2ecf20Sopenharmony_ci				       false, true, notes->start + al->offset);
27688c2ecf20Sopenharmony_ci		insert_source_line(&tmp_root, al, opts);
27698c2ecf20Sopenharmony_ci	}
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_ci	resort_source_line(root, &tmp_root);
27728c2ecf20Sopenharmony_ci}
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_cistatic void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root,
27758c2ecf20Sopenharmony_ci			       struct annotation_options *opts)
27768c2ecf20Sopenharmony_ci{
27778c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(ms->sym);
27788c2ecf20Sopenharmony_ci
27798c2ecf20Sopenharmony_ci	annotation__calc_lines(notes, ms->map, root, opts);
27808c2ecf20Sopenharmony_ci}
27818c2ecf20Sopenharmony_ci
27828c2ecf20Sopenharmony_ciint symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel,
27838c2ecf20Sopenharmony_ci			  struct annotation_options *opts)
27848c2ecf20Sopenharmony_ci{
27858c2ecf20Sopenharmony_ci	struct dso *dso = ms->map->dso;
27868c2ecf20Sopenharmony_ci	struct symbol *sym = ms->sym;
27878c2ecf20Sopenharmony_ci	struct rb_root source_line = RB_ROOT;
27888c2ecf20Sopenharmony_ci	struct hists *hists = evsel__hists(evsel);
27898c2ecf20Sopenharmony_ci	char buf[1024];
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	if (symbol__annotate2(ms, evsel, opts, NULL) < 0)
27928c2ecf20Sopenharmony_ci		return -1;
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_ci	if (opts->print_lines) {
27958c2ecf20Sopenharmony_ci		srcline_full_filename = opts->full_path;
27968c2ecf20Sopenharmony_ci		symbol__calc_lines(ms, &source_line, opts);
27978c2ecf20Sopenharmony_ci		print_summary(&source_line, dso->long_name);
27988c2ecf20Sopenharmony_ci	}
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_ci	hists__scnprintf_title(hists, buf, sizeof(buf));
28018c2ecf20Sopenharmony_ci	fprintf(stdout, "%s, [percent: %s]\n%s() %s\n",
28028c2ecf20Sopenharmony_ci		buf, percent_type_str(opts->percent_type), sym->name, dso->long_name);
28038c2ecf20Sopenharmony_ci	symbol__annotate_fprintf2(sym, stdout, opts);
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci	annotated_source__purge(symbol__annotation(sym)->src);
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_ci	return 0;
28088c2ecf20Sopenharmony_ci}
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ciint symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel,
28118c2ecf20Sopenharmony_ci			 struct annotation_options *opts)
28128c2ecf20Sopenharmony_ci{
28138c2ecf20Sopenharmony_ci	struct dso *dso = ms->map->dso;
28148c2ecf20Sopenharmony_ci	struct symbol *sym = ms->sym;
28158c2ecf20Sopenharmony_ci	struct rb_root source_line = RB_ROOT;
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_ci	if (symbol__annotate(ms, evsel, opts, NULL) < 0)
28188c2ecf20Sopenharmony_ci		return -1;
28198c2ecf20Sopenharmony_ci
28208c2ecf20Sopenharmony_ci	symbol__calc_percent(sym, evsel);
28218c2ecf20Sopenharmony_ci
28228c2ecf20Sopenharmony_ci	if (opts->print_lines) {
28238c2ecf20Sopenharmony_ci		srcline_full_filename = opts->full_path;
28248c2ecf20Sopenharmony_ci		symbol__calc_lines(ms, &source_line, opts);
28258c2ecf20Sopenharmony_ci		print_summary(&source_line, dso->long_name);
28268c2ecf20Sopenharmony_ci	}
28278c2ecf20Sopenharmony_ci
28288c2ecf20Sopenharmony_ci	symbol__annotate_printf(ms, evsel, opts);
28298c2ecf20Sopenharmony_ci
28308c2ecf20Sopenharmony_ci	annotated_source__purge(symbol__annotation(sym)->src);
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	return 0;
28338c2ecf20Sopenharmony_ci}
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_cibool ui__has_annotation(void)
28368c2ecf20Sopenharmony_ci{
28378c2ecf20Sopenharmony_ci	return use_browser == 1 && perf_hpp_list.sym;
28388c2ecf20Sopenharmony_ci}
28398c2ecf20Sopenharmony_ci
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_cistatic double annotation_line__max_percent(struct annotation_line *al,
28428c2ecf20Sopenharmony_ci					   struct annotation *notes,
28438c2ecf20Sopenharmony_ci					   unsigned int percent_type)
28448c2ecf20Sopenharmony_ci{
28458c2ecf20Sopenharmony_ci	double percent_max = 0.0;
28468c2ecf20Sopenharmony_ci	int i;
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_ci	for (i = 0; i < notes->nr_events; i++) {
28498c2ecf20Sopenharmony_ci		double percent;
28508c2ecf20Sopenharmony_ci
28518c2ecf20Sopenharmony_ci		percent = annotation_data__percent(&al->data[i],
28528c2ecf20Sopenharmony_ci						   percent_type);
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci		if (percent > percent_max)
28558c2ecf20Sopenharmony_ci			percent_max = percent;
28568c2ecf20Sopenharmony_ci	}
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_ci	return percent_max;
28598c2ecf20Sopenharmony_ci}
28608c2ecf20Sopenharmony_ci
28618c2ecf20Sopenharmony_cistatic void disasm_line__write(struct disasm_line *dl, struct annotation *notes,
28628c2ecf20Sopenharmony_ci			       void *obj, char *bf, size_t size,
28638c2ecf20Sopenharmony_ci			       void (*obj__printf)(void *obj, const char *fmt, ...),
28648c2ecf20Sopenharmony_ci			       void (*obj__write_graph)(void *obj, int graph))
28658c2ecf20Sopenharmony_ci{
28668c2ecf20Sopenharmony_ci	if (dl->ins.ops && dl->ins.ops->scnprintf) {
28678c2ecf20Sopenharmony_ci		if (ins__is_jump(&dl->ins)) {
28688c2ecf20Sopenharmony_ci			bool fwd;
28698c2ecf20Sopenharmony_ci
28708c2ecf20Sopenharmony_ci			if (dl->ops.target.outside)
28718c2ecf20Sopenharmony_ci				goto call_like;
28728c2ecf20Sopenharmony_ci			fwd = dl->ops.target.offset > dl->al.offset;
28738c2ecf20Sopenharmony_ci			obj__write_graph(obj, fwd ? DARROW_CHAR : UARROW_CHAR);
28748c2ecf20Sopenharmony_ci			obj__printf(obj, " ");
28758c2ecf20Sopenharmony_ci		} else if (ins__is_call(&dl->ins)) {
28768c2ecf20Sopenharmony_cicall_like:
28778c2ecf20Sopenharmony_ci			obj__write_graph(obj, RARROW_CHAR);
28788c2ecf20Sopenharmony_ci			obj__printf(obj, " ");
28798c2ecf20Sopenharmony_ci		} else if (ins__is_ret(&dl->ins)) {
28808c2ecf20Sopenharmony_ci			obj__write_graph(obj, LARROW_CHAR);
28818c2ecf20Sopenharmony_ci			obj__printf(obj, " ");
28828c2ecf20Sopenharmony_ci		} else {
28838c2ecf20Sopenharmony_ci			obj__printf(obj, "  ");
28848c2ecf20Sopenharmony_ci		}
28858c2ecf20Sopenharmony_ci	} else {
28868c2ecf20Sopenharmony_ci		obj__printf(obj, "  ");
28878c2ecf20Sopenharmony_ci	}
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci	disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset, notes->widths.max_ins_name);
28908c2ecf20Sopenharmony_ci}
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_cistatic void ipc_coverage_string(char *bf, int size, struct annotation *notes)
28938c2ecf20Sopenharmony_ci{
28948c2ecf20Sopenharmony_ci	double ipc = 0.0, coverage = 0.0;
28958c2ecf20Sopenharmony_ci
28968c2ecf20Sopenharmony_ci	if (notes->hit_cycles)
28978c2ecf20Sopenharmony_ci		ipc = notes->hit_insn / ((double)notes->hit_cycles);
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_ci	if (notes->total_insn) {
29008c2ecf20Sopenharmony_ci		coverage = notes->cover_insn * 100.0 /
29018c2ecf20Sopenharmony_ci			((double)notes->total_insn);
29028c2ecf20Sopenharmony_ci	}
29038c2ecf20Sopenharmony_ci
29048c2ecf20Sopenharmony_ci	scnprintf(bf, size, "(Average IPC: %.2f, IPC Coverage: %.1f%%)",
29058c2ecf20Sopenharmony_ci		  ipc, coverage);
29068c2ecf20Sopenharmony_ci}
29078c2ecf20Sopenharmony_ci
29088c2ecf20Sopenharmony_cistatic void __annotation_line__write(struct annotation_line *al, struct annotation *notes,
29098c2ecf20Sopenharmony_ci				     bool first_line, bool current_entry, bool change_color, int width,
29108c2ecf20Sopenharmony_ci				     void *obj, unsigned int percent_type,
29118c2ecf20Sopenharmony_ci				     int  (*obj__set_color)(void *obj, int color),
29128c2ecf20Sopenharmony_ci				     void (*obj__set_percent_color)(void *obj, double percent, bool current),
29138c2ecf20Sopenharmony_ci				     int  (*obj__set_jumps_percent_color)(void *obj, int nr, bool current),
29148c2ecf20Sopenharmony_ci				     void (*obj__printf)(void *obj, const char *fmt, ...),
29158c2ecf20Sopenharmony_ci				     void (*obj__write_graph)(void *obj, int graph))
29168c2ecf20Sopenharmony_ci
29178c2ecf20Sopenharmony_ci{
29188c2ecf20Sopenharmony_ci	double percent_max = annotation_line__max_percent(al, notes, percent_type);
29198c2ecf20Sopenharmony_ci	int pcnt_width = annotation__pcnt_width(notes),
29208c2ecf20Sopenharmony_ci	    cycles_width = annotation__cycles_width(notes);
29218c2ecf20Sopenharmony_ci	bool show_title = false;
29228c2ecf20Sopenharmony_ci	char bf[256];
29238c2ecf20Sopenharmony_ci	int printed;
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci	if (first_line && (al->offset == -1 || percent_max == 0.0)) {
29268c2ecf20Sopenharmony_ci		if (notes->have_cycles) {
29278c2ecf20Sopenharmony_ci			if (al->ipc == 0.0 && al->cycles == 0)
29288c2ecf20Sopenharmony_ci				show_title = true;
29298c2ecf20Sopenharmony_ci		} else
29308c2ecf20Sopenharmony_ci			show_title = true;
29318c2ecf20Sopenharmony_ci	}
29328c2ecf20Sopenharmony_ci
29338c2ecf20Sopenharmony_ci	if (al->offset != -1 && percent_max != 0.0) {
29348c2ecf20Sopenharmony_ci		int i;
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci		for (i = 0; i < notes->nr_events; i++) {
29378c2ecf20Sopenharmony_ci			double percent;
29388c2ecf20Sopenharmony_ci
29398c2ecf20Sopenharmony_ci			percent = annotation_data__percent(&al->data[i], percent_type);
29408c2ecf20Sopenharmony_ci
29418c2ecf20Sopenharmony_ci			obj__set_percent_color(obj, percent, current_entry);
29428c2ecf20Sopenharmony_ci			if (symbol_conf.show_total_period) {
29438c2ecf20Sopenharmony_ci				obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period);
29448c2ecf20Sopenharmony_ci			} else if (symbol_conf.show_nr_samples) {
29458c2ecf20Sopenharmony_ci				obj__printf(obj, "%6" PRIu64 " ",
29468c2ecf20Sopenharmony_ci						   al->data[i].he.nr_samples);
29478c2ecf20Sopenharmony_ci			} else {
29488c2ecf20Sopenharmony_ci				obj__printf(obj, "%6.2f ", percent);
29498c2ecf20Sopenharmony_ci			}
29508c2ecf20Sopenharmony_ci		}
29518c2ecf20Sopenharmony_ci	} else {
29528c2ecf20Sopenharmony_ci		obj__set_percent_color(obj, 0, current_entry);
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci		if (!show_title)
29558c2ecf20Sopenharmony_ci			obj__printf(obj, "%-*s", pcnt_width, " ");
29568c2ecf20Sopenharmony_ci		else {
29578c2ecf20Sopenharmony_ci			obj__printf(obj, "%-*s", pcnt_width,
29588c2ecf20Sopenharmony_ci					   symbol_conf.show_total_period ? "Period" :
29598c2ecf20Sopenharmony_ci					   symbol_conf.show_nr_samples ? "Samples" : "Percent");
29608c2ecf20Sopenharmony_ci		}
29618c2ecf20Sopenharmony_ci	}
29628c2ecf20Sopenharmony_ci
29638c2ecf20Sopenharmony_ci	if (notes->have_cycles) {
29648c2ecf20Sopenharmony_ci		if (al->ipc)
29658c2ecf20Sopenharmony_ci			obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc);
29668c2ecf20Sopenharmony_ci		else if (!show_title)
29678c2ecf20Sopenharmony_ci			obj__printf(obj, "%*s", ANNOTATION__IPC_WIDTH, " ");
29688c2ecf20Sopenharmony_ci		else
29698c2ecf20Sopenharmony_ci			obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci		if (!notes->options->show_minmax_cycle) {
29728c2ecf20Sopenharmony_ci			if (al->cycles)
29738c2ecf20Sopenharmony_ci				obj__printf(obj, "%*" PRIu64 " ",
29748c2ecf20Sopenharmony_ci					   ANNOTATION__CYCLES_WIDTH - 1, al->cycles);
29758c2ecf20Sopenharmony_ci			else if (!show_title)
29768c2ecf20Sopenharmony_ci				obj__printf(obj, "%*s",
29778c2ecf20Sopenharmony_ci					    ANNOTATION__CYCLES_WIDTH, " ");
29788c2ecf20Sopenharmony_ci			else
29798c2ecf20Sopenharmony_ci				obj__printf(obj, "%*s ",
29808c2ecf20Sopenharmony_ci					    ANNOTATION__CYCLES_WIDTH - 1,
29818c2ecf20Sopenharmony_ci					    "Cycle");
29828c2ecf20Sopenharmony_ci		} else {
29838c2ecf20Sopenharmony_ci			if (al->cycles) {
29848c2ecf20Sopenharmony_ci				char str[32];
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci				scnprintf(str, sizeof(str),
29878c2ecf20Sopenharmony_ci					"%" PRIu64 "(%" PRIu64 "/%" PRIu64 ")",
29888c2ecf20Sopenharmony_ci					al->cycles, al->cycles_min,
29898c2ecf20Sopenharmony_ci					al->cycles_max);
29908c2ecf20Sopenharmony_ci
29918c2ecf20Sopenharmony_ci				obj__printf(obj, "%*s ",
29928c2ecf20Sopenharmony_ci					    ANNOTATION__MINMAX_CYCLES_WIDTH - 1,
29938c2ecf20Sopenharmony_ci					    str);
29948c2ecf20Sopenharmony_ci			} else if (!show_title)
29958c2ecf20Sopenharmony_ci				obj__printf(obj, "%*s",
29968c2ecf20Sopenharmony_ci					    ANNOTATION__MINMAX_CYCLES_WIDTH,
29978c2ecf20Sopenharmony_ci					    " ");
29988c2ecf20Sopenharmony_ci			else
29998c2ecf20Sopenharmony_ci				obj__printf(obj, "%*s ",
30008c2ecf20Sopenharmony_ci					    ANNOTATION__MINMAX_CYCLES_WIDTH - 1,
30018c2ecf20Sopenharmony_ci					    "Cycle(min/max)");
30028c2ecf20Sopenharmony_ci		}
30038c2ecf20Sopenharmony_ci
30048c2ecf20Sopenharmony_ci		if (show_title && !*al->line) {
30058c2ecf20Sopenharmony_ci			ipc_coverage_string(bf, sizeof(bf), notes);
30068c2ecf20Sopenharmony_ci			obj__printf(obj, "%*s", ANNOTATION__AVG_IPC_WIDTH, bf);
30078c2ecf20Sopenharmony_ci		}
30088c2ecf20Sopenharmony_ci	}
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_ci	obj__printf(obj, " ");
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_ci	if (!*al->line)
30138c2ecf20Sopenharmony_ci		obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " ");
30148c2ecf20Sopenharmony_ci	else if (al->offset == -1) {
30158c2ecf20Sopenharmony_ci		if (al->line_nr && notes->options->show_linenr)
30168c2ecf20Sopenharmony_ci			printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr);
30178c2ecf20Sopenharmony_ci		else
30188c2ecf20Sopenharmony_ci			printed = scnprintf(bf, sizeof(bf), "%-*s  ", notes->widths.addr, " ");
30198c2ecf20Sopenharmony_ci		obj__printf(obj, bf);
30208c2ecf20Sopenharmony_ci		obj__printf(obj, "%-*s", width - printed - pcnt_width - cycles_width + 1, al->line);
30218c2ecf20Sopenharmony_ci	} else {
30228c2ecf20Sopenharmony_ci		u64 addr = al->offset;
30238c2ecf20Sopenharmony_ci		int color = -1;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci		if (!notes->options->use_offset)
30268c2ecf20Sopenharmony_ci			addr += notes->start;
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci		if (!notes->options->use_offset) {
30298c2ecf20Sopenharmony_ci			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
30308c2ecf20Sopenharmony_ci		} else {
30318c2ecf20Sopenharmony_ci			if (al->jump_sources &&
30328c2ecf20Sopenharmony_ci			    notes->options->offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) {
30338c2ecf20Sopenharmony_ci				if (notes->options->show_nr_jumps) {
30348c2ecf20Sopenharmony_ci					int prev;
30358c2ecf20Sopenharmony_ci					printed = scnprintf(bf, sizeof(bf), "%*d ",
30368c2ecf20Sopenharmony_ci							    notes->widths.jumps,
30378c2ecf20Sopenharmony_ci							    al->jump_sources);
30388c2ecf20Sopenharmony_ci					prev = obj__set_jumps_percent_color(obj, al->jump_sources,
30398c2ecf20Sopenharmony_ci									    current_entry);
30408c2ecf20Sopenharmony_ci					obj__printf(obj, bf);
30418c2ecf20Sopenharmony_ci					obj__set_color(obj, prev);
30428c2ecf20Sopenharmony_ci				}
30438c2ecf20Sopenharmony_ciprint_addr:
30448c2ecf20Sopenharmony_ci				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
30458c2ecf20Sopenharmony_ci						    notes->widths.target, addr);
30468c2ecf20Sopenharmony_ci			} else if (ins__is_call(&disasm_line(al)->ins) &&
30478c2ecf20Sopenharmony_ci				   notes->options->offset_level >= ANNOTATION__OFFSET_CALL) {
30488c2ecf20Sopenharmony_ci				goto print_addr;
30498c2ecf20Sopenharmony_ci			} else if (notes->options->offset_level == ANNOTATION__MAX_OFFSET_LEVEL) {
30508c2ecf20Sopenharmony_ci				goto print_addr;
30518c2ecf20Sopenharmony_ci			} else {
30528c2ecf20Sopenharmony_ci				printed = scnprintf(bf, sizeof(bf), "%-*s  ",
30538c2ecf20Sopenharmony_ci						    notes->widths.addr, " ");
30548c2ecf20Sopenharmony_ci			}
30558c2ecf20Sopenharmony_ci		}
30568c2ecf20Sopenharmony_ci
30578c2ecf20Sopenharmony_ci		if (change_color)
30588c2ecf20Sopenharmony_ci			color = obj__set_color(obj, HE_COLORSET_ADDR);
30598c2ecf20Sopenharmony_ci		obj__printf(obj, bf);
30608c2ecf20Sopenharmony_ci		if (change_color)
30618c2ecf20Sopenharmony_ci			obj__set_color(obj, color);
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_ci		disasm_line__write(disasm_line(al), notes, obj, bf, sizeof(bf), obj__printf, obj__write_graph);
30648c2ecf20Sopenharmony_ci
30658c2ecf20Sopenharmony_ci		obj__printf(obj, "%-*s", width - pcnt_width - cycles_width - 3 - printed, bf);
30668c2ecf20Sopenharmony_ci	}
30678c2ecf20Sopenharmony_ci
30688c2ecf20Sopenharmony_ci}
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_civoid annotation_line__write(struct annotation_line *al, struct annotation *notes,
30718c2ecf20Sopenharmony_ci			    struct annotation_write_ops *wops,
30728c2ecf20Sopenharmony_ci			    struct annotation_options *opts)
30738c2ecf20Sopenharmony_ci{
30748c2ecf20Sopenharmony_ci	__annotation_line__write(al, notes, wops->first_line, wops->current_entry,
30758c2ecf20Sopenharmony_ci				 wops->change_color, wops->width, wops->obj,
30768c2ecf20Sopenharmony_ci				 opts->percent_type,
30778c2ecf20Sopenharmony_ci				 wops->set_color, wops->set_percent_color,
30788c2ecf20Sopenharmony_ci				 wops->set_jumps_percent_color, wops->printf,
30798c2ecf20Sopenharmony_ci				 wops->write_graph);
30808c2ecf20Sopenharmony_ci}
30818c2ecf20Sopenharmony_ci
30828c2ecf20Sopenharmony_ciint symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,
30838c2ecf20Sopenharmony_ci		      struct annotation_options *options, struct arch **parch)
30848c2ecf20Sopenharmony_ci{
30858c2ecf20Sopenharmony_ci	struct symbol *sym = ms->sym;
30868c2ecf20Sopenharmony_ci	struct annotation *notes = symbol__annotation(sym);
30878c2ecf20Sopenharmony_ci	size_t size = symbol__size(sym);
30888c2ecf20Sopenharmony_ci	int nr_pcnt = 1, err;
30898c2ecf20Sopenharmony_ci
30908c2ecf20Sopenharmony_ci	notes->offsets = zalloc(size * sizeof(struct annotation_line *));
30918c2ecf20Sopenharmony_ci	if (notes->offsets == NULL)
30928c2ecf20Sopenharmony_ci		return ENOMEM;
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_ci	if (evsel__is_group_event(evsel))
30958c2ecf20Sopenharmony_ci		nr_pcnt = evsel->core.nr_members;
30968c2ecf20Sopenharmony_ci
30978c2ecf20Sopenharmony_ci	err = symbol__annotate(ms, evsel, options, parch);
30988c2ecf20Sopenharmony_ci	if (err)
30998c2ecf20Sopenharmony_ci		goto out_free_offsets;
31008c2ecf20Sopenharmony_ci
31018c2ecf20Sopenharmony_ci	notes->options = options;
31028c2ecf20Sopenharmony_ci
31038c2ecf20Sopenharmony_ci	symbol__calc_percent(sym, evsel);
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_ci	annotation__set_offsets(notes, size);
31068c2ecf20Sopenharmony_ci	annotation__mark_jump_targets(notes, sym);
31078c2ecf20Sopenharmony_ci	annotation__compute_ipc(notes, size);
31088c2ecf20Sopenharmony_ci	annotation__init_column_widths(notes, sym);
31098c2ecf20Sopenharmony_ci	notes->nr_events = nr_pcnt;
31108c2ecf20Sopenharmony_ci
31118c2ecf20Sopenharmony_ci	annotation__update_column_widths(notes);
31128c2ecf20Sopenharmony_ci	sym->annotate2 = true;
31138c2ecf20Sopenharmony_ci
31148c2ecf20Sopenharmony_ci	return 0;
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ciout_free_offsets:
31178c2ecf20Sopenharmony_ci	zfree(&notes->offsets);
31188c2ecf20Sopenharmony_ci	return err;
31198c2ecf20Sopenharmony_ci}
31208c2ecf20Sopenharmony_ci
31218c2ecf20Sopenharmony_cistatic int annotation__config(const char *var, const char *value, void *data)
31228c2ecf20Sopenharmony_ci{
31238c2ecf20Sopenharmony_ci	struct annotation_options *opt = data;
31248c2ecf20Sopenharmony_ci
31258c2ecf20Sopenharmony_ci	if (!strstarts(var, "annotate."))
31268c2ecf20Sopenharmony_ci		return 0;
31278c2ecf20Sopenharmony_ci
31288c2ecf20Sopenharmony_ci	if (!strcmp(var, "annotate.offset_level")) {
31298c2ecf20Sopenharmony_ci		perf_config_u8(&opt->offset_level, "offset_level", value);
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_ci		if (opt->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
31328c2ecf20Sopenharmony_ci			opt->offset_level = ANNOTATION__MAX_OFFSET_LEVEL;
31338c2ecf20Sopenharmony_ci		else if (opt->offset_level < ANNOTATION__MIN_OFFSET_LEVEL)
31348c2ecf20Sopenharmony_ci			opt->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
31358c2ecf20Sopenharmony_ci	} else if (!strcmp(var, "annotate.hide_src_code")) {
31368c2ecf20Sopenharmony_ci		opt->hide_src_code = perf_config_bool("hide_src_code", value);
31378c2ecf20Sopenharmony_ci	} else if (!strcmp(var, "annotate.jump_arrows")) {
31388c2ecf20Sopenharmony_ci		opt->jump_arrows = perf_config_bool("jump_arrows", value);
31398c2ecf20Sopenharmony_ci	} else if (!strcmp(var, "annotate.show_linenr")) {
31408c2ecf20Sopenharmony_ci		opt->show_linenr = perf_config_bool("show_linenr", value);
31418c2ecf20Sopenharmony_ci	} else if (!strcmp(var, "annotate.show_nr_jumps")) {
31428c2ecf20Sopenharmony_ci		opt->show_nr_jumps = perf_config_bool("show_nr_jumps", value);
31438c2ecf20Sopenharmony_ci	} else if (!strcmp(var, "annotate.show_nr_samples")) {
31448c2ecf20Sopenharmony_ci		symbol_conf.show_nr_samples = perf_config_bool("show_nr_samples",
31458c2ecf20Sopenharmony_ci								value);
31468c2ecf20Sopenharmony_ci	} else if (!strcmp(var, "annotate.show_total_period")) {
31478c2ecf20Sopenharmony_ci		symbol_conf.show_total_period = perf_config_bool("show_total_period",
31488c2ecf20Sopenharmony_ci								value);
31498c2ecf20Sopenharmony_ci	} else if (!strcmp(var, "annotate.use_offset")) {
31508c2ecf20Sopenharmony_ci		opt->use_offset = perf_config_bool("use_offset", value);
31518c2ecf20Sopenharmony_ci	} else if (!strcmp(var, "annotate.disassembler_style")) {
31528c2ecf20Sopenharmony_ci		opt->disassembler_style = value;
31538c2ecf20Sopenharmony_ci	} else {
31548c2ecf20Sopenharmony_ci		pr_debug("%s variable unknown, ignoring...", var);
31558c2ecf20Sopenharmony_ci	}
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	return 0;
31588c2ecf20Sopenharmony_ci}
31598c2ecf20Sopenharmony_ci
31608c2ecf20Sopenharmony_civoid annotation_config__init(struct annotation_options *opt)
31618c2ecf20Sopenharmony_ci{
31628c2ecf20Sopenharmony_ci	perf_config(annotation__config, opt);
31638c2ecf20Sopenharmony_ci}
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_cistatic unsigned int parse_percent_type(char *str1, char *str2)
31668c2ecf20Sopenharmony_ci{
31678c2ecf20Sopenharmony_ci	unsigned int type = (unsigned int) -1;
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_ci	if (!strcmp("period", str1)) {
31708c2ecf20Sopenharmony_ci		if (!strcmp("local", str2))
31718c2ecf20Sopenharmony_ci			type = PERCENT_PERIOD_LOCAL;
31728c2ecf20Sopenharmony_ci		else if (!strcmp("global", str2))
31738c2ecf20Sopenharmony_ci			type = PERCENT_PERIOD_GLOBAL;
31748c2ecf20Sopenharmony_ci	}
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	if (!strcmp("hits", str1)) {
31778c2ecf20Sopenharmony_ci		if (!strcmp("local", str2))
31788c2ecf20Sopenharmony_ci			type = PERCENT_HITS_LOCAL;
31798c2ecf20Sopenharmony_ci		else if (!strcmp("global", str2))
31808c2ecf20Sopenharmony_ci			type = PERCENT_HITS_GLOBAL;
31818c2ecf20Sopenharmony_ci	}
31828c2ecf20Sopenharmony_ci
31838c2ecf20Sopenharmony_ci	return type;
31848c2ecf20Sopenharmony_ci}
31858c2ecf20Sopenharmony_ci
31868c2ecf20Sopenharmony_ciint annotate_parse_percent_type(const struct option *opt, const char *_str,
31878c2ecf20Sopenharmony_ci				int unset __maybe_unused)
31888c2ecf20Sopenharmony_ci{
31898c2ecf20Sopenharmony_ci	struct annotation_options *opts = opt->value;
31908c2ecf20Sopenharmony_ci	unsigned int type;
31918c2ecf20Sopenharmony_ci	char *str1, *str2;
31928c2ecf20Sopenharmony_ci	int err = -1;
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_ci	str1 = strdup(_str);
31958c2ecf20Sopenharmony_ci	if (!str1)
31968c2ecf20Sopenharmony_ci		return -ENOMEM;
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci	str2 = strchr(str1, '-');
31998c2ecf20Sopenharmony_ci	if (!str2)
32008c2ecf20Sopenharmony_ci		goto out;
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_ci	*str2++ = 0;
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci	type = parse_percent_type(str1, str2);
32058c2ecf20Sopenharmony_ci	if (type == (unsigned int) -1)
32068c2ecf20Sopenharmony_ci		type = parse_percent_type(str2, str1);
32078c2ecf20Sopenharmony_ci	if (type != (unsigned int) -1) {
32088c2ecf20Sopenharmony_ci		opts->percent_type = type;
32098c2ecf20Sopenharmony_ci		err = 0;
32108c2ecf20Sopenharmony_ci	}
32118c2ecf20Sopenharmony_ci
32128c2ecf20Sopenharmony_ciout:
32138c2ecf20Sopenharmony_ci	free(str1);
32148c2ecf20Sopenharmony_ci	return err;
32158c2ecf20Sopenharmony_ci}
32168c2ecf20Sopenharmony_ci
32178c2ecf20Sopenharmony_ciint annotate_check_args(struct annotation_options *args)
32188c2ecf20Sopenharmony_ci{
32198c2ecf20Sopenharmony_ci	if (args->prefix_strip && !args->prefix) {
32208c2ecf20Sopenharmony_ci		pr_err("--prefix-strip requires --prefix\n");
32218c2ecf20Sopenharmony_ci		return -1;
32228c2ecf20Sopenharmony_ci	}
32238c2ecf20Sopenharmony_ci	return 0;
32248c2ecf20Sopenharmony_ci}
3225