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