linux/tools/perf/arch/s390/annotate/instructions.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/compiler.h>
   3
   4static int s390_call__parse(struct arch *arch, struct ins_operands *ops,
   5                            struct map_symbol *ms)
   6{
   7        char *endptr, *tok, *name;
   8        struct map *map = ms->map;
   9        struct addr_map_symbol target = {
  10                .map = map,
  11        };
  12
  13        tok = strchr(ops->raw, ',');
  14        if (!tok)
  15                return -1;
  16
  17        ops->target.addr = strtoull(tok + 1, &endptr, 16);
  18
  19        name = strchr(endptr, '<');
  20        if (name == NULL)
  21                return -1;
  22
  23        name++;
  24
  25        if (arch->objdump.skip_functions_char &&
  26            strchr(name, arch->objdump.skip_functions_char))
  27                return -1;
  28
  29        tok = strchr(name, '>');
  30        if (tok == NULL)
  31                return -1;
  32
  33        *tok = '\0';
  34        ops->target.name = strdup(name);
  35        *tok = '>';
  36
  37        if (ops->target.name == NULL)
  38                return -1;
  39        target.addr = map__objdump_2mem(map, ops->target.addr);
  40
  41        if (map_groups__find_ams(&target) == 0 &&
  42            map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr)
  43                ops->target.sym = target.sym;
  44
  45        return 0;
  46}
  47
  48static int call__scnprintf(struct ins *ins, char *bf, size_t size,
  49                           struct ins_operands *ops, int max_ins_name);
  50
  51static struct ins_ops s390_call_ops = {
  52        .parse     = s390_call__parse,
  53        .scnprintf = call__scnprintf,
  54};
  55
  56static int s390_mov__parse(struct arch *arch __maybe_unused,
  57                           struct ins_operands *ops,
  58                           struct map_symbol *ms __maybe_unused)
  59{
  60        char *s = strchr(ops->raw, ','), *target, *endptr;
  61
  62        if (s == NULL)
  63                return -1;
  64
  65        *s = '\0';
  66        ops->source.raw = strdup(ops->raw);
  67        *s = ',';
  68
  69        if (ops->source.raw == NULL)
  70                return -1;
  71
  72        target = ++s;
  73        ops->target.raw = strdup(target);
  74        if (ops->target.raw == NULL)
  75                goto out_free_source;
  76
  77        ops->target.addr = strtoull(target, &endptr, 16);
  78        if (endptr == target)
  79                goto out_free_target;
  80
  81        s = strchr(endptr, '<');
  82        if (s == NULL)
  83                goto out_free_target;
  84        endptr = strchr(s + 1, '>');
  85        if (endptr == NULL)
  86                goto out_free_target;
  87
  88        *endptr = '\0';
  89        ops->target.name = strdup(s + 1);
  90        *endptr = '>';
  91        if (ops->target.name == NULL)
  92                goto out_free_target;
  93
  94        return 0;
  95
  96out_free_target:
  97        zfree(&ops->target.raw);
  98out_free_source:
  99        zfree(&ops->source.raw);
 100        return -1;
 101}
 102
 103
 104static struct ins_ops s390_mov_ops = {
 105        .parse     = s390_mov__parse,
 106        .scnprintf = mov__scnprintf,
 107};
 108
 109static struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *name)
 110{
 111        struct ins_ops *ops = NULL;
 112
 113        /* catch all kind of jumps */
 114        if (strchr(name, 'j') ||
 115            !strncmp(name, "bct", 3) ||
 116            !strncmp(name, "br", 2))
 117                ops = &jump_ops;
 118        /* override call/returns */
 119        if (!strcmp(name, "bras") ||
 120            !strcmp(name, "brasl") ||
 121            !strcmp(name, "basr"))
 122                ops = &s390_call_ops;
 123        if (!strcmp(name, "br"))
 124                ops = &ret_ops;
 125        /* override load/store relative to PC */
 126        if (!strcmp(name, "lrl") ||
 127            !strcmp(name, "lgrl") ||
 128            !strcmp(name, "lgfrl") ||
 129            !strcmp(name, "llgfrl") ||
 130            !strcmp(name, "strl") ||
 131            !strcmp(name, "stgrl"))
 132                ops = &s390_mov_ops;
 133
 134        if (ops)
 135                arch__associate_ins_ops(arch, name, ops);
 136        return ops;
 137}
 138
 139static int s390__cpuid_parse(struct arch *arch, char *cpuid)
 140{
 141        unsigned int family;
 142        char model[16], model_c[16], cpumf_v[16], cpumf_a[16];
 143        int ret;
 144
 145        /*
 146         * cpuid string format:
 147         * "IBM,family,model-capacity,model[,cpum_cf-version,cpum_cf-authorization]"
 148         */
 149        ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%s", &family, model_c,
 150                     model, cpumf_v, cpumf_a);
 151        if (ret >= 2) {
 152                arch->family = family;
 153                arch->model = 0;
 154                return 0;
 155        }
 156
 157        return -1;
 158}
 159
 160static int s390__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
 161{
 162        int err = 0;
 163
 164        if (!arch->initialized) {
 165                arch->initialized = true;
 166                arch->associate_instruction_ops = s390__associate_ins_ops;
 167                if (cpuid)
 168                        err = s390__cpuid_parse(arch, cpuid);
 169        }
 170
 171        return err;
 172}
 173