1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 4 * Copyright (C) 2015 Naveen N. Rao, IBM Corporation 5 */ 6 7 #include "dso.h" 8 #include "symbol.h" 9 #include "map.h" 10 #include "probe-event.h" 11 #include "probe-file.h" 12 13 int arch__choose_best_symbol(struct symbol *syma, 14 struct symbol *symb __maybe_unused) 15 { 16 char *sym = syma->name; 17 18 #if !defined(_CALL_ELF) || _CALL_ELF != 2 19 /* Skip over any initial dot */ 20 if (*sym == '.') 21 sym++; 22 #endif 23 24 /* Avoid "SyS" kernel syscall aliases */ 25 if (strlen(sym) >= 3 && !strncmp(sym, "SyS", 3)) 26 return SYMBOL_B; 27 if (strlen(sym) >= 10 && !strncmp(sym, "compat_SyS", 10)) 28 return SYMBOL_B; 29 30 return SYMBOL_A; 31 } 32 33 #if !defined(_CALL_ELF) || _CALL_ELF != 2 34 /* Allow matching against dot variants */ 35 int arch__compare_symbol_names(const char *namea, const char *nameb) 36 { 37 /* Skip over initial dot */ 38 if (*namea == '.') 39 namea++; 40 if (*nameb == '.') 41 nameb++; 42 43 return strcmp(namea, nameb); 44 } 45 46 int arch__compare_symbol_names_n(const char *namea, const char *nameb, 47 unsigned int n) 48 { 49 /* Skip over initial dot */ 50 if (*namea == '.') 51 namea++; 52 if (*nameb == '.') 53 nameb++; 54 55 return strncmp(namea, nameb, n); 56 } 57 58 const char *arch__normalize_symbol_name(const char *name) 59 { 60 /* Skip over initial dot */ 61 if (name && *name == '.') 62 name++; 63 return name; 64 } 65 #endif 66 67 #if defined(_CALL_ELF) && _CALL_ELF == 2 68 69 #ifdef HAVE_LIBELF_SUPPORT 70 void arch__sym_update(struct symbol *s, GElf_Sym *sym) 71 { 72 s->arch_sym = sym->st_other; 73 } 74 #endif 75 76 #define PPC64LE_LEP_OFFSET 8 77 78 void arch__fix_tev_from_maps(struct perf_probe_event *pev, 79 struct probe_trace_event *tev, struct map *map, 80 struct symbol *sym) 81 { 82 int lep_offset; 83 84 /* 85 * When probing at a function entry point, we normally always want the 86 * LEP since that catches calls to the function through both the GEP and 87 * the LEP. Hence, we would like to probe at an offset of 8 bytes if 88 * the user only specified the function entry. 89 * 90 * However, if the user specifies an offset, we fall back to using the 91 * GEP since all userspace applications (objdump/readelf) show function 92 * disassembly with offsets from the GEP. 93 */ 94 if (pev->point.offset || !map || !sym) 95 return; 96 97 /* For kretprobes, add an offset only if the kernel supports it */ 98 if (!pev->uprobes && pev->point.retprobe) { 99 #ifdef HAVE_LIBELF_SUPPORT 100 if (!kretprobe_offset_is_supported()) 101 #endif 102 return; 103 } 104 105 lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym); 106 107 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) 108 tev->point.offset += PPC64LE_LEP_OFFSET; 109 else if (lep_offset) { 110 if (pev->uprobes) 111 tev->point.address += lep_offset; 112 else 113 tev->point.offset += lep_offset; 114 } 115 } 116 117 #ifdef HAVE_LIBELF_SUPPORT 118 void arch__post_process_probe_trace_events(struct perf_probe_event *pev, 119 int ntevs) 120 { 121 struct probe_trace_event *tev; 122 struct map *map; 123 struct symbol *sym = NULL; 124 struct rb_node *tmp; 125 int i = 0; 126 127 map = get_target_map(pev->target, pev->nsi, pev->uprobes); 128 if (!map || map__load(map) < 0) 129 return; 130 131 for (i = 0; i < ntevs; i++) { 132 tev = &pev->tevs[i]; 133 map__for_each_symbol(map, sym, tmp) { 134 if (map->unmap_ip(map, sym->start) == tev->point.address) { 135 arch__fix_tev_from_maps(pev, tev, map, sym); 136 break; 137 } 138 } 139 } 140 } 141 #endif /* HAVE_LIBELF_SUPPORT */ 142 143 #endif 144