107b972ffSIan Rogers // SPDX-License-Identifier: GPL-2.0
207b972ffSIan Rogers /*
307b972ffSIan Rogers * Perf annotate functions.
407b972ffSIan Rogers *
507b972ffSIan Rogers * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
607b972ffSIan Rogers */
707b972ffSIan Rogers #include <stdlib.h>
807b972ffSIan Rogers #include <string.h>
907b972ffSIan Rogers #include <linux/compiler.h>
10*0e26ba5aSIan Rogers #include <linux/zalloc.h>
1107b972ffSIan Rogers #include "../disasm.h"
1207b972ffSIan Rogers #include "../map.h"
1307b972ffSIan Rogers #include "../maps.h"
1407b972ffSIan Rogers #include "../symbol.h"
15c4e3a003SIan Rogers #include "../thread.h"
1607b972ffSIan Rogers
loongarch_call__parse(const struct arch * arch,struct ins_operands * ops,struct map_symbol * ms,struct disasm_line * dl __maybe_unused)1707b972ffSIan Rogers static int loongarch_call__parse(const struct arch *arch, struct ins_operands *ops,
1807b972ffSIan Rogers struct map_symbol *ms,
1907b972ffSIan Rogers struct disasm_line *dl __maybe_unused)
2007b972ffSIan Rogers {
2107b972ffSIan Rogers char *c, *endptr, *tok, *name;
2207b972ffSIan Rogers struct map *map = ms->map;
2307b972ffSIan Rogers struct addr_map_symbol target;
2407b972ffSIan Rogers
2507b972ffSIan Rogers c = strchr(ops->raw, '#');
2607b972ffSIan Rogers if (c++ == NULL)
2707b972ffSIan Rogers return -1;
2807b972ffSIan Rogers
2907b972ffSIan Rogers ops->target.addr = strtoull(c, &endptr, 16);
3007b972ffSIan Rogers
3107b972ffSIan Rogers name = strchr(endptr, '<');
3207b972ffSIan Rogers name++;
3307b972ffSIan Rogers
3407b972ffSIan Rogers if (arch->objdump.skip_functions_char &&
3507b972ffSIan Rogers strchr(name, arch->objdump.skip_functions_char))
3607b972ffSIan Rogers return -1;
3707b972ffSIan Rogers
3807b972ffSIan Rogers tok = strchr(name, '>');
3907b972ffSIan Rogers if (tok == NULL)
4007b972ffSIan Rogers return -1;
4107b972ffSIan Rogers
4207b972ffSIan Rogers *tok = '\0';
4307b972ffSIan Rogers ops->target.name = strdup(name);
4407b972ffSIan Rogers *tok = '>';
4507b972ffSIan Rogers
4607b972ffSIan Rogers if (ops->target.name == NULL)
4707b972ffSIan Rogers return -1;
4807b972ffSIan Rogers
4907b972ffSIan Rogers target = (struct addr_map_symbol) {
5007b972ffSIan Rogers .ms = { .map = map__get(map), },
5107b972ffSIan Rogers .addr = map__objdump_2mem(map, ops->target.addr),
5207b972ffSIan Rogers };
5307b972ffSIan Rogers
54c4e3a003SIan Rogers if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
5507b972ffSIan Rogers map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
5607b972ffSIan Rogers ops->target.sym = target.ms.sym;
5707b972ffSIan Rogers
5807b972ffSIan Rogers addr_map_symbol__exit(&target);
5907b972ffSIan Rogers return 0;
6007b972ffSIan Rogers }
6107b972ffSIan Rogers
625301cc69SIan Rogers static const struct ins_ops loongarch_call_ops = {
6307b972ffSIan Rogers .parse = loongarch_call__parse,
6407b972ffSIan Rogers .scnprintf = call__scnprintf,
655301cc69SIan Rogers .is_call = true,
6607b972ffSIan Rogers };
6707b972ffSIan Rogers
loongarch_jump__parse(const struct arch * arch,struct ins_operands * ops,struct map_symbol * ms,struct disasm_line * dl __maybe_unused)6807b972ffSIan Rogers static int loongarch_jump__parse(const struct arch *arch, struct ins_operands *ops,
6907b972ffSIan Rogers struct map_symbol *ms,
7007b972ffSIan Rogers struct disasm_line *dl __maybe_unused)
7107b972ffSIan Rogers
7207b972ffSIan Rogers {
7307b972ffSIan Rogers struct map *map = ms->map;
7407b972ffSIan Rogers struct symbol *sym = ms->sym;
7507b972ffSIan Rogers struct addr_map_symbol target = {
7607b972ffSIan Rogers .ms = { .map = map__get(map), },
7707b972ffSIan Rogers };
7807b972ffSIan Rogers const char *c = strchr(ops->raw, '#');
7907b972ffSIan Rogers u64 start, end;
8007b972ffSIan Rogers
8107b972ffSIan Rogers ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char);
8207b972ffSIan Rogers ops->jump.raw_func_start = strchr(ops->raw, '<');
8307b972ffSIan Rogers
8407b972ffSIan Rogers if (ops->jump.raw_func_start && c > ops->jump.raw_func_start)
8507b972ffSIan Rogers c = NULL;
8607b972ffSIan Rogers
8707b972ffSIan Rogers if (c++ != NULL)
8807b972ffSIan Rogers ops->target.addr = strtoull(c, NULL, 16);
8907b972ffSIan Rogers else
9007b972ffSIan Rogers ops->target.addr = strtoull(ops->raw, NULL, 16);
9107b972ffSIan Rogers
9207b972ffSIan Rogers target.addr = map__objdump_2mem(map, ops->target.addr);
9307b972ffSIan Rogers start = map__unmap_ip(map, sym->start);
9407b972ffSIan Rogers end = map__unmap_ip(map, sym->end);
9507b972ffSIan Rogers
9607b972ffSIan Rogers ops->target.outside = target.addr < start || target.addr > end;
9707b972ffSIan Rogers
98c4e3a003SIan Rogers if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
9907b972ffSIan Rogers map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
10007b972ffSIan Rogers ops->target.sym = target.ms.sym;
10107b972ffSIan Rogers
10207b972ffSIan Rogers if (!ops->target.outside) {
10307b972ffSIan Rogers ops->target.offset = target.addr - start;
10407b972ffSIan Rogers ops->target.offset_avail = true;
10507b972ffSIan Rogers } else {
10607b972ffSIan Rogers ops->target.offset_avail = false;
10707b972ffSIan Rogers }
10807b972ffSIan Rogers addr_map_symbol__exit(&target);
10907b972ffSIan Rogers return 0;
11007b972ffSIan Rogers }
11107b972ffSIan Rogers
1125301cc69SIan Rogers static const struct ins_ops loongarch_jump_ops = {
11307b972ffSIan Rogers .parse = loongarch_jump__parse,
11407b972ffSIan Rogers .scnprintf = jump__scnprintf,
1155301cc69SIan Rogers .is_jump = true,
11607b972ffSIan Rogers };
11707b972ffSIan Rogers
11807b972ffSIan Rogers static
loongarch__associate_ins_ops(struct arch * arch,const char * name)11907b972ffSIan Rogers const struct ins_ops *loongarch__associate_ins_ops(struct arch *arch, const char *name)
12007b972ffSIan Rogers {
12107b972ffSIan Rogers const struct ins_ops *ops = NULL;
12207b972ffSIan Rogers
12307b972ffSIan Rogers if (!strcmp(name, "bl"))
12407b972ffSIan Rogers ops = &loongarch_call_ops;
12507b972ffSIan Rogers else if (!strcmp(name, "jirl"))
12607b972ffSIan Rogers ops = &ret_ops;
12707b972ffSIan Rogers else if (!strcmp(name, "b") ||
12807b972ffSIan Rogers !strncmp(name, "beq", 3) ||
12907b972ffSIan Rogers !strncmp(name, "bne", 3) ||
13007b972ffSIan Rogers !strncmp(name, "blt", 3) ||
13107b972ffSIan Rogers !strncmp(name, "bge", 3) ||
13207b972ffSIan Rogers !strncmp(name, "bltu", 4) ||
13307b972ffSIan Rogers !strncmp(name, "bgeu", 4))
13407b972ffSIan Rogers ops = &loongarch_jump_ops;
13507b972ffSIan Rogers else
13607b972ffSIan Rogers return NULL;
13707b972ffSIan Rogers
13807b972ffSIan Rogers arch__associate_ins_ops(arch, name, ops);
13907b972ffSIan Rogers
14007b972ffSIan Rogers return ops;
14107b972ffSIan Rogers }
14207b972ffSIan Rogers
arch__new_loongarch(const struct e_machine_and_e_flags * id,const char * cpuid __maybe_unused)143*0e26ba5aSIan Rogers const struct arch *arch__new_loongarch(const struct e_machine_and_e_flags *id,
144*0e26ba5aSIan Rogers const char *cpuid __maybe_unused)
14507b972ffSIan Rogers {
146*0e26ba5aSIan Rogers struct arch *arch = zalloc(sizeof(*arch));
14707b972ffSIan Rogers
148*0e26ba5aSIan Rogers if (!arch)
149*0e26ba5aSIan Rogers return NULL;
150*0e26ba5aSIan Rogers
151*0e26ba5aSIan Rogers arch->name = "loongarch";
152*0e26ba5aSIan Rogers arch->id = *id;
153*0e26ba5aSIan Rogers arch->associate_instruction_ops = loongarch__associate_ins_ops;
154*0e26ba5aSIan Rogers arch->objdump.comment_char = '#';
155*0e26ba5aSIan Rogers return arch;
15607b972ffSIan Rogers }
157