xref: /linux/tools/perf/util/annotate-arch/annotate-loongarch.c (revision c4e3a00356fffb20c03bd9609083afb1dc4a2edf)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Perf annotate functions.
4  *
5  * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
6  */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <linux/compiler.h>
10 #include "../disasm.h"
11 #include "../map.h"
12 #include "../maps.h"
13 #include "../symbol.h"
14 #include "../thread.h"
15 
16 static int loongarch_call__parse(const struct arch *arch, struct ins_operands *ops,
17 				 struct map_symbol *ms,
18 				 struct disasm_line *dl __maybe_unused)
19 {
20 	char *c, *endptr, *tok, *name;
21 	struct map *map = ms->map;
22 	struct addr_map_symbol target;
23 
24 	c = strchr(ops->raw, '#');
25 	if (c++ == NULL)
26 		return -1;
27 
28 	ops->target.addr = strtoull(c, &endptr, 16);
29 
30 	name = strchr(endptr, '<');
31 	name++;
32 
33 	if (arch->objdump.skip_functions_char &&
34 	    strchr(name, arch->objdump.skip_functions_char))
35 		return -1;
36 
37 	tok = strchr(name, '>');
38 	if (tok == NULL)
39 		return -1;
40 
41 	*tok = '\0';
42 	ops->target.name = strdup(name);
43 	*tok = '>';
44 
45 	if (ops->target.name == NULL)
46 		return -1;
47 
48 	target = (struct addr_map_symbol) {
49 		.ms = { .map = map__get(map), },
50 		.addr = map__objdump_2mem(map, ops->target.addr),
51 	};
52 
53 	if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
54 	    map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
55 		ops->target.sym = target.ms.sym;
56 
57 	addr_map_symbol__exit(&target);
58 	return 0;
59 }
60 
61 static const struct ins_ops loongarch_call_ops = {
62 	.parse	   = loongarch_call__parse,
63 	.scnprintf = call__scnprintf,
64 	.is_call   = true,
65 };
66 
67 static int loongarch_jump__parse(const struct arch *arch, struct ins_operands *ops,
68 				 struct map_symbol *ms,
69 				 struct disasm_line *dl __maybe_unused)
70 
71 {
72 	struct map *map = ms->map;
73 	struct symbol *sym = ms->sym;
74 	struct addr_map_symbol target = {
75 		.ms = { .map = map__get(map), },
76 	};
77 	const char *c = strchr(ops->raw, '#');
78 	u64 start, end;
79 
80 	ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char);
81 	ops->jump.raw_func_start = strchr(ops->raw, '<');
82 
83 	if (ops->jump.raw_func_start && c > ops->jump.raw_func_start)
84 		c = NULL;
85 
86 	if (c++ != NULL)
87 		ops->target.addr = strtoull(c, NULL, 16);
88 	else
89 		ops->target.addr = strtoull(ops->raw, NULL, 16);
90 
91 	target.addr = map__objdump_2mem(map, ops->target.addr);
92 	start = map__unmap_ip(map, sym->start);
93 	end = map__unmap_ip(map, sym->end);
94 
95 	ops->target.outside = target.addr < start || target.addr > end;
96 
97 	if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
98 	    map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
99 		ops->target.sym = target.ms.sym;
100 
101 	if (!ops->target.outside) {
102 		ops->target.offset = target.addr - start;
103 		ops->target.offset_avail = true;
104 	} else {
105 		ops->target.offset_avail = false;
106 	}
107 	addr_map_symbol__exit(&target);
108 	return 0;
109 }
110 
111 static const struct ins_ops loongarch_jump_ops = {
112 	.parse	   = loongarch_jump__parse,
113 	.scnprintf = jump__scnprintf,
114 	.is_jump   = true,
115 };
116 
117 static
118 const struct ins_ops *loongarch__associate_ins_ops(struct arch *arch, const char *name)
119 {
120 	const struct ins_ops *ops = NULL;
121 
122 	if (!strcmp(name, "bl"))
123 		ops = &loongarch_call_ops;
124 	else if (!strcmp(name, "jirl"))
125 		ops = &ret_ops;
126 	else if (!strcmp(name, "b") ||
127 		 !strncmp(name, "beq", 3) ||
128 		 !strncmp(name, "bne", 3) ||
129 		 !strncmp(name, "blt", 3) ||
130 		 !strncmp(name, "bge", 3) ||
131 		 !strncmp(name, "bltu", 4) ||
132 		 !strncmp(name, "bgeu", 4))
133 		ops = &loongarch_jump_ops;
134 	else
135 		return NULL;
136 
137 	arch__associate_ins_ops(arch, name, ops);
138 
139 	return ops;
140 }
141 
142 int loongarch__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
143 {
144 	if (!arch->initialized) {
145 		arch->associate_instruction_ops = loongarch__associate_ins_ops;
146 		arch->initialized = true;
147 		arch->objdump.comment_char = '#';
148 	}
149 
150 	return 0;
151 }
152