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