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