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