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