18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2015 Naveen N. Rao, IBM Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "dso.h" 88c2ecf20Sopenharmony_ci#include "symbol.h" 98c2ecf20Sopenharmony_ci#include "map.h" 108c2ecf20Sopenharmony_ci#include "probe-event.h" 118c2ecf20Sopenharmony_ci#include "probe-file.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ciint arch__choose_best_symbol(struct symbol *syma, 148c2ecf20Sopenharmony_ci struct symbol *symb __maybe_unused) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci char *sym = syma->name; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#if !defined(_CALL_ELF) || _CALL_ELF != 2 198c2ecf20Sopenharmony_ci /* Skip over any initial dot */ 208c2ecf20Sopenharmony_ci if (*sym == '.') 218c2ecf20Sopenharmony_ci sym++; 228c2ecf20Sopenharmony_ci#endif 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci /* Avoid "SyS" kernel syscall aliases */ 258c2ecf20Sopenharmony_ci if (strlen(sym) >= 3 && !strncmp(sym, "SyS", 3)) 268c2ecf20Sopenharmony_ci return SYMBOL_B; 278c2ecf20Sopenharmony_ci if (strlen(sym) >= 10 && !strncmp(sym, "compat_SyS", 10)) 288c2ecf20Sopenharmony_ci return SYMBOL_B; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci return SYMBOL_A; 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#if !defined(_CALL_ELF) || _CALL_ELF != 2 348c2ecf20Sopenharmony_ci/* Allow matching against dot variants */ 358c2ecf20Sopenharmony_ciint arch__compare_symbol_names(const char *namea, const char *nameb) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci /* Skip over initial dot */ 388c2ecf20Sopenharmony_ci if (*namea == '.') 398c2ecf20Sopenharmony_ci namea++; 408c2ecf20Sopenharmony_ci if (*nameb == '.') 418c2ecf20Sopenharmony_ci nameb++; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return strcmp(namea, nameb); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciint arch__compare_symbol_names_n(const char *namea, const char *nameb, 478c2ecf20Sopenharmony_ci unsigned int n) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci /* Skip over initial dot */ 508c2ecf20Sopenharmony_ci if (*namea == '.') 518c2ecf20Sopenharmony_ci namea++; 528c2ecf20Sopenharmony_ci if (*nameb == '.') 538c2ecf20Sopenharmony_ci nameb++; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return strncmp(namea, nameb, n); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ciconst char *arch__normalize_symbol_name(const char *name) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci /* Skip over initial dot */ 618c2ecf20Sopenharmony_ci if (name && *name == '.') 628c2ecf20Sopenharmony_ci name++; 638c2ecf20Sopenharmony_ci return name; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci#endif 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#if defined(_CALL_ELF) && _CALL_ELF == 2 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#ifdef HAVE_LIBELF_SUPPORT 708c2ecf20Sopenharmony_civoid arch__sym_update(struct symbol *s, GElf_Sym *sym) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci s->arch_sym = sym->st_other; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci#endif 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define PPC64LE_LEP_OFFSET 8 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_civoid arch__fix_tev_from_maps(struct perf_probe_event *pev, 798c2ecf20Sopenharmony_ci struct probe_trace_event *tev, struct map *map, 808c2ecf20Sopenharmony_ci struct symbol *sym) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci int lep_offset; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* 858c2ecf20Sopenharmony_ci * When probing at a function entry point, we normally always want the 868c2ecf20Sopenharmony_ci * LEP since that catches calls to the function through both the GEP and 878c2ecf20Sopenharmony_ci * the LEP. Hence, we would like to probe at an offset of 8 bytes if 888c2ecf20Sopenharmony_ci * the user only specified the function entry. 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * However, if the user specifies an offset, we fall back to using the 918c2ecf20Sopenharmony_ci * GEP since all userspace applications (objdump/readelf) show function 928c2ecf20Sopenharmony_ci * disassembly with offsets from the GEP. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci if (pev->point.offset || !map || !sym) 958c2ecf20Sopenharmony_ci return; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* For kretprobes, add an offset only if the kernel supports it */ 988c2ecf20Sopenharmony_ci if (!pev->uprobes && pev->point.retprobe) { 998c2ecf20Sopenharmony_ci#ifdef HAVE_LIBELF_SUPPORT 1008c2ecf20Sopenharmony_ci if (!kretprobe_offset_is_supported()) 1018c2ecf20Sopenharmony_ci#endif 1028c2ecf20Sopenharmony_ci return; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) 1088c2ecf20Sopenharmony_ci tev->point.offset += PPC64LE_LEP_OFFSET; 1098c2ecf20Sopenharmony_ci else if (lep_offset) { 1108c2ecf20Sopenharmony_ci if (pev->uprobes) 1118c2ecf20Sopenharmony_ci tev->point.address += lep_offset; 1128c2ecf20Sopenharmony_ci else 1138c2ecf20Sopenharmony_ci tev->point.offset += lep_offset; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#ifdef HAVE_LIBELF_SUPPORT 1188c2ecf20Sopenharmony_civoid arch__post_process_probe_trace_events(struct perf_probe_event *pev, 1198c2ecf20Sopenharmony_ci int ntevs) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct probe_trace_event *tev; 1228c2ecf20Sopenharmony_ci struct map *map; 1238c2ecf20Sopenharmony_ci struct symbol *sym = NULL; 1248c2ecf20Sopenharmony_ci struct rb_node *tmp; 1258c2ecf20Sopenharmony_ci int i = 0; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci map = get_target_map(pev->target, pev->nsi, pev->uprobes); 1288c2ecf20Sopenharmony_ci if (!map || map__load(map) < 0) 1298c2ecf20Sopenharmony_ci return; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci for (i = 0; i < ntevs; i++) { 1328c2ecf20Sopenharmony_ci tev = &pev->tevs[i]; 1338c2ecf20Sopenharmony_ci map__for_each_symbol(map, sym, tmp) { 1348c2ecf20Sopenharmony_ci if (map->unmap_ip(map, sym->start) == tev->point.address) { 1358c2ecf20Sopenharmony_ci arch__fix_tev_from_maps(pev, tev, map, sym); 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci#endif /* HAVE_LIBELF_SUPPORT */ 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#endif 144