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