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