162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2015 Naveen N. Rao, IBM Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "dso.h" 862306a36Sopenharmony_ci#include "symbol.h" 962306a36Sopenharmony_ci#include "map.h" 1062306a36Sopenharmony_ci#include "probe-event.h" 1162306a36Sopenharmony_ci#include "probe-file.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ciint arch__choose_best_symbol(struct symbol *syma, 1462306a36Sopenharmony_ci struct symbol *symb __maybe_unused) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci char *sym = syma->name; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#if !defined(_CALL_ELF) || _CALL_ELF != 2 1962306a36Sopenharmony_ci /* Skip over any initial dot */ 2062306a36Sopenharmony_ci if (*sym == '.') 2162306a36Sopenharmony_ci sym++; 2262306a36Sopenharmony_ci#endif 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci /* Avoid "SyS" kernel syscall aliases */ 2562306a36Sopenharmony_ci if (strlen(sym) >= 3 && !strncmp(sym, "SyS", 3)) 2662306a36Sopenharmony_ci return SYMBOL_B; 2762306a36Sopenharmony_ci if (strlen(sym) >= 10 && !strncmp(sym, "compat_SyS", 10)) 2862306a36Sopenharmony_ci return SYMBOL_B; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci return SYMBOL_A; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#if !defined(_CALL_ELF) || _CALL_ELF != 2 3462306a36Sopenharmony_ci/* Allow matching against dot variants */ 3562306a36Sopenharmony_ciint arch__compare_symbol_names(const char *namea, const char *nameb) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci /* Skip over initial dot */ 3862306a36Sopenharmony_ci if (*namea == '.') 3962306a36Sopenharmony_ci namea++; 4062306a36Sopenharmony_ci if (*nameb == '.') 4162306a36Sopenharmony_ci nameb++; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci return strcmp(namea, nameb); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciint arch__compare_symbol_names_n(const char *namea, const char *nameb, 4762306a36Sopenharmony_ci unsigned int n) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci /* Skip over initial dot */ 5062306a36Sopenharmony_ci if (*namea == '.') 5162306a36Sopenharmony_ci namea++; 5262306a36Sopenharmony_ci if (*nameb == '.') 5362306a36Sopenharmony_ci nameb++; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return strncmp(namea, nameb, n); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciconst char *arch__normalize_symbol_name(const char *name) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci /* Skip over initial dot */ 6162306a36Sopenharmony_ci if (name && *name == '.') 6262306a36Sopenharmony_ci name++; 6362306a36Sopenharmony_ci return name; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci#endif 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#if defined(_CALL_ELF) && _CALL_ELF == 2 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#ifdef HAVE_LIBELF_SUPPORT 7062306a36Sopenharmony_civoid arch__sym_update(struct symbol *s, GElf_Sym *sym) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci s->arch_sym = sym->st_other; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci#endif 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define PPC64LE_LEP_OFFSET 8 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_civoid arch__fix_tev_from_maps(struct perf_probe_event *pev, 7962306a36Sopenharmony_ci struct probe_trace_event *tev, struct map *map, 8062306a36Sopenharmony_ci struct symbol *sym) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci int lep_offset; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* 8562306a36Sopenharmony_ci * When probing at a function entry point, we normally always want the 8662306a36Sopenharmony_ci * LEP since that catches calls to the function through both the GEP and 8762306a36Sopenharmony_ci * the LEP. Hence, we would like to probe at an offset of 8 bytes if 8862306a36Sopenharmony_ci * the user only specified the function entry. 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * However, if the user specifies an offset, we fall back to using the 9162306a36Sopenharmony_ci * GEP since all userspace applications (objdump/readelf) show function 9262306a36Sopenharmony_ci * disassembly with offsets from the GEP. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci if (pev->point.offset || !map || !sym) 9562306a36Sopenharmony_ci return; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* For kretprobes, add an offset only if the kernel supports it */ 9862306a36Sopenharmony_ci if (!pev->uprobes && pev->point.retprobe) { 9962306a36Sopenharmony_ci#ifdef HAVE_LIBELF_SUPPORT 10062306a36Sopenharmony_ci if (!kretprobe_offset_is_supported()) 10162306a36Sopenharmony_ci#endif 10262306a36Sopenharmony_ci return; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (map__dso(map)->symtab_type == DSO_BINARY_TYPE__KALLSYMS) 10862306a36Sopenharmony_ci tev->point.offset += PPC64LE_LEP_OFFSET; 10962306a36Sopenharmony_ci else if (lep_offset) { 11062306a36Sopenharmony_ci if (pev->uprobes) 11162306a36Sopenharmony_ci tev->point.address += lep_offset; 11262306a36Sopenharmony_ci else 11362306a36Sopenharmony_ci tev->point.offset += lep_offset; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#ifdef HAVE_LIBELF_SUPPORT 11862306a36Sopenharmony_civoid arch__post_process_probe_trace_events(struct perf_probe_event *pev, 11962306a36Sopenharmony_ci int ntevs) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct probe_trace_event *tev; 12262306a36Sopenharmony_ci struct map *map; 12362306a36Sopenharmony_ci struct symbol *sym = NULL; 12462306a36Sopenharmony_ci struct rb_node *tmp; 12562306a36Sopenharmony_ci int i = 0; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci map = get_target_map(pev->target, pev->nsi, pev->uprobes); 12862306a36Sopenharmony_ci if (!map || map__load(map) < 0) 12962306a36Sopenharmony_ci return; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci for (i = 0; i < ntevs; i++) { 13262306a36Sopenharmony_ci tev = &pev->tevs[i]; 13362306a36Sopenharmony_ci map__for_each_symbol(map, sym, tmp) { 13462306a36Sopenharmony_ci if (map__unmap_ip(map, sym->start) == tev->point.address) { 13562306a36Sopenharmony_ci arch__fix_tev_from_maps(pev, tev, map, sym); 13662306a36Sopenharmony_ci break; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci#endif /* HAVE_LIBELF_SUPPORT */ 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#endif 144