1 // SPDX-License-Identifier: GPL-2.0 2 #include "libunwind-arch.h" 3 #include "../debug.h" 4 #include "../maps.h" 5 #include <elf.h> 6 #include <errno.h> 7 8 int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum) 9 { 10 switch (e_machine) { 11 case EM_ARM: 12 return __get_perf_regnum_for_unw_regnum_arm(unw_regnum); 13 case EM_AARCH64: 14 return __get_perf_regnum_for_unw_regnum_arm64(unw_regnum); 15 case EM_LOONGARCH: 16 return __get_perf_regnum_for_unw_regnum_loongarch(unw_regnum); 17 case EM_MIPS: 18 return __get_perf_regnum_for_unw_regnum_mips(unw_regnum); 19 case EM_PPC: 20 return __get_perf_regnum_for_unw_regnum_ppc32(unw_regnum); 21 case EM_PPC64: 22 return __get_perf_regnum_for_unw_regnum_ppc64(unw_regnum); 23 case EM_RISCV: 24 return __get_perf_regnum_for_unw_regnum_riscv(unw_regnum); 25 case EM_S390: 26 return __get_perf_regnum_for_unw_regnum_s390(unw_regnum); 27 case EM_386: 28 return __get_perf_regnum_for_unw_regnum_i386(unw_regnum); 29 case EM_X86_64: 30 return __get_perf_regnum_for_unw_regnum_x86_64(unw_regnum); 31 default: 32 pr_err("ELF MACHINE %x is not supported.\n", e_machine); 33 return -EINVAL; 34 } 35 } 36 37 38 void libunwind_arch__flush_access(struct maps *maps) 39 { 40 unsigned int e_machine = maps__e_machine(maps); 41 42 switch (e_machine) { 43 case EM_NONE: 44 break; // No libunwind info on the maps. 45 case EM_ARM: 46 __libunwind_arch__flush_access_arm(maps); 47 break; 48 case EM_AARCH64: 49 __libunwind_arch__flush_access_arm64(maps); 50 break; 51 case EM_LOONGARCH: 52 __libunwind_arch__flush_access_loongarch(maps); 53 break; 54 case EM_MIPS: 55 __libunwind_arch__flush_access_mips(maps); 56 break; 57 case EM_PPC: 58 __libunwind_arch__flush_access_ppc32(maps); 59 break; 60 case EM_PPC64: 61 __libunwind_arch__flush_access_ppc64(maps); 62 break; 63 case EM_RISCV: 64 __libunwind_arch__flush_access_riscv(maps); 65 break; 66 case EM_S390: 67 __libunwind_arch__flush_access_s390(maps); 68 break; 69 case EM_386: 70 __libunwind_arch__flush_access_i386(maps); 71 break; 72 case EM_X86_64: 73 __libunwind_arch__flush_access_x86_64(maps); 74 break; 75 default: 76 pr_err("ELF MACHINE %x is not supported.\n", e_machine); 77 break; 78 } 79 } 80 81 void libunwind_arch__finish_access(struct maps *maps) 82 { 83 unsigned int e_machine = maps__e_machine(maps); 84 85 switch (e_machine) { 86 case EM_NONE: 87 break; // No libunwind info on the maps. 88 case EM_ARM: 89 __libunwind_arch__finish_access_arm(maps); 90 break; 91 case EM_AARCH64: 92 __libunwind_arch__finish_access_arm64(maps); 93 break; 94 case EM_LOONGARCH: 95 __libunwind_arch__finish_access_loongarch(maps); 96 break; 97 case EM_MIPS: 98 __libunwind_arch__finish_access_mips(maps); 99 break; 100 case EM_PPC: 101 __libunwind_arch__finish_access_ppc32(maps); 102 break; 103 case EM_PPC64: 104 __libunwind_arch__finish_access_ppc64(maps); 105 break; 106 case EM_RISCV: 107 __libunwind_arch__finish_access_riscv(maps); 108 break; 109 case EM_S390: 110 __libunwind_arch__finish_access_s390(maps); 111 break; 112 case EM_386: 113 __libunwind_arch__finish_access_i386(maps); 114 break; 115 case EM_X86_64: 116 __libunwind_arch__finish_access_x86_64(maps); 117 break; 118 default: 119 pr_err("ELF MACHINE %x is not supported.\n", e_machine); 120 break; 121 } 122 } 123 124 void *libunwind_arch__create_addr_space(unsigned int e_machine) 125 { 126 switch (e_machine) { 127 case EM_ARM: 128 return __libunwind_arch__create_addr_space_arm(); 129 case EM_AARCH64: 130 return __libunwind_arch__create_addr_space_arm64(); 131 case EM_LOONGARCH: 132 return __libunwind_arch__create_addr_space_loongarch(); 133 case EM_MIPS: 134 return __libunwind_arch__create_addr_space_mips(); 135 case EM_PPC: 136 return __libunwind_arch__create_addr_space_ppc32(); 137 case EM_PPC64: 138 return __libunwind_arch__create_addr_space_ppc64(); 139 case EM_RISCV: 140 return __libunwind_arch__create_addr_space_riscv(); 141 case EM_S390: 142 return __libunwind_arch__create_addr_space_s390(); 143 case EM_386: 144 return __libunwind_arch__create_addr_space_i386(); 145 case EM_X86_64: 146 return __libunwind_arch__create_addr_space_x86_64(); 147 default: 148 pr_err("ELF MACHINE %x is not supported.\n", e_machine); 149 return NULL; 150 } 151 } 152 153 int libunwind_arch__dwarf_search_unwind_table(unsigned int e_machine, 154 void *as, 155 uint64_t ip, 156 struct libarch_unwind__dyn_info *di, 157 void *pi, 158 int need_unwind_info, 159 void *arg) 160 { 161 switch (e_machine) { 162 case EM_ARM: 163 return __libunwind_arch__dwarf_search_unwind_table_arm(as, ip, di, pi, 164 need_unwind_info, arg); 165 case EM_AARCH64: 166 return __libunwind_arch__dwarf_search_unwind_table_arm64(as, ip, di, pi, 167 need_unwind_info, arg); 168 case EM_LOONGARCH: 169 return __libunwind_arch__dwarf_search_unwind_table_loongarch(as, ip, di, pi, 170 need_unwind_info, arg); 171 case EM_MIPS: 172 return __libunwind_arch__dwarf_search_unwind_table_mips(as, ip, di, pi, 173 need_unwind_info, arg); 174 case EM_PPC: 175 return __libunwind_arch__dwarf_search_unwind_table_ppc32(as, ip, di, pi, 176 need_unwind_info, arg); 177 case EM_PPC64: 178 return __libunwind_arch__dwarf_search_unwind_table_ppc64(as, ip, di, pi, 179 need_unwind_info, arg); 180 case EM_RISCV: 181 return __libunwind_arch__dwarf_search_unwind_table_riscv(as, ip, di, pi, 182 need_unwind_info, arg); 183 case EM_S390: 184 return __libunwind_arch__dwarf_search_unwind_table_s390(as, ip, di, pi, 185 need_unwind_info, arg); 186 case EM_386: 187 return __libunwind_arch__dwarf_search_unwind_table_i386(as, ip, di, pi, 188 need_unwind_info, arg); 189 case EM_X86_64: 190 return __libunwind_arch__dwarf_search_unwind_table_x86_64(as, ip, di, pi, 191 need_unwind_info, arg); 192 default: 193 pr_err("ELF MACHINE %x is not supported.\n", e_machine); 194 return -EINVAL; 195 } 196 } 197 198 int libunwind_arch__dwarf_find_debug_frame(unsigned int e_machine, 199 int found, 200 struct libarch_unwind__dyn_info *di_debug, 201 uint64_t ip, 202 uint64_t segbase, 203 const char *obj_name, 204 uint64_t start, 205 uint64_t end) 206 { 207 switch (e_machine) { 208 case EM_ARM: 209 return __libunwind_arch__dwarf_find_debug_frame_arm(found, di_debug, ip, segbase, 210 obj_name, start, end); 211 case EM_AARCH64: 212 return __libunwind_arch__dwarf_find_debug_frame_arm64(found, di_debug, ip, segbase, 213 obj_name, start, end); 214 case EM_LOONGARCH: 215 return __libunwind_arch__dwarf_find_debug_frame_loongarch(found, di_debug, ip, 216 segbase, obj_name, 217 start, end); 218 case EM_MIPS: 219 return __libunwind_arch__dwarf_find_debug_frame_mips(found, di_debug, ip, segbase, 220 obj_name, start, end); 221 case EM_PPC: 222 return __libunwind_arch__dwarf_find_debug_frame_ppc32(found, di_debug, ip, segbase, 223 obj_name, start, end); 224 case EM_PPC64: 225 return __libunwind_arch__dwarf_find_debug_frame_ppc64(found, di_debug, ip, segbase, 226 obj_name, start, end); 227 case EM_RISCV: 228 return __libunwind_arch__dwarf_find_debug_frame_riscv(found, di_debug, ip, segbase, 229 obj_name, start, end); 230 case EM_S390: 231 return __libunwind_arch__dwarf_find_debug_frame_s390(found, di_debug, ip, segbase, 232 obj_name, start, end); 233 case EM_386: 234 return __libunwind_arch__dwarf_find_debug_frame_i386(found, di_debug, ip, segbase, 235 obj_name, start, end); 236 case EM_X86_64: 237 return __libunwind_arch__dwarf_find_debug_frame_x86_64(found, di_debug, ip, segbase, 238 obj_name, start, end); 239 default: 240 pr_err("ELF MACHINE %x is not supported.\n", e_machine); 241 return -EINVAL; 242 } 243 } 244 245 struct unwind_info *libunwind_arch_unwind_info__new(struct thread *thread, 246 struct perf_sample *sample, int max_stack, 247 bool best_effort, uint16_t e_machine, 248 uint64_t first_ip) 249 { 250 switch (e_machine) { 251 case EM_ARM: 252 return __libunwind_arch_unwind_info__new_arm(thread, sample, max_stack, 253 best_effort, first_ip); 254 case EM_AARCH64: 255 return __libunwind_arch_unwind_info__new_arm64(thread, sample, max_stack, 256 best_effort, first_ip); 257 case EM_LOONGARCH: 258 return __libunwind_arch_unwind_info__new_loongarch(thread, sample, max_stack, 259 best_effort, first_ip); 260 case EM_MIPS: 261 return __libunwind_arch_unwind_info__new_mips(thread, sample, max_stack, 262 best_effort, first_ip); 263 case EM_PPC: 264 return __libunwind_arch_unwind_info__new_ppc32(thread, sample, max_stack, 265 best_effort, first_ip); 266 case EM_PPC64: 267 return __libunwind_arch_unwind_info__new_ppc64(thread, sample, max_stack, 268 best_effort, first_ip); 269 case EM_RISCV: 270 return __libunwind_arch_unwind_info__new_riscv(thread, sample, max_stack, 271 best_effort, first_ip); 272 case EM_S390: 273 return __libunwind_arch_unwind_info__new_s390(thread, sample, max_stack, 274 best_effort, first_ip); 275 case EM_386: 276 return __libunwind_arch_unwind_info__new_i386(thread, sample, max_stack, 277 best_effort, first_ip); 278 case EM_X86_64: 279 return __libunwind_arch_unwind_info__new_x86_64(thread, sample, max_stack, 280 best_effort, first_ip); 281 default: 282 pr_err("ELF MACHINE %x is not supported.\n", e_machine); 283 return NULL; 284 } 285 } 286 287 void libunwind_arch_unwind_info__delete(struct unwind_info *ui) 288 { 289 free(ui); 290 } 291 292 int libunwind_arch__unwind_step(struct unwind_info *ui) 293 { 294 switch (ui->e_machine) { 295 case EM_ARM: 296 return __libunwind_arch__unwind_step_arm(ui); 297 case EM_AARCH64: 298 return __libunwind_arch__unwind_step_arm64(ui); 299 case EM_LOONGARCH: 300 return __libunwind_arch__unwind_step_loongarch(ui); 301 case EM_MIPS: 302 return __libunwind_arch__unwind_step_mips(ui); 303 case EM_PPC: 304 return __libunwind_arch__unwind_step_ppc32(ui); 305 case EM_PPC64: 306 return __libunwind_arch__unwind_step_ppc64(ui); 307 case EM_RISCV: 308 return __libunwind_arch__unwind_step_riscv(ui); 309 case EM_S390: 310 return __libunwind_arch__unwind_step_s390(ui); 311 case EM_386: 312 return __libunwind_arch__unwind_step_i386(ui); 313 case EM_X86_64: 314 return __libunwind_arch__unwind_step_x86_64(ui); 315 default: 316 pr_err("ELF MACHINE %x is not supported.\n", ui->e_machine); 317 return -EINVAL; 318 } 319 } 320