1*387f9dfdSAndroid Build Coastguard Worker /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2*387f9dfdSAndroid Build Coastguard Worker // Copyright (c) 2020 Wenbo Zhang
3*387f9dfdSAndroid Build Coastguard Worker //
4*387f9dfdSAndroid Build Coastguard Worker // Based on ksyms improvements from Andrii Nakryiko, add more helpers.
5*387f9dfdSAndroid Build Coastguard Worker // 28-Feb-2020 Wenbo Zhang Created this.
6*387f9dfdSAndroid Build Coastguard Worker #ifndef _GNU_SOURCE
7*387f9dfdSAndroid Build Coastguard Worker #define _GNU_SOURCE
8*387f9dfdSAndroid Build Coastguard Worker #endif
9*387f9dfdSAndroid Build Coastguard Worker #include <ctype.h>
10*387f9dfdSAndroid Build Coastguard Worker #include <stdio.h>
11*387f9dfdSAndroid Build Coastguard Worker #include <stdlib.h>
12*387f9dfdSAndroid Build Coastguard Worker #include <string.h>
13*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
14*387f9dfdSAndroid Build Coastguard Worker #include <errno.h>
15*387f9dfdSAndroid Build Coastguard Worker #include <fcntl.h>
16*387f9dfdSAndroid Build Coastguard Worker #include <sys/resource.h>
17*387f9dfdSAndroid Build Coastguard Worker #include <time.h>
18*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf.h>
19*387f9dfdSAndroid Build Coastguard Worker #include <bpf/btf.h>
20*387f9dfdSAndroid Build Coastguard Worker #include <bpf/libbpf.h>
21*387f9dfdSAndroid Build Coastguard Worker #include <limits.h>
22*387f9dfdSAndroid Build Coastguard Worker #include "trace_helpers.h"
23*387f9dfdSAndroid Build Coastguard Worker #include "uprobe_helpers.h"
24*387f9dfdSAndroid Build Coastguard Worker
25*387f9dfdSAndroid Build Coastguard Worker #define min(x, y) ({ \
26*387f9dfdSAndroid Build Coastguard Worker typeof(x) _min1 = (x); \
27*387f9dfdSAndroid Build Coastguard Worker typeof(y) _min2 = (y); \
28*387f9dfdSAndroid Build Coastguard Worker (void) (&_min1 == &_min2); \
29*387f9dfdSAndroid Build Coastguard Worker _min1 < _min2 ? _min1 : _min2; })
30*387f9dfdSAndroid Build Coastguard Worker
31*387f9dfdSAndroid Build Coastguard Worker #define DISK_NAME_LEN 32
32*387f9dfdSAndroid Build Coastguard Worker
33*387f9dfdSAndroid Build Coastguard Worker #define MINORBITS 20
34*387f9dfdSAndroid Build Coastguard Worker #define MINORMASK ((1U << MINORBITS) - 1)
35*387f9dfdSAndroid Build Coastguard Worker
36*387f9dfdSAndroid Build Coastguard Worker #define MKDEV(ma, mi) (((ma) << MINORBITS) | (mi))
37*387f9dfdSAndroid Build Coastguard Worker
38*387f9dfdSAndroid Build Coastguard Worker struct ksyms {
39*387f9dfdSAndroid Build Coastguard Worker struct ksym *syms;
40*387f9dfdSAndroid Build Coastguard Worker int syms_sz;
41*387f9dfdSAndroid Build Coastguard Worker int syms_cap;
42*387f9dfdSAndroid Build Coastguard Worker char *strs;
43*387f9dfdSAndroid Build Coastguard Worker int strs_sz;
44*387f9dfdSAndroid Build Coastguard Worker int strs_cap;
45*387f9dfdSAndroid Build Coastguard Worker };
46*387f9dfdSAndroid Build Coastguard Worker
ksyms__add_symbol(struct ksyms * ksyms,const char * name,unsigned long addr)47*387f9dfdSAndroid Build Coastguard Worker static int ksyms__add_symbol(struct ksyms *ksyms, const char *name, unsigned long addr)
48*387f9dfdSAndroid Build Coastguard Worker {
49*387f9dfdSAndroid Build Coastguard Worker size_t new_cap, name_len = strlen(name) + 1;
50*387f9dfdSAndroid Build Coastguard Worker struct ksym *ksym;
51*387f9dfdSAndroid Build Coastguard Worker void *tmp;
52*387f9dfdSAndroid Build Coastguard Worker
53*387f9dfdSAndroid Build Coastguard Worker if (ksyms->strs_sz + name_len > ksyms->strs_cap) {
54*387f9dfdSAndroid Build Coastguard Worker new_cap = ksyms->strs_cap * 4 / 3;
55*387f9dfdSAndroid Build Coastguard Worker if (new_cap < ksyms->strs_sz + name_len)
56*387f9dfdSAndroid Build Coastguard Worker new_cap = ksyms->strs_sz + name_len;
57*387f9dfdSAndroid Build Coastguard Worker if (new_cap < 1024)
58*387f9dfdSAndroid Build Coastguard Worker new_cap = 1024;
59*387f9dfdSAndroid Build Coastguard Worker tmp = realloc(ksyms->strs, new_cap);
60*387f9dfdSAndroid Build Coastguard Worker if (!tmp)
61*387f9dfdSAndroid Build Coastguard Worker return -1;
62*387f9dfdSAndroid Build Coastguard Worker ksyms->strs = tmp;
63*387f9dfdSAndroid Build Coastguard Worker ksyms->strs_cap = new_cap;
64*387f9dfdSAndroid Build Coastguard Worker }
65*387f9dfdSAndroid Build Coastguard Worker if (ksyms->syms_sz + 1 > ksyms->syms_cap) {
66*387f9dfdSAndroid Build Coastguard Worker new_cap = ksyms->syms_cap * 4 / 3;
67*387f9dfdSAndroid Build Coastguard Worker if (new_cap < 1024)
68*387f9dfdSAndroid Build Coastguard Worker new_cap = 1024;
69*387f9dfdSAndroid Build Coastguard Worker tmp = realloc(ksyms->syms, sizeof(*ksyms->syms) * new_cap);
70*387f9dfdSAndroid Build Coastguard Worker if (!tmp)
71*387f9dfdSAndroid Build Coastguard Worker return -1;
72*387f9dfdSAndroid Build Coastguard Worker ksyms->syms = tmp;
73*387f9dfdSAndroid Build Coastguard Worker ksyms->syms_cap = new_cap;
74*387f9dfdSAndroid Build Coastguard Worker }
75*387f9dfdSAndroid Build Coastguard Worker
76*387f9dfdSAndroid Build Coastguard Worker ksym = &ksyms->syms[ksyms->syms_sz];
77*387f9dfdSAndroid Build Coastguard Worker /* while constructing, re-use pointer as just a plain offset */
78*387f9dfdSAndroid Build Coastguard Worker ksym->name = (void *)(unsigned long)ksyms->strs_sz;
79*387f9dfdSAndroid Build Coastguard Worker ksym->addr = addr;
80*387f9dfdSAndroid Build Coastguard Worker
81*387f9dfdSAndroid Build Coastguard Worker memcpy(ksyms->strs + ksyms->strs_sz, name, name_len);
82*387f9dfdSAndroid Build Coastguard Worker ksyms->strs_sz += name_len;
83*387f9dfdSAndroid Build Coastguard Worker ksyms->syms_sz++;
84*387f9dfdSAndroid Build Coastguard Worker
85*387f9dfdSAndroid Build Coastguard Worker return 0;
86*387f9dfdSAndroid Build Coastguard Worker }
87*387f9dfdSAndroid Build Coastguard Worker
ksym_cmp(const void * p1,const void * p2)88*387f9dfdSAndroid Build Coastguard Worker static int ksym_cmp(const void *p1, const void *p2)
89*387f9dfdSAndroid Build Coastguard Worker {
90*387f9dfdSAndroid Build Coastguard Worker const struct ksym *s1 = p1, *s2 = p2;
91*387f9dfdSAndroid Build Coastguard Worker
92*387f9dfdSAndroid Build Coastguard Worker if (s1->addr == s2->addr)
93*387f9dfdSAndroid Build Coastguard Worker return strcmp(s1->name, s2->name);
94*387f9dfdSAndroid Build Coastguard Worker return s1->addr < s2->addr ? -1 : 1;
95*387f9dfdSAndroid Build Coastguard Worker }
96*387f9dfdSAndroid Build Coastguard Worker
ksyms__load(void)97*387f9dfdSAndroid Build Coastguard Worker struct ksyms *ksyms__load(void)
98*387f9dfdSAndroid Build Coastguard Worker {
99*387f9dfdSAndroid Build Coastguard Worker char sym_type, sym_name[256];
100*387f9dfdSAndroid Build Coastguard Worker struct ksyms *ksyms;
101*387f9dfdSAndroid Build Coastguard Worker unsigned long sym_addr;
102*387f9dfdSAndroid Build Coastguard Worker int i, ret;
103*387f9dfdSAndroid Build Coastguard Worker FILE *f;
104*387f9dfdSAndroid Build Coastguard Worker
105*387f9dfdSAndroid Build Coastguard Worker f = fopen("/proc/kallsyms", "r");
106*387f9dfdSAndroid Build Coastguard Worker if (!f)
107*387f9dfdSAndroid Build Coastguard Worker return NULL;
108*387f9dfdSAndroid Build Coastguard Worker
109*387f9dfdSAndroid Build Coastguard Worker ksyms = calloc(1, sizeof(*ksyms));
110*387f9dfdSAndroid Build Coastguard Worker if (!ksyms)
111*387f9dfdSAndroid Build Coastguard Worker goto err_out;
112*387f9dfdSAndroid Build Coastguard Worker
113*387f9dfdSAndroid Build Coastguard Worker while (true) {
114*387f9dfdSAndroid Build Coastguard Worker ret = fscanf(f, "%lx %c %s%*[^\n]\n",
115*387f9dfdSAndroid Build Coastguard Worker &sym_addr, &sym_type, sym_name);
116*387f9dfdSAndroid Build Coastguard Worker if (ret == EOF && feof(f))
117*387f9dfdSAndroid Build Coastguard Worker break;
118*387f9dfdSAndroid Build Coastguard Worker if (ret != 3)
119*387f9dfdSAndroid Build Coastguard Worker goto err_out;
120*387f9dfdSAndroid Build Coastguard Worker if (ksyms__add_symbol(ksyms, sym_name, sym_addr))
121*387f9dfdSAndroid Build Coastguard Worker goto err_out;
122*387f9dfdSAndroid Build Coastguard Worker }
123*387f9dfdSAndroid Build Coastguard Worker
124*387f9dfdSAndroid Build Coastguard Worker /* now when strings are finalized, adjust pointers properly */
125*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < ksyms->syms_sz; i++)
126*387f9dfdSAndroid Build Coastguard Worker ksyms->syms[i].name += (unsigned long)ksyms->strs;
127*387f9dfdSAndroid Build Coastguard Worker
128*387f9dfdSAndroid Build Coastguard Worker qsort(ksyms->syms, ksyms->syms_sz, sizeof(*ksyms->syms), ksym_cmp);
129*387f9dfdSAndroid Build Coastguard Worker
130*387f9dfdSAndroid Build Coastguard Worker fclose(f);
131*387f9dfdSAndroid Build Coastguard Worker return ksyms;
132*387f9dfdSAndroid Build Coastguard Worker
133*387f9dfdSAndroid Build Coastguard Worker err_out:
134*387f9dfdSAndroid Build Coastguard Worker ksyms__free(ksyms);
135*387f9dfdSAndroid Build Coastguard Worker fclose(f);
136*387f9dfdSAndroid Build Coastguard Worker return NULL;
137*387f9dfdSAndroid Build Coastguard Worker }
138*387f9dfdSAndroid Build Coastguard Worker
ksyms__free(struct ksyms * ksyms)139*387f9dfdSAndroid Build Coastguard Worker void ksyms__free(struct ksyms *ksyms)
140*387f9dfdSAndroid Build Coastguard Worker {
141*387f9dfdSAndroid Build Coastguard Worker if (!ksyms)
142*387f9dfdSAndroid Build Coastguard Worker return;
143*387f9dfdSAndroid Build Coastguard Worker
144*387f9dfdSAndroid Build Coastguard Worker free(ksyms->syms);
145*387f9dfdSAndroid Build Coastguard Worker free(ksyms->strs);
146*387f9dfdSAndroid Build Coastguard Worker free(ksyms);
147*387f9dfdSAndroid Build Coastguard Worker }
148*387f9dfdSAndroid Build Coastguard Worker
ksyms__map_addr(const struct ksyms * ksyms,unsigned long addr)149*387f9dfdSAndroid Build Coastguard Worker const struct ksym *ksyms__map_addr(const struct ksyms *ksyms,
150*387f9dfdSAndroid Build Coastguard Worker unsigned long addr)
151*387f9dfdSAndroid Build Coastguard Worker {
152*387f9dfdSAndroid Build Coastguard Worker int start = 0, end = ksyms->syms_sz - 1, mid;
153*387f9dfdSAndroid Build Coastguard Worker unsigned long sym_addr;
154*387f9dfdSAndroid Build Coastguard Worker
155*387f9dfdSAndroid Build Coastguard Worker /* find largest sym_addr <= addr using binary search */
156*387f9dfdSAndroid Build Coastguard Worker while (start < end) {
157*387f9dfdSAndroid Build Coastguard Worker mid = start + (end - start + 1) / 2;
158*387f9dfdSAndroid Build Coastguard Worker sym_addr = ksyms->syms[mid].addr;
159*387f9dfdSAndroid Build Coastguard Worker
160*387f9dfdSAndroid Build Coastguard Worker if (sym_addr <= addr)
161*387f9dfdSAndroid Build Coastguard Worker start = mid;
162*387f9dfdSAndroid Build Coastguard Worker else
163*387f9dfdSAndroid Build Coastguard Worker end = mid - 1;
164*387f9dfdSAndroid Build Coastguard Worker }
165*387f9dfdSAndroid Build Coastguard Worker
166*387f9dfdSAndroid Build Coastguard Worker if (start == end && ksyms->syms[start].addr <= addr)
167*387f9dfdSAndroid Build Coastguard Worker return &ksyms->syms[start];
168*387f9dfdSAndroid Build Coastguard Worker return NULL;
169*387f9dfdSAndroid Build Coastguard Worker }
170*387f9dfdSAndroid Build Coastguard Worker
ksyms__get_symbol(const struct ksyms * ksyms,const char * name)171*387f9dfdSAndroid Build Coastguard Worker const struct ksym *ksyms__get_symbol(const struct ksyms *ksyms,
172*387f9dfdSAndroid Build Coastguard Worker const char *name)
173*387f9dfdSAndroid Build Coastguard Worker {
174*387f9dfdSAndroid Build Coastguard Worker int i;
175*387f9dfdSAndroid Build Coastguard Worker
176*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < ksyms->syms_sz; i++) {
177*387f9dfdSAndroid Build Coastguard Worker if (strcmp(ksyms->syms[i].name, name) == 0)
178*387f9dfdSAndroid Build Coastguard Worker return &ksyms->syms[i];
179*387f9dfdSAndroid Build Coastguard Worker }
180*387f9dfdSAndroid Build Coastguard Worker
181*387f9dfdSAndroid Build Coastguard Worker return NULL;
182*387f9dfdSAndroid Build Coastguard Worker }
183*387f9dfdSAndroid Build Coastguard Worker
184*387f9dfdSAndroid Build Coastguard Worker struct load_range {
185*387f9dfdSAndroid Build Coastguard Worker uint64_t start;
186*387f9dfdSAndroid Build Coastguard Worker uint64_t end;
187*387f9dfdSAndroid Build Coastguard Worker uint64_t file_off;
188*387f9dfdSAndroid Build Coastguard Worker };
189*387f9dfdSAndroid Build Coastguard Worker
190*387f9dfdSAndroid Build Coastguard Worker enum elf_type {
191*387f9dfdSAndroid Build Coastguard Worker EXEC,
192*387f9dfdSAndroid Build Coastguard Worker DYN,
193*387f9dfdSAndroid Build Coastguard Worker PERF_MAP,
194*387f9dfdSAndroid Build Coastguard Worker VDSO,
195*387f9dfdSAndroid Build Coastguard Worker UNKNOWN,
196*387f9dfdSAndroid Build Coastguard Worker };
197*387f9dfdSAndroid Build Coastguard Worker
198*387f9dfdSAndroid Build Coastguard Worker struct dso {
199*387f9dfdSAndroid Build Coastguard Worker char *name;
200*387f9dfdSAndroid Build Coastguard Worker struct load_range *ranges;
201*387f9dfdSAndroid Build Coastguard Worker int range_sz;
202*387f9dfdSAndroid Build Coastguard Worker /* Dyn's first text section virtual addr at execution */
203*387f9dfdSAndroid Build Coastguard Worker uint64_t sh_addr;
204*387f9dfdSAndroid Build Coastguard Worker /* Dyn's first text section file offset */
205*387f9dfdSAndroid Build Coastguard Worker uint64_t sh_offset;
206*387f9dfdSAndroid Build Coastguard Worker enum elf_type type;
207*387f9dfdSAndroid Build Coastguard Worker
208*387f9dfdSAndroid Build Coastguard Worker struct sym *syms;
209*387f9dfdSAndroid Build Coastguard Worker int syms_sz;
210*387f9dfdSAndroid Build Coastguard Worker int syms_cap;
211*387f9dfdSAndroid Build Coastguard Worker
212*387f9dfdSAndroid Build Coastguard Worker /*
213*387f9dfdSAndroid Build Coastguard Worker * libbpf's struct btf is actually a pretty efficient
214*387f9dfdSAndroid Build Coastguard Worker * "set of strings" data structure, so we create an
215*387f9dfdSAndroid Build Coastguard Worker * empty one and use it to store symbol names.
216*387f9dfdSAndroid Build Coastguard Worker */
217*387f9dfdSAndroid Build Coastguard Worker struct btf *btf;
218*387f9dfdSAndroid Build Coastguard Worker };
219*387f9dfdSAndroid Build Coastguard Worker
220*387f9dfdSAndroid Build Coastguard Worker struct map {
221*387f9dfdSAndroid Build Coastguard Worker uint64_t start_addr;
222*387f9dfdSAndroid Build Coastguard Worker uint64_t end_addr;
223*387f9dfdSAndroid Build Coastguard Worker uint64_t file_off;
224*387f9dfdSAndroid Build Coastguard Worker uint64_t dev_major;
225*387f9dfdSAndroid Build Coastguard Worker uint64_t dev_minor;
226*387f9dfdSAndroid Build Coastguard Worker uint64_t inode;
227*387f9dfdSAndroid Build Coastguard Worker };
228*387f9dfdSAndroid Build Coastguard Worker
229*387f9dfdSAndroid Build Coastguard Worker struct syms {
230*387f9dfdSAndroid Build Coastguard Worker struct dso *dsos;
231*387f9dfdSAndroid Build Coastguard Worker int dso_sz;
232*387f9dfdSAndroid Build Coastguard Worker };
233*387f9dfdSAndroid Build Coastguard Worker
is_file_backed(const char * mapname)234*387f9dfdSAndroid Build Coastguard Worker static bool is_file_backed(const char *mapname)
235*387f9dfdSAndroid Build Coastguard Worker {
236*387f9dfdSAndroid Build Coastguard Worker #define STARTS_WITH(mapname, prefix) \
237*387f9dfdSAndroid Build Coastguard Worker (!strncmp(mapname, prefix, sizeof(prefix) - 1))
238*387f9dfdSAndroid Build Coastguard Worker
239*387f9dfdSAndroid Build Coastguard Worker return mapname[0] && !(
240*387f9dfdSAndroid Build Coastguard Worker STARTS_WITH(mapname, "//anon") ||
241*387f9dfdSAndroid Build Coastguard Worker STARTS_WITH(mapname, "/dev/zero") ||
242*387f9dfdSAndroid Build Coastguard Worker STARTS_WITH(mapname, "/anon_hugepage") ||
243*387f9dfdSAndroid Build Coastguard Worker STARTS_WITH(mapname, "[stack") ||
244*387f9dfdSAndroid Build Coastguard Worker STARTS_WITH(mapname, "/SYSV") ||
245*387f9dfdSAndroid Build Coastguard Worker STARTS_WITH(mapname, "[heap]") ||
246*387f9dfdSAndroid Build Coastguard Worker STARTS_WITH(mapname, "[uprobes]") ||
247*387f9dfdSAndroid Build Coastguard Worker STARTS_WITH(mapname, "[vsyscall]"));
248*387f9dfdSAndroid Build Coastguard Worker }
249*387f9dfdSAndroid Build Coastguard Worker
is_perf_map(const char * path)250*387f9dfdSAndroid Build Coastguard Worker static bool is_perf_map(const char *path)
251*387f9dfdSAndroid Build Coastguard Worker {
252*387f9dfdSAndroid Build Coastguard Worker return false;
253*387f9dfdSAndroid Build Coastguard Worker }
254*387f9dfdSAndroid Build Coastguard Worker
is_vdso(const char * path)255*387f9dfdSAndroid Build Coastguard Worker static bool is_vdso(const char *path)
256*387f9dfdSAndroid Build Coastguard Worker {
257*387f9dfdSAndroid Build Coastguard Worker return !strcmp(path, "[vdso]");
258*387f9dfdSAndroid Build Coastguard Worker }
259*387f9dfdSAndroid Build Coastguard Worker
is_uprobes(const char * path)260*387f9dfdSAndroid Build Coastguard Worker static bool is_uprobes(const char *path)
261*387f9dfdSAndroid Build Coastguard Worker {
262*387f9dfdSAndroid Build Coastguard Worker return !strcmp(path, "[uprobes]");
263*387f9dfdSAndroid Build Coastguard Worker }
264*387f9dfdSAndroid Build Coastguard Worker
get_elf_type(const char * path)265*387f9dfdSAndroid Build Coastguard Worker static int get_elf_type(const char *path)
266*387f9dfdSAndroid Build Coastguard Worker {
267*387f9dfdSAndroid Build Coastguard Worker GElf_Ehdr hdr;
268*387f9dfdSAndroid Build Coastguard Worker void *res;
269*387f9dfdSAndroid Build Coastguard Worker Elf *e;
270*387f9dfdSAndroid Build Coastguard Worker int fd;
271*387f9dfdSAndroid Build Coastguard Worker
272*387f9dfdSAndroid Build Coastguard Worker if (is_vdso(path))
273*387f9dfdSAndroid Build Coastguard Worker return -1;
274*387f9dfdSAndroid Build Coastguard Worker if (is_uprobes(path))
275*387f9dfdSAndroid Build Coastguard Worker return -1;
276*387f9dfdSAndroid Build Coastguard Worker e = open_elf(path, &fd);
277*387f9dfdSAndroid Build Coastguard Worker if (!e)
278*387f9dfdSAndroid Build Coastguard Worker return -1;
279*387f9dfdSAndroid Build Coastguard Worker res = gelf_getehdr(e, &hdr);
280*387f9dfdSAndroid Build Coastguard Worker close_elf(e, fd);
281*387f9dfdSAndroid Build Coastguard Worker if (!res)
282*387f9dfdSAndroid Build Coastguard Worker return -1;
283*387f9dfdSAndroid Build Coastguard Worker return hdr.e_type;
284*387f9dfdSAndroid Build Coastguard Worker }
285*387f9dfdSAndroid Build Coastguard Worker
get_elf_text_scn_info(const char * path,uint64_t * addr,uint64_t * offset)286*387f9dfdSAndroid Build Coastguard Worker static int get_elf_text_scn_info(const char *path, uint64_t *addr,
287*387f9dfdSAndroid Build Coastguard Worker uint64_t *offset)
288*387f9dfdSAndroid Build Coastguard Worker {
289*387f9dfdSAndroid Build Coastguard Worker Elf_Scn *section = NULL;
290*387f9dfdSAndroid Build Coastguard Worker int fd = -1, err = -1;
291*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr header;
292*387f9dfdSAndroid Build Coastguard Worker size_t stridx;
293*387f9dfdSAndroid Build Coastguard Worker Elf *e = NULL;
294*387f9dfdSAndroid Build Coastguard Worker char *name;
295*387f9dfdSAndroid Build Coastguard Worker
296*387f9dfdSAndroid Build Coastguard Worker e = open_elf(path, &fd);
297*387f9dfdSAndroid Build Coastguard Worker if (!e)
298*387f9dfdSAndroid Build Coastguard Worker goto err_out;
299*387f9dfdSAndroid Build Coastguard Worker err = elf_getshdrstrndx(e, &stridx);
300*387f9dfdSAndroid Build Coastguard Worker if (err < 0)
301*387f9dfdSAndroid Build Coastguard Worker goto err_out;
302*387f9dfdSAndroid Build Coastguard Worker
303*387f9dfdSAndroid Build Coastguard Worker err = -1;
304*387f9dfdSAndroid Build Coastguard Worker while ((section = elf_nextscn(e, section)) != 0) {
305*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getshdr(section, &header))
306*387f9dfdSAndroid Build Coastguard Worker continue;
307*387f9dfdSAndroid Build Coastguard Worker
308*387f9dfdSAndroid Build Coastguard Worker name = elf_strptr(e, stridx, header.sh_name);
309*387f9dfdSAndroid Build Coastguard Worker if (name && !strcmp(name, ".text")) {
310*387f9dfdSAndroid Build Coastguard Worker *addr = (uint64_t)header.sh_addr;
311*387f9dfdSAndroid Build Coastguard Worker *offset = (uint64_t)header.sh_offset;
312*387f9dfdSAndroid Build Coastguard Worker err = 0;
313*387f9dfdSAndroid Build Coastguard Worker break;
314*387f9dfdSAndroid Build Coastguard Worker }
315*387f9dfdSAndroid Build Coastguard Worker }
316*387f9dfdSAndroid Build Coastguard Worker
317*387f9dfdSAndroid Build Coastguard Worker err_out:
318*387f9dfdSAndroid Build Coastguard Worker close_elf(e, fd);
319*387f9dfdSAndroid Build Coastguard Worker return err;
320*387f9dfdSAndroid Build Coastguard Worker }
321*387f9dfdSAndroid Build Coastguard Worker
syms__add_dso(struct syms * syms,struct map * map,const char * name)322*387f9dfdSAndroid Build Coastguard Worker static int syms__add_dso(struct syms *syms, struct map *map, const char *name)
323*387f9dfdSAndroid Build Coastguard Worker {
324*387f9dfdSAndroid Build Coastguard Worker struct dso *dso = NULL;
325*387f9dfdSAndroid Build Coastguard Worker int i, type;
326*387f9dfdSAndroid Build Coastguard Worker void *tmp;
327*387f9dfdSAndroid Build Coastguard Worker
328*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < syms->dso_sz; i++) {
329*387f9dfdSAndroid Build Coastguard Worker if (!strcmp(syms->dsos[i].name, name)) {
330*387f9dfdSAndroid Build Coastguard Worker dso = &syms->dsos[i];
331*387f9dfdSAndroid Build Coastguard Worker break;
332*387f9dfdSAndroid Build Coastguard Worker }
333*387f9dfdSAndroid Build Coastguard Worker }
334*387f9dfdSAndroid Build Coastguard Worker
335*387f9dfdSAndroid Build Coastguard Worker if (!dso) {
336*387f9dfdSAndroid Build Coastguard Worker tmp = realloc(syms->dsos, (syms->dso_sz + 1) *
337*387f9dfdSAndroid Build Coastguard Worker sizeof(*syms->dsos));
338*387f9dfdSAndroid Build Coastguard Worker if (!tmp)
339*387f9dfdSAndroid Build Coastguard Worker return -1;
340*387f9dfdSAndroid Build Coastguard Worker syms->dsos = tmp;
341*387f9dfdSAndroid Build Coastguard Worker dso = &syms->dsos[syms->dso_sz++];
342*387f9dfdSAndroid Build Coastguard Worker memset(dso, 0, sizeof(*dso));
343*387f9dfdSAndroid Build Coastguard Worker dso->name = strdup(name);
344*387f9dfdSAndroid Build Coastguard Worker dso->btf = btf__new_empty();
345*387f9dfdSAndroid Build Coastguard Worker }
346*387f9dfdSAndroid Build Coastguard Worker
347*387f9dfdSAndroid Build Coastguard Worker tmp = realloc(dso->ranges, (dso->range_sz + 1) * sizeof(*dso->ranges));
348*387f9dfdSAndroid Build Coastguard Worker if (!tmp)
349*387f9dfdSAndroid Build Coastguard Worker return -1;
350*387f9dfdSAndroid Build Coastguard Worker dso->ranges = tmp;
351*387f9dfdSAndroid Build Coastguard Worker dso->ranges[dso->range_sz].start = map->start_addr;
352*387f9dfdSAndroid Build Coastguard Worker dso->ranges[dso->range_sz].end = map->end_addr;
353*387f9dfdSAndroid Build Coastguard Worker dso->ranges[dso->range_sz].file_off = map->file_off;
354*387f9dfdSAndroid Build Coastguard Worker dso->range_sz++;
355*387f9dfdSAndroid Build Coastguard Worker type = get_elf_type(name);
356*387f9dfdSAndroid Build Coastguard Worker if (type == ET_EXEC) {
357*387f9dfdSAndroid Build Coastguard Worker dso->type = EXEC;
358*387f9dfdSAndroid Build Coastguard Worker } else if (type == ET_DYN) {
359*387f9dfdSAndroid Build Coastguard Worker dso->type = DYN;
360*387f9dfdSAndroid Build Coastguard Worker if (get_elf_text_scn_info(name, &dso->sh_addr, &dso->sh_offset) < 0)
361*387f9dfdSAndroid Build Coastguard Worker return -1;
362*387f9dfdSAndroid Build Coastguard Worker } else if (is_perf_map(name)) {
363*387f9dfdSAndroid Build Coastguard Worker dso->type = PERF_MAP;
364*387f9dfdSAndroid Build Coastguard Worker } else if (is_vdso(name)) {
365*387f9dfdSAndroid Build Coastguard Worker dso->type = VDSO;
366*387f9dfdSAndroid Build Coastguard Worker } else {
367*387f9dfdSAndroid Build Coastguard Worker dso->type = UNKNOWN;
368*387f9dfdSAndroid Build Coastguard Worker }
369*387f9dfdSAndroid Build Coastguard Worker return 0;
370*387f9dfdSAndroid Build Coastguard Worker }
371*387f9dfdSAndroid Build Coastguard Worker
syms__find_dso(const struct syms * syms,unsigned long addr,uint64_t * offset)372*387f9dfdSAndroid Build Coastguard Worker static struct dso *syms__find_dso(const struct syms *syms, unsigned long addr,
373*387f9dfdSAndroid Build Coastguard Worker uint64_t *offset)
374*387f9dfdSAndroid Build Coastguard Worker {
375*387f9dfdSAndroid Build Coastguard Worker struct load_range *range;
376*387f9dfdSAndroid Build Coastguard Worker struct dso *dso;
377*387f9dfdSAndroid Build Coastguard Worker int i, j;
378*387f9dfdSAndroid Build Coastguard Worker
379*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < syms->dso_sz; i++) {
380*387f9dfdSAndroid Build Coastguard Worker dso = &syms->dsos[i];
381*387f9dfdSAndroid Build Coastguard Worker for (j = 0; j < dso->range_sz; j++) {
382*387f9dfdSAndroid Build Coastguard Worker range = &dso->ranges[j];
383*387f9dfdSAndroid Build Coastguard Worker if (addr <= range->start || addr >= range->end)
384*387f9dfdSAndroid Build Coastguard Worker continue;
385*387f9dfdSAndroid Build Coastguard Worker if (dso->type == DYN || dso->type == VDSO) {
386*387f9dfdSAndroid Build Coastguard Worker /* Offset within the mmap */
387*387f9dfdSAndroid Build Coastguard Worker *offset = addr - range->start + range->file_off;
388*387f9dfdSAndroid Build Coastguard Worker /* Offset within the ELF for dyn symbol lookup */
389*387f9dfdSAndroid Build Coastguard Worker *offset += dso->sh_addr - dso->sh_offset;
390*387f9dfdSAndroid Build Coastguard Worker } else {
391*387f9dfdSAndroid Build Coastguard Worker *offset = addr;
392*387f9dfdSAndroid Build Coastguard Worker }
393*387f9dfdSAndroid Build Coastguard Worker
394*387f9dfdSAndroid Build Coastguard Worker return dso;
395*387f9dfdSAndroid Build Coastguard Worker }
396*387f9dfdSAndroid Build Coastguard Worker }
397*387f9dfdSAndroid Build Coastguard Worker
398*387f9dfdSAndroid Build Coastguard Worker return NULL;
399*387f9dfdSAndroid Build Coastguard Worker }
400*387f9dfdSAndroid Build Coastguard Worker
dso__load_sym_table_from_perf_map(struct dso * dso)401*387f9dfdSAndroid Build Coastguard Worker static int dso__load_sym_table_from_perf_map(struct dso *dso)
402*387f9dfdSAndroid Build Coastguard Worker {
403*387f9dfdSAndroid Build Coastguard Worker return -1;
404*387f9dfdSAndroid Build Coastguard Worker }
405*387f9dfdSAndroid Build Coastguard Worker
dso__add_sym(struct dso * dso,const char * name,uint64_t start,uint64_t size)406*387f9dfdSAndroid Build Coastguard Worker static int dso__add_sym(struct dso *dso, const char *name, uint64_t start,
407*387f9dfdSAndroid Build Coastguard Worker uint64_t size)
408*387f9dfdSAndroid Build Coastguard Worker {
409*387f9dfdSAndroid Build Coastguard Worker struct sym *sym;
410*387f9dfdSAndroid Build Coastguard Worker size_t new_cap;
411*387f9dfdSAndroid Build Coastguard Worker void *tmp;
412*387f9dfdSAndroid Build Coastguard Worker int off;
413*387f9dfdSAndroid Build Coastguard Worker
414*387f9dfdSAndroid Build Coastguard Worker off = btf__add_str(dso->btf, name);
415*387f9dfdSAndroid Build Coastguard Worker if (off < 0)
416*387f9dfdSAndroid Build Coastguard Worker return off;
417*387f9dfdSAndroid Build Coastguard Worker
418*387f9dfdSAndroid Build Coastguard Worker if (dso->syms_sz + 1 > dso->syms_cap) {
419*387f9dfdSAndroid Build Coastguard Worker new_cap = dso->syms_cap * 4 / 3;
420*387f9dfdSAndroid Build Coastguard Worker if (new_cap < 1024)
421*387f9dfdSAndroid Build Coastguard Worker new_cap = 1024;
422*387f9dfdSAndroid Build Coastguard Worker tmp = realloc(dso->syms, sizeof(*dso->syms) * new_cap);
423*387f9dfdSAndroid Build Coastguard Worker if (!tmp)
424*387f9dfdSAndroid Build Coastguard Worker return -1;
425*387f9dfdSAndroid Build Coastguard Worker dso->syms = tmp;
426*387f9dfdSAndroid Build Coastguard Worker dso->syms_cap = new_cap;
427*387f9dfdSAndroid Build Coastguard Worker }
428*387f9dfdSAndroid Build Coastguard Worker
429*387f9dfdSAndroid Build Coastguard Worker sym = &dso->syms[dso->syms_sz++];
430*387f9dfdSAndroid Build Coastguard Worker /* while constructing, re-use pointer as just a plain offset */
431*387f9dfdSAndroid Build Coastguard Worker sym->name = (void*)(unsigned long)off;
432*387f9dfdSAndroid Build Coastguard Worker sym->start = start;
433*387f9dfdSAndroid Build Coastguard Worker sym->size = size;
434*387f9dfdSAndroid Build Coastguard Worker sym->offset = 0;
435*387f9dfdSAndroid Build Coastguard Worker
436*387f9dfdSAndroid Build Coastguard Worker return 0;
437*387f9dfdSAndroid Build Coastguard Worker }
438*387f9dfdSAndroid Build Coastguard Worker
sym_cmp(const void * p1,const void * p2)439*387f9dfdSAndroid Build Coastguard Worker static int sym_cmp(const void *p1, const void *p2)
440*387f9dfdSAndroid Build Coastguard Worker {
441*387f9dfdSAndroid Build Coastguard Worker const struct sym *s1 = p1, *s2 = p2;
442*387f9dfdSAndroid Build Coastguard Worker
443*387f9dfdSAndroid Build Coastguard Worker if (s1->start == s2->start)
444*387f9dfdSAndroid Build Coastguard Worker return strcmp(s1->name, s2->name);
445*387f9dfdSAndroid Build Coastguard Worker return s1->start < s2->start ? -1 : 1;
446*387f9dfdSAndroid Build Coastguard Worker }
447*387f9dfdSAndroid Build Coastguard Worker
dso__add_syms(struct dso * dso,Elf * e,Elf_Scn * section,size_t stridx,size_t symsize)448*387f9dfdSAndroid Build Coastguard Worker static int dso__add_syms(struct dso *dso, Elf *e, Elf_Scn *section,
449*387f9dfdSAndroid Build Coastguard Worker size_t stridx, size_t symsize)
450*387f9dfdSAndroid Build Coastguard Worker {
451*387f9dfdSAndroid Build Coastguard Worker Elf_Data *data = NULL;
452*387f9dfdSAndroid Build Coastguard Worker
453*387f9dfdSAndroid Build Coastguard Worker while ((data = elf_getdata(section, data)) != 0) {
454*387f9dfdSAndroid Build Coastguard Worker size_t i, symcount = data->d_size / symsize;
455*387f9dfdSAndroid Build Coastguard Worker
456*387f9dfdSAndroid Build Coastguard Worker if (data->d_size % symsize)
457*387f9dfdSAndroid Build Coastguard Worker return -1;
458*387f9dfdSAndroid Build Coastguard Worker
459*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < symcount; ++i) {
460*387f9dfdSAndroid Build Coastguard Worker const char *name;
461*387f9dfdSAndroid Build Coastguard Worker GElf_Sym sym;
462*387f9dfdSAndroid Build Coastguard Worker
463*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getsym(data, (int)i, &sym))
464*387f9dfdSAndroid Build Coastguard Worker continue;
465*387f9dfdSAndroid Build Coastguard Worker if (!(name = elf_strptr(e, stridx, sym.st_name)))
466*387f9dfdSAndroid Build Coastguard Worker continue;
467*387f9dfdSAndroid Build Coastguard Worker if (name[0] == '\0')
468*387f9dfdSAndroid Build Coastguard Worker continue;
469*387f9dfdSAndroid Build Coastguard Worker
470*387f9dfdSAndroid Build Coastguard Worker if (sym.st_value == 0)
471*387f9dfdSAndroid Build Coastguard Worker continue;
472*387f9dfdSAndroid Build Coastguard Worker
473*387f9dfdSAndroid Build Coastguard Worker if (dso__add_sym(dso, name, sym.st_value, sym.st_size))
474*387f9dfdSAndroid Build Coastguard Worker goto err_out;
475*387f9dfdSAndroid Build Coastguard Worker }
476*387f9dfdSAndroid Build Coastguard Worker }
477*387f9dfdSAndroid Build Coastguard Worker
478*387f9dfdSAndroid Build Coastguard Worker return 0;
479*387f9dfdSAndroid Build Coastguard Worker
480*387f9dfdSAndroid Build Coastguard Worker err_out:
481*387f9dfdSAndroid Build Coastguard Worker return -1;
482*387f9dfdSAndroid Build Coastguard Worker }
483*387f9dfdSAndroid Build Coastguard Worker
dso__free_fields(struct dso * dso)484*387f9dfdSAndroid Build Coastguard Worker static void dso__free_fields(struct dso *dso)
485*387f9dfdSAndroid Build Coastguard Worker {
486*387f9dfdSAndroid Build Coastguard Worker if (!dso)
487*387f9dfdSAndroid Build Coastguard Worker return;
488*387f9dfdSAndroid Build Coastguard Worker
489*387f9dfdSAndroid Build Coastguard Worker free(dso->name);
490*387f9dfdSAndroid Build Coastguard Worker free(dso->ranges);
491*387f9dfdSAndroid Build Coastguard Worker free(dso->syms);
492*387f9dfdSAndroid Build Coastguard Worker btf__free(dso->btf);
493*387f9dfdSAndroid Build Coastguard Worker }
494*387f9dfdSAndroid Build Coastguard Worker
dso__load_sym_table_from_elf(struct dso * dso,int fd)495*387f9dfdSAndroid Build Coastguard Worker static int dso__load_sym_table_from_elf(struct dso *dso, int fd)
496*387f9dfdSAndroid Build Coastguard Worker {
497*387f9dfdSAndroid Build Coastguard Worker Elf_Scn *section = NULL;
498*387f9dfdSAndroid Build Coastguard Worker Elf *e;
499*387f9dfdSAndroid Build Coastguard Worker int i;
500*387f9dfdSAndroid Build Coastguard Worker
501*387f9dfdSAndroid Build Coastguard Worker e = fd > 0 ? open_elf_by_fd(fd) : open_elf(dso->name, &fd);
502*387f9dfdSAndroid Build Coastguard Worker if (!e)
503*387f9dfdSAndroid Build Coastguard Worker return -1;
504*387f9dfdSAndroid Build Coastguard Worker
505*387f9dfdSAndroid Build Coastguard Worker while ((section = elf_nextscn(e, section)) != 0) {
506*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr header;
507*387f9dfdSAndroid Build Coastguard Worker
508*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getshdr(section, &header))
509*387f9dfdSAndroid Build Coastguard Worker continue;
510*387f9dfdSAndroid Build Coastguard Worker
511*387f9dfdSAndroid Build Coastguard Worker if (header.sh_type != SHT_SYMTAB &&
512*387f9dfdSAndroid Build Coastguard Worker header.sh_type != SHT_DYNSYM)
513*387f9dfdSAndroid Build Coastguard Worker continue;
514*387f9dfdSAndroid Build Coastguard Worker
515*387f9dfdSAndroid Build Coastguard Worker if (dso__add_syms(dso, e, section, header.sh_link,
516*387f9dfdSAndroid Build Coastguard Worker header.sh_entsize))
517*387f9dfdSAndroid Build Coastguard Worker goto err_out;
518*387f9dfdSAndroid Build Coastguard Worker }
519*387f9dfdSAndroid Build Coastguard Worker
520*387f9dfdSAndroid Build Coastguard Worker /* now when strings are finalized, adjust pointers properly */
521*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < dso->syms_sz; i++)
522*387f9dfdSAndroid Build Coastguard Worker dso->syms[i].name =
523*387f9dfdSAndroid Build Coastguard Worker btf__name_by_offset(dso->btf,
524*387f9dfdSAndroid Build Coastguard Worker (unsigned long)dso->syms[i].name);
525*387f9dfdSAndroid Build Coastguard Worker
526*387f9dfdSAndroid Build Coastguard Worker qsort(dso->syms, dso->syms_sz, sizeof(*dso->syms), sym_cmp);
527*387f9dfdSAndroid Build Coastguard Worker
528*387f9dfdSAndroid Build Coastguard Worker close_elf(e, fd);
529*387f9dfdSAndroid Build Coastguard Worker return 0;
530*387f9dfdSAndroid Build Coastguard Worker
531*387f9dfdSAndroid Build Coastguard Worker err_out:
532*387f9dfdSAndroid Build Coastguard Worker dso__free_fields(dso);
533*387f9dfdSAndroid Build Coastguard Worker close_elf(e, fd);
534*387f9dfdSAndroid Build Coastguard Worker return -1;
535*387f9dfdSAndroid Build Coastguard Worker }
536*387f9dfdSAndroid Build Coastguard Worker
create_tmp_vdso_image(struct dso * dso)537*387f9dfdSAndroid Build Coastguard Worker static int create_tmp_vdso_image(struct dso *dso)
538*387f9dfdSAndroid Build Coastguard Worker {
539*387f9dfdSAndroid Build Coastguard Worker uint64_t start_addr, end_addr;
540*387f9dfdSAndroid Build Coastguard Worker long pid = getpid();
541*387f9dfdSAndroid Build Coastguard Worker char buf[PATH_MAX];
542*387f9dfdSAndroid Build Coastguard Worker void *image = NULL;
543*387f9dfdSAndroid Build Coastguard Worker char tmpfile[128];
544*387f9dfdSAndroid Build Coastguard Worker int ret, fd = -1;
545*387f9dfdSAndroid Build Coastguard Worker uint64_t sz;
546*387f9dfdSAndroid Build Coastguard Worker char *name;
547*387f9dfdSAndroid Build Coastguard Worker FILE *f;
548*387f9dfdSAndroid Build Coastguard Worker
549*387f9dfdSAndroid Build Coastguard Worker snprintf(tmpfile, sizeof(tmpfile), "/proc/%ld/maps", pid);
550*387f9dfdSAndroid Build Coastguard Worker f = fopen(tmpfile, "r");
551*387f9dfdSAndroid Build Coastguard Worker if (!f)
552*387f9dfdSAndroid Build Coastguard Worker return -1;
553*387f9dfdSAndroid Build Coastguard Worker
554*387f9dfdSAndroid Build Coastguard Worker while (true) {
555*387f9dfdSAndroid Build Coastguard Worker ret = fscanf(f, "%lx-%lx %*s %*x %*x:%*x %*u%[^\n]",
556*387f9dfdSAndroid Build Coastguard Worker &start_addr, &end_addr, buf);
557*387f9dfdSAndroid Build Coastguard Worker if (ret == EOF && feof(f))
558*387f9dfdSAndroid Build Coastguard Worker break;
559*387f9dfdSAndroid Build Coastguard Worker if (ret != 3)
560*387f9dfdSAndroid Build Coastguard Worker goto err_out;
561*387f9dfdSAndroid Build Coastguard Worker
562*387f9dfdSAndroid Build Coastguard Worker name = buf;
563*387f9dfdSAndroid Build Coastguard Worker while (isspace(*name))
564*387f9dfdSAndroid Build Coastguard Worker name++;
565*387f9dfdSAndroid Build Coastguard Worker if (!is_file_backed(name))
566*387f9dfdSAndroid Build Coastguard Worker continue;
567*387f9dfdSAndroid Build Coastguard Worker if (is_vdso(name))
568*387f9dfdSAndroid Build Coastguard Worker break;
569*387f9dfdSAndroid Build Coastguard Worker }
570*387f9dfdSAndroid Build Coastguard Worker
571*387f9dfdSAndroid Build Coastguard Worker sz = end_addr - start_addr;
572*387f9dfdSAndroid Build Coastguard Worker image = malloc(sz);
573*387f9dfdSAndroid Build Coastguard Worker if (!image)
574*387f9dfdSAndroid Build Coastguard Worker goto err_out;
575*387f9dfdSAndroid Build Coastguard Worker memcpy(image, (void *)start_addr, sz);
576*387f9dfdSAndroid Build Coastguard Worker
577*387f9dfdSAndroid Build Coastguard Worker snprintf(tmpfile, sizeof(tmpfile),
578*387f9dfdSAndroid Build Coastguard Worker "/tmp/libbpf_%ld_vdso_image_XXXXXX", pid);
579*387f9dfdSAndroid Build Coastguard Worker fd = mkostemp(tmpfile, O_CLOEXEC);
580*387f9dfdSAndroid Build Coastguard Worker if (fd < 0) {
581*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "failed to create temp file: %s\n",
582*387f9dfdSAndroid Build Coastguard Worker strerror(errno));
583*387f9dfdSAndroid Build Coastguard Worker goto err_out;
584*387f9dfdSAndroid Build Coastguard Worker }
585*387f9dfdSAndroid Build Coastguard Worker /* Unlink the file to avoid leaking */
586*387f9dfdSAndroid Build Coastguard Worker if (unlink(tmpfile) == -1)
587*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "failed to unlink %s: %s\n", tmpfile,
588*387f9dfdSAndroid Build Coastguard Worker strerror(errno));
589*387f9dfdSAndroid Build Coastguard Worker if (write(fd, image, sz) == -1) {
590*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "failed to write to vDSO image: %s\n",
591*387f9dfdSAndroid Build Coastguard Worker strerror(errno));
592*387f9dfdSAndroid Build Coastguard Worker close(fd);
593*387f9dfdSAndroid Build Coastguard Worker fd = -1;
594*387f9dfdSAndroid Build Coastguard Worker goto err_out;
595*387f9dfdSAndroid Build Coastguard Worker }
596*387f9dfdSAndroid Build Coastguard Worker
597*387f9dfdSAndroid Build Coastguard Worker err_out:
598*387f9dfdSAndroid Build Coastguard Worker fclose(f);
599*387f9dfdSAndroid Build Coastguard Worker free(image);
600*387f9dfdSAndroid Build Coastguard Worker return fd;
601*387f9dfdSAndroid Build Coastguard Worker }
602*387f9dfdSAndroid Build Coastguard Worker
dso__load_sym_table_from_vdso_image(struct dso * dso)603*387f9dfdSAndroid Build Coastguard Worker static int dso__load_sym_table_from_vdso_image(struct dso *dso)
604*387f9dfdSAndroid Build Coastguard Worker {
605*387f9dfdSAndroid Build Coastguard Worker int fd = create_tmp_vdso_image(dso);
606*387f9dfdSAndroid Build Coastguard Worker
607*387f9dfdSAndroid Build Coastguard Worker if (fd < 0)
608*387f9dfdSAndroid Build Coastguard Worker return -1;
609*387f9dfdSAndroid Build Coastguard Worker return dso__load_sym_table_from_elf(dso, fd);
610*387f9dfdSAndroid Build Coastguard Worker }
611*387f9dfdSAndroid Build Coastguard Worker
dso__load_sym_table(struct dso * dso)612*387f9dfdSAndroid Build Coastguard Worker static int dso__load_sym_table(struct dso *dso)
613*387f9dfdSAndroid Build Coastguard Worker {
614*387f9dfdSAndroid Build Coastguard Worker if (dso->type == UNKNOWN)
615*387f9dfdSAndroid Build Coastguard Worker return -1;
616*387f9dfdSAndroid Build Coastguard Worker if (dso->type == PERF_MAP)
617*387f9dfdSAndroid Build Coastguard Worker return dso__load_sym_table_from_perf_map(dso);
618*387f9dfdSAndroid Build Coastguard Worker if (dso->type == EXEC || dso->type == DYN)
619*387f9dfdSAndroid Build Coastguard Worker return dso__load_sym_table_from_elf(dso, 0);
620*387f9dfdSAndroid Build Coastguard Worker if (dso->type == VDSO)
621*387f9dfdSAndroid Build Coastguard Worker return dso__load_sym_table_from_vdso_image(dso);
622*387f9dfdSAndroid Build Coastguard Worker return -1;
623*387f9dfdSAndroid Build Coastguard Worker }
624*387f9dfdSAndroid Build Coastguard Worker
dso__find_sym(struct dso * dso,uint64_t offset)625*387f9dfdSAndroid Build Coastguard Worker static struct sym *dso__find_sym(struct dso *dso, uint64_t offset)
626*387f9dfdSAndroid Build Coastguard Worker {
627*387f9dfdSAndroid Build Coastguard Worker unsigned long sym_addr;
628*387f9dfdSAndroid Build Coastguard Worker int start, end, mid;
629*387f9dfdSAndroid Build Coastguard Worker
630*387f9dfdSAndroid Build Coastguard Worker if (!dso->syms && dso__load_sym_table(dso))
631*387f9dfdSAndroid Build Coastguard Worker return NULL;
632*387f9dfdSAndroid Build Coastguard Worker
633*387f9dfdSAndroid Build Coastguard Worker start = 0;
634*387f9dfdSAndroid Build Coastguard Worker end = dso->syms_sz - 1;
635*387f9dfdSAndroid Build Coastguard Worker
636*387f9dfdSAndroid Build Coastguard Worker /* find largest sym_addr <= addr using binary search */
637*387f9dfdSAndroid Build Coastguard Worker while (start < end) {
638*387f9dfdSAndroid Build Coastguard Worker mid = start + (end - start + 1) / 2;
639*387f9dfdSAndroid Build Coastguard Worker sym_addr = dso->syms[mid].start;
640*387f9dfdSAndroid Build Coastguard Worker
641*387f9dfdSAndroid Build Coastguard Worker if (sym_addr <= offset)
642*387f9dfdSAndroid Build Coastguard Worker start = mid;
643*387f9dfdSAndroid Build Coastguard Worker else
644*387f9dfdSAndroid Build Coastguard Worker end = mid - 1;
645*387f9dfdSAndroid Build Coastguard Worker }
646*387f9dfdSAndroid Build Coastguard Worker
647*387f9dfdSAndroid Build Coastguard Worker if (start == end && dso->syms[start].start <= offset) {
648*387f9dfdSAndroid Build Coastguard Worker (dso->syms[start]).offset = offset - dso->syms[start].start;
649*387f9dfdSAndroid Build Coastguard Worker return &dso->syms[start];
650*387f9dfdSAndroid Build Coastguard Worker }
651*387f9dfdSAndroid Build Coastguard Worker return NULL;
652*387f9dfdSAndroid Build Coastguard Worker }
653*387f9dfdSAndroid Build Coastguard Worker
syms__load_file(const char * fname)654*387f9dfdSAndroid Build Coastguard Worker struct syms *syms__load_file(const char *fname)
655*387f9dfdSAndroid Build Coastguard Worker {
656*387f9dfdSAndroid Build Coastguard Worker char buf[PATH_MAX], perm[5];
657*387f9dfdSAndroid Build Coastguard Worker struct syms *syms;
658*387f9dfdSAndroid Build Coastguard Worker struct map map;
659*387f9dfdSAndroid Build Coastguard Worker char *name;
660*387f9dfdSAndroid Build Coastguard Worker FILE *f;
661*387f9dfdSAndroid Build Coastguard Worker int ret;
662*387f9dfdSAndroid Build Coastguard Worker
663*387f9dfdSAndroid Build Coastguard Worker f = fopen(fname, "r");
664*387f9dfdSAndroid Build Coastguard Worker if (!f)
665*387f9dfdSAndroid Build Coastguard Worker return NULL;
666*387f9dfdSAndroid Build Coastguard Worker
667*387f9dfdSAndroid Build Coastguard Worker syms = calloc(1, sizeof(*syms));
668*387f9dfdSAndroid Build Coastguard Worker if (!syms)
669*387f9dfdSAndroid Build Coastguard Worker goto err_out;
670*387f9dfdSAndroid Build Coastguard Worker
671*387f9dfdSAndroid Build Coastguard Worker while (true) {
672*387f9dfdSAndroid Build Coastguard Worker ret = fscanf(f, "%lx-%lx %4s %lx %lx:%lx %lu%[^\n]",
673*387f9dfdSAndroid Build Coastguard Worker &map.start_addr, &map.end_addr, perm,
674*387f9dfdSAndroid Build Coastguard Worker &map.file_off, &map.dev_major,
675*387f9dfdSAndroid Build Coastguard Worker &map.dev_minor, &map.inode, buf);
676*387f9dfdSAndroid Build Coastguard Worker if (ret == EOF && feof(f))
677*387f9dfdSAndroid Build Coastguard Worker break;
678*387f9dfdSAndroid Build Coastguard Worker if (ret != 8) /* perf-<PID>.map */
679*387f9dfdSAndroid Build Coastguard Worker goto err_out;
680*387f9dfdSAndroid Build Coastguard Worker
681*387f9dfdSAndroid Build Coastguard Worker if (perm[2] != 'x')
682*387f9dfdSAndroid Build Coastguard Worker continue;
683*387f9dfdSAndroid Build Coastguard Worker
684*387f9dfdSAndroid Build Coastguard Worker name = buf;
685*387f9dfdSAndroid Build Coastguard Worker while (isspace(*name))
686*387f9dfdSAndroid Build Coastguard Worker name++;
687*387f9dfdSAndroid Build Coastguard Worker if (!is_file_backed(name))
688*387f9dfdSAndroid Build Coastguard Worker continue;
689*387f9dfdSAndroid Build Coastguard Worker
690*387f9dfdSAndroid Build Coastguard Worker if (syms__add_dso(syms, &map, name))
691*387f9dfdSAndroid Build Coastguard Worker goto err_out;
692*387f9dfdSAndroid Build Coastguard Worker }
693*387f9dfdSAndroid Build Coastguard Worker
694*387f9dfdSAndroid Build Coastguard Worker fclose(f);
695*387f9dfdSAndroid Build Coastguard Worker return syms;
696*387f9dfdSAndroid Build Coastguard Worker
697*387f9dfdSAndroid Build Coastguard Worker err_out:
698*387f9dfdSAndroid Build Coastguard Worker syms__free(syms);
699*387f9dfdSAndroid Build Coastguard Worker fclose(f);
700*387f9dfdSAndroid Build Coastguard Worker return NULL;
701*387f9dfdSAndroid Build Coastguard Worker }
702*387f9dfdSAndroid Build Coastguard Worker
syms__load_pid(pid_t tgid)703*387f9dfdSAndroid Build Coastguard Worker struct syms *syms__load_pid(pid_t tgid)
704*387f9dfdSAndroid Build Coastguard Worker {
705*387f9dfdSAndroid Build Coastguard Worker char fname[128];
706*387f9dfdSAndroid Build Coastguard Worker
707*387f9dfdSAndroid Build Coastguard Worker snprintf(fname, sizeof(fname), "/proc/%ld/maps", (long)tgid);
708*387f9dfdSAndroid Build Coastguard Worker return syms__load_file(fname);
709*387f9dfdSAndroid Build Coastguard Worker }
710*387f9dfdSAndroid Build Coastguard Worker
syms__free(struct syms * syms)711*387f9dfdSAndroid Build Coastguard Worker void syms__free(struct syms *syms)
712*387f9dfdSAndroid Build Coastguard Worker {
713*387f9dfdSAndroid Build Coastguard Worker int i;
714*387f9dfdSAndroid Build Coastguard Worker
715*387f9dfdSAndroid Build Coastguard Worker if (!syms)
716*387f9dfdSAndroid Build Coastguard Worker return;
717*387f9dfdSAndroid Build Coastguard Worker
718*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < syms->dso_sz; i++)
719*387f9dfdSAndroid Build Coastguard Worker dso__free_fields(&syms->dsos[i]);
720*387f9dfdSAndroid Build Coastguard Worker free(syms->dsos);
721*387f9dfdSAndroid Build Coastguard Worker free(syms);
722*387f9dfdSAndroid Build Coastguard Worker }
723*387f9dfdSAndroid Build Coastguard Worker
syms__map_addr(const struct syms * syms,unsigned long addr)724*387f9dfdSAndroid Build Coastguard Worker const struct sym *syms__map_addr(const struct syms *syms, unsigned long addr)
725*387f9dfdSAndroid Build Coastguard Worker {
726*387f9dfdSAndroid Build Coastguard Worker struct dso *dso;
727*387f9dfdSAndroid Build Coastguard Worker uint64_t offset;
728*387f9dfdSAndroid Build Coastguard Worker
729*387f9dfdSAndroid Build Coastguard Worker dso = syms__find_dso(syms, addr, &offset);
730*387f9dfdSAndroid Build Coastguard Worker if (!dso)
731*387f9dfdSAndroid Build Coastguard Worker return NULL;
732*387f9dfdSAndroid Build Coastguard Worker return dso__find_sym(dso, offset);
733*387f9dfdSAndroid Build Coastguard Worker }
734*387f9dfdSAndroid Build Coastguard Worker
syms__map_addr_dso(const struct syms * syms,unsigned long addr,char ** dso_name,unsigned long * dso_offset)735*387f9dfdSAndroid Build Coastguard Worker const struct sym *syms__map_addr_dso(const struct syms *syms, unsigned long addr,
736*387f9dfdSAndroid Build Coastguard Worker char **dso_name, unsigned long *dso_offset)
737*387f9dfdSAndroid Build Coastguard Worker {
738*387f9dfdSAndroid Build Coastguard Worker struct dso *dso;
739*387f9dfdSAndroid Build Coastguard Worker uint64_t offset;
740*387f9dfdSAndroid Build Coastguard Worker
741*387f9dfdSAndroid Build Coastguard Worker dso = syms__find_dso(syms, addr, &offset);
742*387f9dfdSAndroid Build Coastguard Worker if (!dso)
743*387f9dfdSAndroid Build Coastguard Worker return NULL;
744*387f9dfdSAndroid Build Coastguard Worker
745*387f9dfdSAndroid Build Coastguard Worker *dso_name = dso->name;
746*387f9dfdSAndroid Build Coastguard Worker *dso_offset = offset;
747*387f9dfdSAndroid Build Coastguard Worker
748*387f9dfdSAndroid Build Coastguard Worker return dso__find_sym(dso, offset);
749*387f9dfdSAndroid Build Coastguard Worker }
750*387f9dfdSAndroid Build Coastguard Worker
751*387f9dfdSAndroid Build Coastguard Worker struct syms_cache {
752*387f9dfdSAndroid Build Coastguard Worker struct {
753*387f9dfdSAndroid Build Coastguard Worker struct syms *syms;
754*387f9dfdSAndroid Build Coastguard Worker int tgid;
755*387f9dfdSAndroid Build Coastguard Worker } *data;
756*387f9dfdSAndroid Build Coastguard Worker int nr;
757*387f9dfdSAndroid Build Coastguard Worker };
758*387f9dfdSAndroid Build Coastguard Worker
syms_cache__new(int nr)759*387f9dfdSAndroid Build Coastguard Worker struct syms_cache *syms_cache__new(int nr)
760*387f9dfdSAndroid Build Coastguard Worker {
761*387f9dfdSAndroid Build Coastguard Worker struct syms_cache *syms_cache;
762*387f9dfdSAndroid Build Coastguard Worker
763*387f9dfdSAndroid Build Coastguard Worker syms_cache = calloc(1, sizeof(*syms_cache));
764*387f9dfdSAndroid Build Coastguard Worker if (!syms_cache)
765*387f9dfdSAndroid Build Coastguard Worker return NULL;
766*387f9dfdSAndroid Build Coastguard Worker if (nr > 0)
767*387f9dfdSAndroid Build Coastguard Worker syms_cache->data = calloc(nr, sizeof(*syms_cache->data));
768*387f9dfdSAndroid Build Coastguard Worker return syms_cache;
769*387f9dfdSAndroid Build Coastguard Worker }
770*387f9dfdSAndroid Build Coastguard Worker
syms_cache__free(struct syms_cache * syms_cache)771*387f9dfdSAndroid Build Coastguard Worker void syms_cache__free(struct syms_cache *syms_cache)
772*387f9dfdSAndroid Build Coastguard Worker {
773*387f9dfdSAndroid Build Coastguard Worker int i;
774*387f9dfdSAndroid Build Coastguard Worker
775*387f9dfdSAndroid Build Coastguard Worker if (!syms_cache)
776*387f9dfdSAndroid Build Coastguard Worker return;
777*387f9dfdSAndroid Build Coastguard Worker
778*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < syms_cache->nr; i++)
779*387f9dfdSAndroid Build Coastguard Worker syms__free(syms_cache->data[i].syms);
780*387f9dfdSAndroid Build Coastguard Worker free(syms_cache->data);
781*387f9dfdSAndroid Build Coastguard Worker free(syms_cache);
782*387f9dfdSAndroid Build Coastguard Worker }
783*387f9dfdSAndroid Build Coastguard Worker
syms_cache__get_syms(struct syms_cache * syms_cache,int tgid)784*387f9dfdSAndroid Build Coastguard Worker struct syms *syms_cache__get_syms(struct syms_cache *syms_cache, int tgid)
785*387f9dfdSAndroid Build Coastguard Worker {
786*387f9dfdSAndroid Build Coastguard Worker void *tmp;
787*387f9dfdSAndroid Build Coastguard Worker int i;
788*387f9dfdSAndroid Build Coastguard Worker
789*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < syms_cache->nr; i++) {
790*387f9dfdSAndroid Build Coastguard Worker if (syms_cache->data[i].tgid == tgid)
791*387f9dfdSAndroid Build Coastguard Worker return syms_cache->data[i].syms;
792*387f9dfdSAndroid Build Coastguard Worker }
793*387f9dfdSAndroid Build Coastguard Worker
794*387f9dfdSAndroid Build Coastguard Worker tmp = realloc(syms_cache->data, (syms_cache->nr + 1) *
795*387f9dfdSAndroid Build Coastguard Worker sizeof(*syms_cache->data));
796*387f9dfdSAndroid Build Coastguard Worker if (!tmp)
797*387f9dfdSAndroid Build Coastguard Worker return NULL;
798*387f9dfdSAndroid Build Coastguard Worker syms_cache->data = tmp;
799*387f9dfdSAndroid Build Coastguard Worker syms_cache->data[syms_cache->nr].syms = syms__load_pid(tgid);
800*387f9dfdSAndroid Build Coastguard Worker syms_cache->data[syms_cache->nr].tgid = tgid;
801*387f9dfdSAndroid Build Coastguard Worker return syms_cache->data[syms_cache->nr++].syms;
802*387f9dfdSAndroid Build Coastguard Worker }
803*387f9dfdSAndroid Build Coastguard Worker
804*387f9dfdSAndroid Build Coastguard Worker struct partitions {
805*387f9dfdSAndroid Build Coastguard Worker struct partition *items;
806*387f9dfdSAndroid Build Coastguard Worker int sz;
807*387f9dfdSAndroid Build Coastguard Worker };
808*387f9dfdSAndroid Build Coastguard Worker
partitions__add_partition(struct partitions * partitions,const char * name,unsigned int dev)809*387f9dfdSAndroid Build Coastguard Worker static int partitions__add_partition(struct partitions *partitions,
810*387f9dfdSAndroid Build Coastguard Worker const char *name, unsigned int dev)
811*387f9dfdSAndroid Build Coastguard Worker {
812*387f9dfdSAndroid Build Coastguard Worker struct partition *partition;
813*387f9dfdSAndroid Build Coastguard Worker void *tmp;
814*387f9dfdSAndroid Build Coastguard Worker
815*387f9dfdSAndroid Build Coastguard Worker tmp = realloc(partitions->items, (partitions->sz + 1) *
816*387f9dfdSAndroid Build Coastguard Worker sizeof(*partitions->items));
817*387f9dfdSAndroid Build Coastguard Worker if (!tmp)
818*387f9dfdSAndroid Build Coastguard Worker return -1;
819*387f9dfdSAndroid Build Coastguard Worker partitions->items = tmp;
820*387f9dfdSAndroid Build Coastguard Worker partition = &partitions->items[partitions->sz];
821*387f9dfdSAndroid Build Coastguard Worker partition->name = strdup(name);
822*387f9dfdSAndroid Build Coastguard Worker partition->dev = dev;
823*387f9dfdSAndroid Build Coastguard Worker partitions->sz++;
824*387f9dfdSAndroid Build Coastguard Worker
825*387f9dfdSAndroid Build Coastguard Worker return 0;
826*387f9dfdSAndroid Build Coastguard Worker }
827*387f9dfdSAndroid Build Coastguard Worker
partitions__load(void)828*387f9dfdSAndroid Build Coastguard Worker struct partitions *partitions__load(void)
829*387f9dfdSAndroid Build Coastguard Worker {
830*387f9dfdSAndroid Build Coastguard Worker char part_name[DISK_NAME_LEN];
831*387f9dfdSAndroid Build Coastguard Worker unsigned int devmaj, devmin;
832*387f9dfdSAndroid Build Coastguard Worker unsigned long long nop;
833*387f9dfdSAndroid Build Coastguard Worker struct partitions *partitions;
834*387f9dfdSAndroid Build Coastguard Worker char buf[64];
835*387f9dfdSAndroid Build Coastguard Worker FILE *f;
836*387f9dfdSAndroid Build Coastguard Worker
837*387f9dfdSAndroid Build Coastguard Worker f = fopen("/proc/partitions", "r");
838*387f9dfdSAndroid Build Coastguard Worker if (!f)
839*387f9dfdSAndroid Build Coastguard Worker return NULL;
840*387f9dfdSAndroid Build Coastguard Worker
841*387f9dfdSAndroid Build Coastguard Worker partitions = calloc(1, sizeof(*partitions));
842*387f9dfdSAndroid Build Coastguard Worker if (!partitions)
843*387f9dfdSAndroid Build Coastguard Worker goto err_out;
844*387f9dfdSAndroid Build Coastguard Worker
845*387f9dfdSAndroid Build Coastguard Worker while (fgets(buf, sizeof(buf), f) != NULL) {
846*387f9dfdSAndroid Build Coastguard Worker /* skip heading */
847*387f9dfdSAndroid Build Coastguard Worker if (buf[0] != ' ' || buf[0] == '\n')
848*387f9dfdSAndroid Build Coastguard Worker continue;
849*387f9dfdSAndroid Build Coastguard Worker if (sscanf(buf, "%u %u %llu %s", &devmaj, &devmin, &nop,
850*387f9dfdSAndroid Build Coastguard Worker part_name) != 4)
851*387f9dfdSAndroid Build Coastguard Worker goto err_out;
852*387f9dfdSAndroid Build Coastguard Worker if (partitions__add_partition(partitions, part_name,
853*387f9dfdSAndroid Build Coastguard Worker MKDEV(devmaj, devmin)))
854*387f9dfdSAndroid Build Coastguard Worker goto err_out;
855*387f9dfdSAndroid Build Coastguard Worker }
856*387f9dfdSAndroid Build Coastguard Worker
857*387f9dfdSAndroid Build Coastguard Worker fclose(f);
858*387f9dfdSAndroid Build Coastguard Worker return partitions;
859*387f9dfdSAndroid Build Coastguard Worker
860*387f9dfdSAndroid Build Coastguard Worker err_out:
861*387f9dfdSAndroid Build Coastguard Worker partitions__free(partitions);
862*387f9dfdSAndroid Build Coastguard Worker fclose(f);
863*387f9dfdSAndroid Build Coastguard Worker return NULL;
864*387f9dfdSAndroid Build Coastguard Worker }
865*387f9dfdSAndroid Build Coastguard Worker
partitions__free(struct partitions * partitions)866*387f9dfdSAndroid Build Coastguard Worker void partitions__free(struct partitions *partitions)
867*387f9dfdSAndroid Build Coastguard Worker {
868*387f9dfdSAndroid Build Coastguard Worker int i;
869*387f9dfdSAndroid Build Coastguard Worker
870*387f9dfdSAndroid Build Coastguard Worker if (!partitions)
871*387f9dfdSAndroid Build Coastguard Worker return;
872*387f9dfdSAndroid Build Coastguard Worker
873*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < partitions->sz; i++)
874*387f9dfdSAndroid Build Coastguard Worker free(partitions->items[i].name);
875*387f9dfdSAndroid Build Coastguard Worker free(partitions->items);
876*387f9dfdSAndroid Build Coastguard Worker free(partitions);
877*387f9dfdSAndroid Build Coastguard Worker }
878*387f9dfdSAndroid Build Coastguard Worker
879*387f9dfdSAndroid Build Coastguard Worker const struct partition *
partitions__get_by_dev(const struct partitions * partitions,unsigned int dev)880*387f9dfdSAndroid Build Coastguard Worker partitions__get_by_dev(const struct partitions *partitions, unsigned int dev)
881*387f9dfdSAndroid Build Coastguard Worker {
882*387f9dfdSAndroid Build Coastguard Worker int i;
883*387f9dfdSAndroid Build Coastguard Worker
884*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < partitions->sz; i++) {
885*387f9dfdSAndroid Build Coastguard Worker if (partitions->items[i].dev == dev)
886*387f9dfdSAndroid Build Coastguard Worker return &partitions->items[i];
887*387f9dfdSAndroid Build Coastguard Worker }
888*387f9dfdSAndroid Build Coastguard Worker
889*387f9dfdSAndroid Build Coastguard Worker return NULL;
890*387f9dfdSAndroid Build Coastguard Worker }
891*387f9dfdSAndroid Build Coastguard Worker
892*387f9dfdSAndroid Build Coastguard Worker const struct partition *
partitions__get_by_name(const struct partitions * partitions,const char * name)893*387f9dfdSAndroid Build Coastguard Worker partitions__get_by_name(const struct partitions *partitions, const char *name)
894*387f9dfdSAndroid Build Coastguard Worker {
895*387f9dfdSAndroid Build Coastguard Worker int i;
896*387f9dfdSAndroid Build Coastguard Worker
897*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < partitions->sz; i++) {
898*387f9dfdSAndroid Build Coastguard Worker if (strcmp(partitions->items[i].name, name) == 0)
899*387f9dfdSAndroid Build Coastguard Worker return &partitions->items[i];
900*387f9dfdSAndroid Build Coastguard Worker }
901*387f9dfdSAndroid Build Coastguard Worker
902*387f9dfdSAndroid Build Coastguard Worker return NULL;
903*387f9dfdSAndroid Build Coastguard Worker }
904*387f9dfdSAndroid Build Coastguard Worker
print_stars(unsigned int val,unsigned int val_max,int width)905*387f9dfdSAndroid Build Coastguard Worker static void print_stars(unsigned int val, unsigned int val_max, int width)
906*387f9dfdSAndroid Build Coastguard Worker {
907*387f9dfdSAndroid Build Coastguard Worker int num_stars, num_spaces, i;
908*387f9dfdSAndroid Build Coastguard Worker bool need_plus;
909*387f9dfdSAndroid Build Coastguard Worker
910*387f9dfdSAndroid Build Coastguard Worker num_stars = min(val, val_max) * width / val_max;
911*387f9dfdSAndroid Build Coastguard Worker num_spaces = width - num_stars;
912*387f9dfdSAndroid Build Coastguard Worker need_plus = val > val_max;
913*387f9dfdSAndroid Build Coastguard Worker
914*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < num_stars; i++)
915*387f9dfdSAndroid Build Coastguard Worker printf("*");
916*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < num_spaces; i++)
917*387f9dfdSAndroid Build Coastguard Worker printf(" ");
918*387f9dfdSAndroid Build Coastguard Worker if (need_plus)
919*387f9dfdSAndroid Build Coastguard Worker printf("+");
920*387f9dfdSAndroid Build Coastguard Worker }
921*387f9dfdSAndroid Build Coastguard Worker
print_log2_hist(unsigned int * vals,int vals_size,const char * val_type)922*387f9dfdSAndroid Build Coastguard Worker void print_log2_hist(unsigned int *vals, int vals_size, const char *val_type)
923*387f9dfdSAndroid Build Coastguard Worker {
924*387f9dfdSAndroid Build Coastguard Worker int stars_max = 40, idx_max = -1;
925*387f9dfdSAndroid Build Coastguard Worker unsigned int val, val_max = 0;
926*387f9dfdSAndroid Build Coastguard Worker unsigned long long low, high;
927*387f9dfdSAndroid Build Coastguard Worker int stars, width, i;
928*387f9dfdSAndroid Build Coastguard Worker
929*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < vals_size; i++) {
930*387f9dfdSAndroid Build Coastguard Worker val = vals[i];
931*387f9dfdSAndroid Build Coastguard Worker if (val > 0)
932*387f9dfdSAndroid Build Coastguard Worker idx_max = i;
933*387f9dfdSAndroid Build Coastguard Worker if (val > val_max)
934*387f9dfdSAndroid Build Coastguard Worker val_max = val;
935*387f9dfdSAndroid Build Coastguard Worker }
936*387f9dfdSAndroid Build Coastguard Worker
937*387f9dfdSAndroid Build Coastguard Worker if (idx_max < 0)
938*387f9dfdSAndroid Build Coastguard Worker return;
939*387f9dfdSAndroid Build Coastguard Worker
940*387f9dfdSAndroid Build Coastguard Worker printf("%*s%-*s : count distribution\n", idx_max <= 32 ? 5 : 15, "",
941*387f9dfdSAndroid Build Coastguard Worker idx_max <= 32 ? 19 : 29, val_type);
942*387f9dfdSAndroid Build Coastguard Worker
943*387f9dfdSAndroid Build Coastguard Worker if (idx_max <= 32)
944*387f9dfdSAndroid Build Coastguard Worker stars = stars_max;
945*387f9dfdSAndroid Build Coastguard Worker else
946*387f9dfdSAndroid Build Coastguard Worker stars = stars_max / 2;
947*387f9dfdSAndroid Build Coastguard Worker
948*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i <= idx_max; i++) {
949*387f9dfdSAndroid Build Coastguard Worker low = (1ULL << (i + 1)) >> 1;
950*387f9dfdSAndroid Build Coastguard Worker high = (1ULL << (i + 1)) - 1;
951*387f9dfdSAndroid Build Coastguard Worker if (low == high)
952*387f9dfdSAndroid Build Coastguard Worker low -= 1;
953*387f9dfdSAndroid Build Coastguard Worker val = vals[i];
954*387f9dfdSAndroid Build Coastguard Worker width = idx_max <= 32 ? 10 : 20;
955*387f9dfdSAndroid Build Coastguard Worker printf("%*lld -> %-*lld : %-8d |", width, low, width, high, val);
956*387f9dfdSAndroid Build Coastguard Worker print_stars(val, val_max, stars);
957*387f9dfdSAndroid Build Coastguard Worker printf("|\n");
958*387f9dfdSAndroid Build Coastguard Worker }
959*387f9dfdSAndroid Build Coastguard Worker }
960*387f9dfdSAndroid Build Coastguard Worker
print_linear_hist(unsigned int * vals,int vals_size,unsigned int base,unsigned int step,const char * val_type)961*387f9dfdSAndroid Build Coastguard Worker void print_linear_hist(unsigned int *vals, int vals_size, unsigned int base,
962*387f9dfdSAndroid Build Coastguard Worker unsigned int step, const char *val_type)
963*387f9dfdSAndroid Build Coastguard Worker {
964*387f9dfdSAndroid Build Coastguard Worker int i, stars_max = 40, idx_min = -1, idx_max = -1;
965*387f9dfdSAndroid Build Coastguard Worker unsigned int val, val_max = 0;
966*387f9dfdSAndroid Build Coastguard Worker
967*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < vals_size; i++) {
968*387f9dfdSAndroid Build Coastguard Worker val = vals[i];
969*387f9dfdSAndroid Build Coastguard Worker if (val > 0) {
970*387f9dfdSAndroid Build Coastguard Worker idx_max = i;
971*387f9dfdSAndroid Build Coastguard Worker if (idx_min < 0)
972*387f9dfdSAndroid Build Coastguard Worker idx_min = i;
973*387f9dfdSAndroid Build Coastguard Worker }
974*387f9dfdSAndroid Build Coastguard Worker if (val > val_max)
975*387f9dfdSAndroid Build Coastguard Worker val_max = val;
976*387f9dfdSAndroid Build Coastguard Worker }
977*387f9dfdSAndroid Build Coastguard Worker
978*387f9dfdSAndroid Build Coastguard Worker if (idx_max < 0)
979*387f9dfdSAndroid Build Coastguard Worker return;
980*387f9dfdSAndroid Build Coastguard Worker
981*387f9dfdSAndroid Build Coastguard Worker printf(" %-13s : count distribution\n", val_type);
982*387f9dfdSAndroid Build Coastguard Worker for (i = idx_min; i <= idx_max; i++) {
983*387f9dfdSAndroid Build Coastguard Worker val = vals[i];
984*387f9dfdSAndroid Build Coastguard Worker if (!val)
985*387f9dfdSAndroid Build Coastguard Worker continue;
986*387f9dfdSAndroid Build Coastguard Worker printf(" %-10d : %-8d |", base + i * step, val);
987*387f9dfdSAndroid Build Coastguard Worker print_stars(val, val_max, stars_max);
988*387f9dfdSAndroid Build Coastguard Worker printf("|\n");
989*387f9dfdSAndroid Build Coastguard Worker }
990*387f9dfdSAndroid Build Coastguard Worker }
991*387f9dfdSAndroid Build Coastguard Worker
get_ktime_ns(void)992*387f9dfdSAndroid Build Coastguard Worker unsigned long long get_ktime_ns(void)
993*387f9dfdSAndroid Build Coastguard Worker {
994*387f9dfdSAndroid Build Coastguard Worker struct timespec ts;
995*387f9dfdSAndroid Build Coastguard Worker
996*387f9dfdSAndroid Build Coastguard Worker clock_gettime(CLOCK_MONOTONIC, &ts);
997*387f9dfdSAndroid Build Coastguard Worker return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
998*387f9dfdSAndroid Build Coastguard Worker }
999*387f9dfdSAndroid Build Coastguard Worker
is_kernel_module(const char * name)1000*387f9dfdSAndroid Build Coastguard Worker bool is_kernel_module(const char *name)
1001*387f9dfdSAndroid Build Coastguard Worker {
1002*387f9dfdSAndroid Build Coastguard Worker bool found = false;
1003*387f9dfdSAndroid Build Coastguard Worker char buf[64];
1004*387f9dfdSAndroid Build Coastguard Worker FILE *f;
1005*387f9dfdSAndroid Build Coastguard Worker
1006*387f9dfdSAndroid Build Coastguard Worker f = fopen("/proc/modules", "r");
1007*387f9dfdSAndroid Build Coastguard Worker if (!f)
1008*387f9dfdSAndroid Build Coastguard Worker return false;
1009*387f9dfdSAndroid Build Coastguard Worker
1010*387f9dfdSAndroid Build Coastguard Worker while (fgets(buf, sizeof(buf), f) != NULL) {
1011*387f9dfdSAndroid Build Coastguard Worker if (sscanf(buf, "%s %*s\n", buf) != 1)
1012*387f9dfdSAndroid Build Coastguard Worker break;
1013*387f9dfdSAndroid Build Coastguard Worker if (!strcmp(buf, name)) {
1014*387f9dfdSAndroid Build Coastguard Worker found = true;
1015*387f9dfdSAndroid Build Coastguard Worker break;
1016*387f9dfdSAndroid Build Coastguard Worker }
1017*387f9dfdSAndroid Build Coastguard Worker }
1018*387f9dfdSAndroid Build Coastguard Worker
1019*387f9dfdSAndroid Build Coastguard Worker fclose(f);
1020*387f9dfdSAndroid Build Coastguard Worker return found;
1021*387f9dfdSAndroid Build Coastguard Worker }
1022*387f9dfdSAndroid Build Coastguard Worker
fentry_try_attach(int id)1023*387f9dfdSAndroid Build Coastguard Worker static bool fentry_try_attach(int id)
1024*387f9dfdSAndroid Build Coastguard Worker {
1025*387f9dfdSAndroid Build Coastguard Worker int prog_fd, attach_fd;
1026*387f9dfdSAndroid Build Coastguard Worker char error[4096];
1027*387f9dfdSAndroid Build Coastguard Worker struct bpf_insn insns[] = {
1028*387f9dfdSAndroid Build Coastguard Worker { .code = BPF_ALU64 | BPF_MOV | BPF_K, .dst_reg = BPF_REG_0, .imm = 0 },
1029*387f9dfdSAndroid Build Coastguard Worker { .code = BPF_JMP | BPF_EXIT },
1030*387f9dfdSAndroid Build Coastguard Worker };
1031*387f9dfdSAndroid Build Coastguard Worker LIBBPF_OPTS(bpf_prog_load_opts, opts,
1032*387f9dfdSAndroid Build Coastguard Worker .expected_attach_type = BPF_TRACE_FENTRY,
1033*387f9dfdSAndroid Build Coastguard Worker .attach_btf_id = id,
1034*387f9dfdSAndroid Build Coastguard Worker .log_buf = error,
1035*387f9dfdSAndroid Build Coastguard Worker .log_size = sizeof(error),
1036*387f9dfdSAndroid Build Coastguard Worker );
1037*387f9dfdSAndroid Build Coastguard Worker
1038*387f9dfdSAndroid Build Coastguard Worker prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACING, "test", "GPL", insns,
1039*387f9dfdSAndroid Build Coastguard Worker sizeof(insns) / sizeof(struct bpf_insn), &opts);
1040*387f9dfdSAndroid Build Coastguard Worker if (prog_fd < 0)
1041*387f9dfdSAndroid Build Coastguard Worker return false;
1042*387f9dfdSAndroid Build Coastguard Worker
1043*387f9dfdSAndroid Build Coastguard Worker attach_fd = bpf_raw_tracepoint_open(NULL, prog_fd);
1044*387f9dfdSAndroid Build Coastguard Worker if (attach_fd >= 0)
1045*387f9dfdSAndroid Build Coastguard Worker close(attach_fd);
1046*387f9dfdSAndroid Build Coastguard Worker
1047*387f9dfdSAndroid Build Coastguard Worker close(prog_fd);
1048*387f9dfdSAndroid Build Coastguard Worker return attach_fd >= 0;
1049*387f9dfdSAndroid Build Coastguard Worker }
1050*387f9dfdSAndroid Build Coastguard Worker
fentry_can_attach(const char * name,const char * mod)1051*387f9dfdSAndroid Build Coastguard Worker bool fentry_can_attach(const char *name, const char *mod)
1052*387f9dfdSAndroid Build Coastguard Worker {
1053*387f9dfdSAndroid Build Coastguard Worker struct btf *btf, *vmlinux_btf, *module_btf = NULL;
1054*387f9dfdSAndroid Build Coastguard Worker int err, id;
1055*387f9dfdSAndroid Build Coastguard Worker
1056*387f9dfdSAndroid Build Coastguard Worker vmlinux_btf = btf__load_vmlinux_btf();
1057*387f9dfdSAndroid Build Coastguard Worker err = libbpf_get_error(vmlinux_btf);
1058*387f9dfdSAndroid Build Coastguard Worker if (err)
1059*387f9dfdSAndroid Build Coastguard Worker return false;
1060*387f9dfdSAndroid Build Coastguard Worker
1061*387f9dfdSAndroid Build Coastguard Worker btf = vmlinux_btf;
1062*387f9dfdSAndroid Build Coastguard Worker
1063*387f9dfdSAndroid Build Coastguard Worker if (mod) {
1064*387f9dfdSAndroid Build Coastguard Worker module_btf = btf__load_module_btf(mod, vmlinux_btf);
1065*387f9dfdSAndroid Build Coastguard Worker err = libbpf_get_error(module_btf);
1066*387f9dfdSAndroid Build Coastguard Worker if (!err)
1067*387f9dfdSAndroid Build Coastguard Worker btf = module_btf;
1068*387f9dfdSAndroid Build Coastguard Worker }
1069*387f9dfdSAndroid Build Coastguard Worker
1070*387f9dfdSAndroid Build Coastguard Worker id = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC);
1071*387f9dfdSAndroid Build Coastguard Worker
1072*387f9dfdSAndroid Build Coastguard Worker btf__free(module_btf);
1073*387f9dfdSAndroid Build Coastguard Worker btf__free(vmlinux_btf);
1074*387f9dfdSAndroid Build Coastguard Worker return id > 0 && fentry_try_attach(id);
1075*387f9dfdSAndroid Build Coastguard Worker }
1076*387f9dfdSAndroid Build Coastguard Worker
1077*387f9dfdSAndroid Build Coastguard Worker #define DEBUGFS "/sys/kernel/debug/tracing"
1078*387f9dfdSAndroid Build Coastguard Worker #define TRACEFS "/sys/kernel/tracing"
1079*387f9dfdSAndroid Build Coastguard Worker
use_debugfs(void)1080*387f9dfdSAndroid Build Coastguard Worker static bool use_debugfs(void)
1081*387f9dfdSAndroid Build Coastguard Worker {
1082*387f9dfdSAndroid Build Coastguard Worker static int has_debugfs = -1;
1083*387f9dfdSAndroid Build Coastguard Worker
1084*387f9dfdSAndroid Build Coastguard Worker if (has_debugfs < 0)
1085*387f9dfdSAndroid Build Coastguard Worker has_debugfs = faccessat(AT_FDCWD, DEBUGFS, F_OK, AT_EACCESS) == 0;
1086*387f9dfdSAndroid Build Coastguard Worker
1087*387f9dfdSAndroid Build Coastguard Worker return has_debugfs == 1;
1088*387f9dfdSAndroid Build Coastguard Worker }
1089*387f9dfdSAndroid Build Coastguard Worker
tracefs_path(void)1090*387f9dfdSAndroid Build Coastguard Worker static const char *tracefs_path(void)
1091*387f9dfdSAndroid Build Coastguard Worker {
1092*387f9dfdSAndroid Build Coastguard Worker return use_debugfs() ? DEBUGFS : TRACEFS;
1093*387f9dfdSAndroid Build Coastguard Worker }
1094*387f9dfdSAndroid Build Coastguard Worker
tracefs_available_filter_functions(void)1095*387f9dfdSAndroid Build Coastguard Worker static const char *tracefs_available_filter_functions(void)
1096*387f9dfdSAndroid Build Coastguard Worker {
1097*387f9dfdSAndroid Build Coastguard Worker return use_debugfs() ? DEBUGFS"/available_filter_functions" :
1098*387f9dfdSAndroid Build Coastguard Worker TRACEFS"/available_filter_functions";
1099*387f9dfdSAndroid Build Coastguard Worker }
1100*387f9dfdSAndroid Build Coastguard Worker
kprobe_exists(const char * name)1101*387f9dfdSAndroid Build Coastguard Worker bool kprobe_exists(const char *name)
1102*387f9dfdSAndroid Build Coastguard Worker {
1103*387f9dfdSAndroid Build Coastguard Worker char addr_range[256];
1104*387f9dfdSAndroid Build Coastguard Worker char sym_name[256];
1105*387f9dfdSAndroid Build Coastguard Worker FILE *f;
1106*387f9dfdSAndroid Build Coastguard Worker int ret;
1107*387f9dfdSAndroid Build Coastguard Worker
1108*387f9dfdSAndroid Build Coastguard Worker f = fopen("/sys/kernel/debug/kprobes/blacklist", "r");
1109*387f9dfdSAndroid Build Coastguard Worker if (!f)
1110*387f9dfdSAndroid Build Coastguard Worker goto avail_filter;
1111*387f9dfdSAndroid Build Coastguard Worker
1112*387f9dfdSAndroid Build Coastguard Worker while (true) {
1113*387f9dfdSAndroid Build Coastguard Worker ret = fscanf(f, "%s %s%*[^\n]\n", addr_range, sym_name);
1114*387f9dfdSAndroid Build Coastguard Worker if (ret == EOF && feof(f))
1115*387f9dfdSAndroid Build Coastguard Worker break;
1116*387f9dfdSAndroid Build Coastguard Worker if (ret != 2) {
1117*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "failed to read symbol from kprobe blacklist\n");
1118*387f9dfdSAndroid Build Coastguard Worker break;
1119*387f9dfdSAndroid Build Coastguard Worker }
1120*387f9dfdSAndroid Build Coastguard Worker if (!strcmp(name, sym_name)) {
1121*387f9dfdSAndroid Build Coastguard Worker fclose(f);
1122*387f9dfdSAndroid Build Coastguard Worker return false;
1123*387f9dfdSAndroid Build Coastguard Worker }
1124*387f9dfdSAndroid Build Coastguard Worker }
1125*387f9dfdSAndroid Build Coastguard Worker fclose(f);
1126*387f9dfdSAndroid Build Coastguard Worker
1127*387f9dfdSAndroid Build Coastguard Worker avail_filter:
1128*387f9dfdSAndroid Build Coastguard Worker f = fopen(tracefs_available_filter_functions(), "r");
1129*387f9dfdSAndroid Build Coastguard Worker if (!f)
1130*387f9dfdSAndroid Build Coastguard Worker goto slow_path;
1131*387f9dfdSAndroid Build Coastguard Worker
1132*387f9dfdSAndroid Build Coastguard Worker while (true) {
1133*387f9dfdSAndroid Build Coastguard Worker ret = fscanf(f, "%s%*[^\n]\n", sym_name);
1134*387f9dfdSAndroid Build Coastguard Worker if (ret == EOF && feof(f))
1135*387f9dfdSAndroid Build Coastguard Worker break;
1136*387f9dfdSAndroid Build Coastguard Worker if (ret != 1) {
1137*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "failed to read symbol from available_filter_functions\n");
1138*387f9dfdSAndroid Build Coastguard Worker break;
1139*387f9dfdSAndroid Build Coastguard Worker }
1140*387f9dfdSAndroid Build Coastguard Worker if (!strcmp(name, sym_name)) {
1141*387f9dfdSAndroid Build Coastguard Worker fclose(f);
1142*387f9dfdSAndroid Build Coastguard Worker return true;
1143*387f9dfdSAndroid Build Coastguard Worker }
1144*387f9dfdSAndroid Build Coastguard Worker }
1145*387f9dfdSAndroid Build Coastguard Worker
1146*387f9dfdSAndroid Build Coastguard Worker fclose(f);
1147*387f9dfdSAndroid Build Coastguard Worker return false;
1148*387f9dfdSAndroid Build Coastguard Worker
1149*387f9dfdSAndroid Build Coastguard Worker slow_path:
1150*387f9dfdSAndroid Build Coastguard Worker f = fopen("/proc/kallsyms", "r");
1151*387f9dfdSAndroid Build Coastguard Worker if (!f)
1152*387f9dfdSAndroid Build Coastguard Worker return false;
1153*387f9dfdSAndroid Build Coastguard Worker
1154*387f9dfdSAndroid Build Coastguard Worker while (true) {
1155*387f9dfdSAndroid Build Coastguard Worker ret = fscanf(f, "%*x %*c %s%*[^\n]\n", sym_name);
1156*387f9dfdSAndroid Build Coastguard Worker if (ret == EOF && feof(f))
1157*387f9dfdSAndroid Build Coastguard Worker break;
1158*387f9dfdSAndroid Build Coastguard Worker if (ret != 1) {
1159*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "failed to read symbol from kallsyms\n");
1160*387f9dfdSAndroid Build Coastguard Worker break;
1161*387f9dfdSAndroid Build Coastguard Worker }
1162*387f9dfdSAndroid Build Coastguard Worker if (!strcmp(name, sym_name)) {
1163*387f9dfdSAndroid Build Coastguard Worker fclose(f);
1164*387f9dfdSAndroid Build Coastguard Worker return true;
1165*387f9dfdSAndroid Build Coastguard Worker }
1166*387f9dfdSAndroid Build Coastguard Worker }
1167*387f9dfdSAndroid Build Coastguard Worker
1168*387f9dfdSAndroid Build Coastguard Worker fclose(f);
1169*387f9dfdSAndroid Build Coastguard Worker return false;
1170*387f9dfdSAndroid Build Coastguard Worker }
1171*387f9dfdSAndroid Build Coastguard Worker
tracepoint_exists(const char * category,const char * event)1172*387f9dfdSAndroid Build Coastguard Worker bool tracepoint_exists(const char *category, const char *event)
1173*387f9dfdSAndroid Build Coastguard Worker {
1174*387f9dfdSAndroid Build Coastguard Worker char path[PATH_MAX];
1175*387f9dfdSAndroid Build Coastguard Worker
1176*387f9dfdSAndroid Build Coastguard Worker snprintf(path, sizeof(path), "%s/events/%s/%s/format", tracefs_path(), category, event);
1177*387f9dfdSAndroid Build Coastguard Worker if (!access(path, F_OK))
1178*387f9dfdSAndroid Build Coastguard Worker return true;
1179*387f9dfdSAndroid Build Coastguard Worker return false;
1180*387f9dfdSAndroid Build Coastguard Worker }
1181*387f9dfdSAndroid Build Coastguard Worker
vmlinux_btf_exists(void)1182*387f9dfdSAndroid Build Coastguard Worker bool vmlinux_btf_exists(void)
1183*387f9dfdSAndroid Build Coastguard Worker {
1184*387f9dfdSAndroid Build Coastguard Worker struct btf *btf;
1185*387f9dfdSAndroid Build Coastguard Worker int err;
1186*387f9dfdSAndroid Build Coastguard Worker
1187*387f9dfdSAndroid Build Coastguard Worker btf = btf__load_vmlinux_btf();
1188*387f9dfdSAndroid Build Coastguard Worker err = libbpf_get_error(btf);
1189*387f9dfdSAndroid Build Coastguard Worker if (err)
1190*387f9dfdSAndroid Build Coastguard Worker return false;
1191*387f9dfdSAndroid Build Coastguard Worker
1192*387f9dfdSAndroid Build Coastguard Worker btf__free(btf);
1193*387f9dfdSAndroid Build Coastguard Worker return true;
1194*387f9dfdSAndroid Build Coastguard Worker }
1195*387f9dfdSAndroid Build Coastguard Worker
module_btf_exists(const char * mod)1196*387f9dfdSAndroid Build Coastguard Worker bool module_btf_exists(const char *mod)
1197*387f9dfdSAndroid Build Coastguard Worker {
1198*387f9dfdSAndroid Build Coastguard Worker char sysfs_mod[80];
1199*387f9dfdSAndroid Build Coastguard Worker
1200*387f9dfdSAndroid Build Coastguard Worker if (mod) {
1201*387f9dfdSAndroid Build Coastguard Worker snprintf(sysfs_mod, sizeof(sysfs_mod), "/sys/kernel/btf/%s", mod);
1202*387f9dfdSAndroid Build Coastguard Worker if (!access(sysfs_mod, R_OK))
1203*387f9dfdSAndroid Build Coastguard Worker return true;
1204*387f9dfdSAndroid Build Coastguard Worker }
1205*387f9dfdSAndroid Build Coastguard Worker return false;
1206*387f9dfdSAndroid Build Coastguard Worker }
1207*387f9dfdSAndroid Build Coastguard Worker
probe_tp_btf(const char * name)1208*387f9dfdSAndroid Build Coastguard Worker bool probe_tp_btf(const char *name)
1209*387f9dfdSAndroid Build Coastguard Worker {
1210*387f9dfdSAndroid Build Coastguard Worker LIBBPF_OPTS(bpf_prog_load_opts, opts, .expected_attach_type = BPF_TRACE_RAW_TP);
1211*387f9dfdSAndroid Build Coastguard Worker struct bpf_insn insns[] = {
1212*387f9dfdSAndroid Build Coastguard Worker { .code = BPF_ALU64 | BPF_MOV | BPF_K, .dst_reg = BPF_REG_0, .imm = 0 },
1213*387f9dfdSAndroid Build Coastguard Worker { .code = BPF_JMP | BPF_EXIT },
1214*387f9dfdSAndroid Build Coastguard Worker };
1215*387f9dfdSAndroid Build Coastguard Worker int fd, insn_cnt = sizeof(insns) / sizeof(struct bpf_insn);
1216*387f9dfdSAndroid Build Coastguard Worker
1217*387f9dfdSAndroid Build Coastguard Worker opts.attach_btf_id = libbpf_find_vmlinux_btf_id(name, BPF_TRACE_RAW_TP);
1218*387f9dfdSAndroid Build Coastguard Worker fd = bpf_prog_load(BPF_PROG_TYPE_TRACING, NULL, "GPL", insns, insn_cnt, &opts);
1219*387f9dfdSAndroid Build Coastguard Worker if (fd >= 0)
1220*387f9dfdSAndroid Build Coastguard Worker close(fd);
1221*387f9dfdSAndroid Build Coastguard Worker return fd >= 0;
1222*387f9dfdSAndroid Build Coastguard Worker }
1223*387f9dfdSAndroid Build Coastguard Worker
probe_ringbuf()1224*387f9dfdSAndroid Build Coastguard Worker bool probe_ringbuf()
1225*387f9dfdSAndroid Build Coastguard Worker {
1226*387f9dfdSAndroid Build Coastguard Worker int map_fd;
1227*387f9dfdSAndroid Build Coastguard Worker
1228*387f9dfdSAndroid Build Coastguard Worker map_fd = bpf_map_create(BPF_MAP_TYPE_RINGBUF, NULL, 0, 0, getpagesize(), NULL);
1229*387f9dfdSAndroid Build Coastguard Worker if (map_fd < 0)
1230*387f9dfdSAndroid Build Coastguard Worker return false;
1231*387f9dfdSAndroid Build Coastguard Worker
1232*387f9dfdSAndroid Build Coastguard Worker close(map_fd);
1233*387f9dfdSAndroid Build Coastguard Worker return true;
1234*387f9dfdSAndroid Build Coastguard Worker }
1235