Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
bda6ee4a | 2 | #include <asm/bug.h> |
877a7a11 | 3 | #include <linux/kernel.h> |
af0de0c5 | 4 | #include <linux/string.h> |
7f7c536f | 5 | #include <linux/zalloc.h> |
c6580451 JO |
6 | #include <sys/time.h> |
7 | #include <sys/resource.h> | |
7a8ef4c4 ACM |
8 | #include <sys/types.h> |
9 | #include <sys/stat.h> | |
10 | #include <unistd.h> | |
a43783ae | 11 | #include <errno.h> |
c23c2a0f | 12 | #include <fcntl.h> |
f2a39fe8 | 13 | #include <stdlib.h> |
ef0580ec | 14 | #ifdef HAVE_LIBBPF_SUPPORT |
6c398d72 JO |
15 | #include <bpf/libbpf.h> |
16 | #include "bpf-event.h" | |
6ac22d03 | 17 | #include "bpf-utils.h" |
ef0580ec | 18 | #endif |
611f0afe | 19 | #include "compress.h" |
f2a39fe8 | 20 | #include "env.h" |
40f3b2d2 | 21 | #include "namespaces.h" |
9a3993d4 | 22 | #include "path.h" |
1101f69a | 23 | #include "map.h" |
cdd059d7 | 24 | #include "symbol.h" |
11ea2515 | 25 | #include "srcline.h" |
cdd059d7 | 26 | #include "dso.h" |
4a3cec84 | 27 | #include "dsos.h" |
69d2591a | 28 | #include "machine.h" |
cfe9174f | 29 | #include "auxtrace.h" |
7f7c536f | 30 | #include "util.h" /* O_CLOEXEC for older systems */ |
cdd059d7 | 31 | #include "debug.h" |
a067558e | 32 | #include "string2.h" |
6ae98ba6 | 33 | #include "vdso.h" |
fc044c53 | 34 | #include "annotate-data.h" |
cdd059d7 | 35 | |
9343e45b MGP |
36 | static const char * const debuglink_paths[] = { |
37 | "%.0s%s", | |
38 | "%s/%s", | |
39 | "%s/.debug/%s", | |
40 | "/usr/lib/debug%s/%s" | |
41 | }; | |
42 | ||
ee756ef7 IR |
43 | void dso__set_nsinfo(struct dso *dso, struct nsinfo *nsi) |
44 | { | |
45 | nsinfo__put(RC_CHK_ACCESS(dso)->nsinfo); | |
46 | RC_CHK_ACCESS(dso)->nsinfo = nsi; | |
47 | } | |
48 | ||
cdd059d7 JO |
49 | char dso__symtab_origin(const struct dso *dso) |
50 | { | |
51 | static const char origin[] = { | |
9cd00941 RRD |
52 | [DSO_BINARY_TYPE__KALLSYMS] = 'k', |
53 | [DSO_BINARY_TYPE__VMLINUX] = 'v', | |
54 | [DSO_BINARY_TYPE__JAVA_JIT] = 'j', | |
55 | [DSO_BINARY_TYPE__DEBUGLINK] = 'l', | |
56 | [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', | |
d2396999 | 57 | [DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO] = 'D', |
9cd00941 RRD |
58 | [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f', |
59 | [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u', | |
85afd355 | 60 | [DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO] = 'x', |
9cd00941 RRD |
61 | [DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO] = 'o', |
62 | [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b', | |
63 | [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', | |
64 | [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', | |
c00c48fc | 65 | [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP] = 'm', |
9cd00941 RRD |
66 | [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', |
67 | [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', | |
c00c48fc | 68 | [DSO_BINARY_TYPE__GUEST_KMODULE_COMP] = 'M', |
9cd00941 | 69 | [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V', |
b10f7430 | 70 | [DSO_BINARY_TYPE__GNU_DEBUGDATA] = 'n', |
cdd059d7 JO |
71 | }; |
72 | ||
ee756ef7 | 73 | if (dso == NULL || dso__symtab_type(dso) == DSO_BINARY_TYPE__NOT_FOUND) |
cdd059d7 | 74 | return '!'; |
ee756ef7 | 75 | return origin[dso__symtab_type(dso)]; |
cdd059d7 JO |
76 | } |
77 | ||
d3b52f71 AH |
78 | bool dso__is_object_file(const struct dso *dso) |
79 | { | |
ee756ef7 | 80 | switch (dso__binary_type(dso)) { |
d3b52f71 AH |
81 | case DSO_BINARY_TYPE__KALLSYMS: |
82 | case DSO_BINARY_TYPE__GUEST_KALLSYMS: | |
83 | case DSO_BINARY_TYPE__JAVA_JIT: | |
84 | case DSO_BINARY_TYPE__BPF_PROG_INFO: | |
85 | case DSO_BINARY_TYPE__BPF_IMAGE: | |
86 | case DSO_BINARY_TYPE__OOL: | |
87 | return false; | |
88 | case DSO_BINARY_TYPE__VMLINUX: | |
89 | case DSO_BINARY_TYPE__GUEST_VMLINUX: | |
90 | case DSO_BINARY_TYPE__DEBUGLINK: | |
91 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: | |
92 | case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: | |
93 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: | |
94 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: | |
95 | case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO: | |
96 | case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: | |
b10f7430 | 97 | case DSO_BINARY_TYPE__GNU_DEBUGDATA: |
d3b52f71 AH |
98 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: |
99 | case DSO_BINARY_TYPE__GUEST_KMODULE: | |
100 | case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: | |
101 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: | |
102 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: | |
103 | case DSO_BINARY_TYPE__KCORE: | |
104 | case DSO_BINARY_TYPE__GUEST_KCORE: | |
105 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: | |
106 | case DSO_BINARY_TYPE__NOT_FOUND: | |
107 | default: | |
108 | return true; | |
109 | } | |
110 | } | |
111 | ||
ee4e9625 ACM |
112 | int dso__read_binary_type_filename(const struct dso *dso, |
113 | enum dso_binary_type type, | |
114 | char *root_dir, char *filename, size_t size) | |
cdd059d7 | 115 | { |
b5d8bbe8 | 116 | char build_id_hex[SBUILD_ID_SIZE]; |
cdd059d7 | 117 | int ret = 0; |
972f393b | 118 | size_t len; |
cdd059d7 JO |
119 | |
120 | switch (type) { | |
9343e45b MGP |
121 | case DSO_BINARY_TYPE__DEBUGLINK: |
122 | { | |
123 | const char *last_slash; | |
124 | char dso_dir[PATH_MAX]; | |
125 | char symfile[PATH_MAX]; | |
126 | unsigned int i; | |
cdd059d7 | 127 | |
ee756ef7 | 128 | len = __symbol__join_symfs(filename, size, dso__long_name(dso)); |
9343e45b MGP |
129 | last_slash = filename + len; |
130 | while (last_slash != filename && *last_slash != '/') | |
131 | last_slash--; | |
40356721 | 132 | |
9343e45b MGP |
133 | strncpy(dso_dir, filename, last_slash - filename); |
134 | dso_dir[last_slash-filename] = '\0'; | |
135 | ||
136 | if (!is_regular_file(filename)) { | |
137 | ret = -1; | |
40356721 | 138 | break; |
9343e45b | 139 | } |
40356721 | 140 | |
9343e45b MGP |
141 | ret = filename__read_debuglink(filename, symfile, PATH_MAX); |
142 | if (ret) | |
143 | break; | |
144 | ||
145 | /* Check predefined locations where debug file might reside */ | |
146 | ret = -1; | |
147 | for (i = 0; i < ARRAY_SIZE(debuglink_paths); i++) { | |
148 | snprintf(filename, size, | |
149 | debuglink_paths[i], dso_dir, symfile); | |
150 | if (is_regular_file(filename)) { | |
151 | ret = 0; | |
152 | break; | |
153 | } | |
cdd059d7 | 154 | } |
9343e45b | 155 | |
cdd059d7 | 156 | break; |
9343e45b | 157 | } |
cdd059d7 | 158 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: |
d2396999 KJ |
159 | if (dso__build_id_filename(dso, filename, size, false) == NULL) |
160 | ret = -1; | |
161 | break; | |
162 | ||
163 | case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: | |
164 | if (dso__build_id_filename(dso, filename, size, true) == NULL) | |
cdd059d7 JO |
165 | ret = -1; |
166 | break; | |
167 | ||
168 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: | |
972f393b | 169 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug"); |
ee756ef7 | 170 | snprintf(filename + len, size - len, "%s.debug", dso__long_name(dso)); |
cdd059d7 JO |
171 | break; |
172 | ||
173 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: | |
972f393b | 174 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug"); |
ee756ef7 | 175 | snprintf(filename + len, size - len, "%s", dso__long_name(dso)); |
cdd059d7 JO |
176 | break; |
177 | ||
85afd355 AH |
178 | case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO: |
179 | /* | |
180 | * Ubuntu can mixup /usr/lib with /lib, putting debuginfo in | |
181 | * /usr/lib/debug/lib when it is expected to be in | |
182 | * /usr/lib/debug/usr/lib | |
183 | */ | |
ee756ef7 IR |
184 | if (strlen(dso__long_name(dso)) < 9 || |
185 | strncmp(dso__long_name(dso), "/usr/lib/", 9)) { | |
85afd355 AH |
186 | ret = -1; |
187 | break; | |
188 | } | |
189 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug"); | |
ee756ef7 | 190 | snprintf(filename + len, size - len, "%s", dso__long_name(dso) + 4); |
85afd355 AH |
191 | break; |
192 | ||
9cd00941 RRD |
193 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: |
194 | { | |
bf4414ae | 195 | const char *last_slash; |
9cd00941 RRD |
196 | size_t dir_size; |
197 | ||
ee756ef7 IR |
198 | last_slash = dso__long_name(dso) + dso__long_name_len(dso); |
199 | while (last_slash != dso__long_name(dso) && *last_slash != '/') | |
9cd00941 RRD |
200 | last_slash--; |
201 | ||
972f393b | 202 | len = __symbol__join_symfs(filename, size, ""); |
ee756ef7 | 203 | dir_size = last_slash - dso__long_name(dso) + 2; |
9cd00941 RRD |
204 | if (dir_size > (size - len)) { |
205 | ret = -1; | |
206 | break; | |
207 | } | |
ee756ef7 | 208 | len += scnprintf(filename + len, dir_size, "%s", dso__long_name(dso)); |
7d2a5122 | 209 | len += scnprintf(filename + len , size - len, ".debug%s", |
9cd00941 RRD |
210 | last_slash); |
211 | break; | |
212 | } | |
213 | ||
cdd059d7 | 214 | case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: |
ee756ef7 | 215 | if (!dso__has_build_id(dso)) { |
cdd059d7 JO |
216 | ret = -1; |
217 | break; | |
218 | } | |
219 | ||
ee756ef7 | 220 | build_id__sprintf(dso__bid_const(dso), build_id_hex); |
972f393b ACM |
221 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/"); |
222 | snprintf(filename + len, size - len, "%.2s/%s.debug", | |
223 | build_id_hex, build_id_hex + 2); | |
cdd059d7 JO |
224 | break; |
225 | ||
39b12f78 AH |
226 | case DSO_BINARY_TYPE__VMLINUX: |
227 | case DSO_BINARY_TYPE__GUEST_VMLINUX: | |
cdd059d7 | 228 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: |
b10f7430 | 229 | case DSO_BINARY_TYPE__GNU_DEBUGDATA: |
ee756ef7 | 230 | __symbol__join_symfs(filename, size, dso__long_name(dso)); |
cdd059d7 JO |
231 | break; |
232 | ||
233 | case DSO_BINARY_TYPE__GUEST_KMODULE: | |
c00c48fc | 234 | case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: |
972f393b | 235 | path__join3(filename, size, symbol_conf.symfs, |
ee756ef7 | 236 | root_dir, dso__long_name(dso)); |
cdd059d7 JO |
237 | break; |
238 | ||
239 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: | |
c00c48fc | 240 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: |
ee756ef7 | 241 | __symbol__join_symfs(filename, size, dso__long_name(dso)); |
cdd059d7 JO |
242 | break; |
243 | ||
8e0cf965 AH |
244 | case DSO_BINARY_TYPE__KCORE: |
245 | case DSO_BINARY_TYPE__GUEST_KCORE: | |
ee756ef7 | 246 | snprintf(filename, size, "%s", dso__long_name(dso)); |
8e0cf965 AH |
247 | break; |
248 | ||
cdd059d7 JO |
249 | default: |
250 | case DSO_BINARY_TYPE__KALLSYMS: | |
cdd059d7 | 251 | case DSO_BINARY_TYPE__GUEST_KALLSYMS: |
cdd059d7 | 252 | case DSO_BINARY_TYPE__JAVA_JIT: |
9b86d04d | 253 | case DSO_BINARY_TYPE__BPF_PROG_INFO: |
3c29d448 | 254 | case DSO_BINARY_TYPE__BPF_IMAGE: |
789e2419 | 255 | case DSO_BINARY_TYPE__OOL: |
cdd059d7 JO |
256 | case DSO_BINARY_TYPE__NOT_FOUND: |
257 | ret = -1; | |
258 | break; | |
259 | } | |
260 | ||
261 | return ret; | |
262 | } | |
263 | ||
4b838b0d JO |
264 | enum { |
265 | COMP_ID__NONE = 0, | |
266 | }; | |
267 | ||
c00c48fc NK |
268 | static const struct { |
269 | const char *fmt; | |
270 | int (*decompress)(const char *input, int output); | |
8b42b7e5 | 271 | bool (*is_compressed)(const char *input); |
c00c48fc | 272 | } compressions[] = { |
4b838b0d | 273 | [COMP_ID__NONE] = { .fmt = NULL, }, |
e92ce12e | 274 | #ifdef HAVE_ZLIB_SUPPORT |
8b42b7e5 | 275 | { "gz", gzip_decompress_to_file, gzip_is_compressed }, |
80a32e5b JO |
276 | #endif |
277 | #ifdef HAVE_LZMA_SUPPORT | |
8b42b7e5 | 278 | { "xz", lzma_decompress_to_file, lzma_is_compressed }, |
e92ce12e | 279 | #endif |
8b42b7e5 | 280 | { NULL, NULL, NULL }, |
c00c48fc NK |
281 | }; |
282 | ||
4b838b0d | 283 | static int is_supported_compression(const char *ext) |
c00c48fc NK |
284 | { |
285 | unsigned i; | |
286 | ||
4b838b0d | 287 | for (i = 1; compressions[i].fmt; i++) { |
c00c48fc | 288 | if (!strcmp(ext, compressions[i].fmt)) |
4b838b0d | 289 | return i; |
c00c48fc | 290 | } |
4b838b0d | 291 | return COMP_ID__NONE; |
c00c48fc NK |
292 | } |
293 | ||
1f121b03 | 294 | bool is_kernel_module(const char *pathname, int cpumode) |
c00c48fc | 295 | { |
8dee9ff1 | 296 | struct kmod_path m; |
1f121b03 WN |
297 | int mode = cpumode & PERF_RECORD_MISC_CPUMODE_MASK; |
298 | ||
299 | WARN_ONCE(mode != cpumode, | |
300 | "Internal error: passing unmasked cpumode (%x) to is_kernel_module", | |
301 | cpumode); | |
302 | ||
303 | switch (mode) { | |
304 | case PERF_RECORD_MISC_USER: | |
305 | case PERF_RECORD_MISC_HYPERVISOR: | |
306 | case PERF_RECORD_MISC_GUEST_USER: | |
307 | return false; | |
308 | /* Treat PERF_RECORD_MISC_CPUMODE_UNKNOWN as kernel */ | |
309 | default: | |
310 | if (kmod_path__parse(&m, pathname)) { | |
311 | pr_err("Failed to check whether %s is a kernel module or not. Assume it is.", | |
312 | pathname); | |
313 | return true; | |
314 | } | |
315 | } | |
c00c48fc | 316 | |
8dee9ff1 | 317 | return m.kmod; |
c00c48fc NK |
318 | } |
319 | ||
c00c48fc NK |
320 | bool dso__needs_decompress(struct dso *dso) |
321 | { | |
ee756ef7 IR |
322 | return dso__symtab_type(dso) == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || |
323 | dso__symtab_type(dso) == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; | |
c00c48fc NK |
324 | } |
325 | ||
7ac22b08 JO |
326 | int filename__decompress(const char *name, char *pathname, |
327 | size_t len, int comp, int *err) | |
42b3fa67 | 328 | { |
c9a8a613 | 329 | char tmpbuf[] = KMOD_DECOMP_NAME; |
42b3fa67 | 330 | int fd = -1; |
42b3fa67 | 331 | |
8b42b7e5 JO |
332 | /* |
333 | * We have proper compression id for DSO and yet the file | |
334 | * behind the 'name' can still be plain uncompressed object. | |
335 | * | |
336 | * The reason is behind the logic we open the DSO object files, | |
337 | * when we try all possible 'debug' objects until we find the | |
338 | * data. So even if the DSO is represented by 'krava.xz' module, | |
339 | * we can end up here opening ~/.debug/....23432432/debug' file | |
340 | * which is not compressed. | |
341 | * | |
342 | * To keep this transparent, we detect this and return the file | |
343 | * descriptor to the uncompressed file. | |
344 | */ | |
7ac22b08 | 345 | if (!compressions[comp].is_compressed(name)) |
8b42b7e5 JO |
346 | return open(name, O_RDONLY); |
347 | ||
42b3fa67 NK |
348 | fd = mkstemp(tmpbuf); |
349 | if (fd < 0) { | |
7ac22b08 | 350 | *err = errno; |
dde755a9 | 351 | return -1; |
42b3fa67 NK |
352 | } |
353 | ||
7ac22b08 JO |
354 | if (compressions[comp].decompress(name, fd)) { |
355 | *err = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE; | |
42b3fa67 NK |
356 | close(fd); |
357 | fd = -1; | |
358 | } | |
359 | ||
c9a8a613 JO |
360 | if (!pathname || (fd < 0)) |
361 | unlink(tmpbuf); | |
362 | ||
363 | if (pathname && (fd >= 0)) | |
fca5085c | 364 | strlcpy(pathname, tmpbuf, len); |
c9a8a613 | 365 | |
42b3fa67 NK |
366 | return fd; |
367 | } | |
368 | ||
7ac22b08 JO |
369 | static int decompress_kmodule(struct dso *dso, const char *name, |
370 | char *pathname, size_t len) | |
371 | { | |
372 | if (!dso__needs_decompress(dso)) | |
373 | return -1; | |
374 | ||
ee756ef7 | 375 | if (dso__comp(dso) == COMP_ID__NONE) |
7ac22b08 JO |
376 | return -1; |
377 | ||
ee756ef7 | 378 | return filename__decompress(name, pathname, len, dso__comp(dso), dso__load_errno(dso)); |
7ac22b08 JO |
379 | } |
380 | ||
42b3fa67 NK |
381 | int dso__decompress_kmodule_fd(struct dso *dso, const char *name) |
382 | { | |
c9a8a613 | 383 | return decompress_kmodule(dso, name, NULL, 0); |
42b3fa67 NK |
384 | } |
385 | ||
386 | int dso__decompress_kmodule_path(struct dso *dso, const char *name, | |
387 | char *pathname, size_t len) | |
388 | { | |
c9a8a613 | 389 | int fd = decompress_kmodule(dso, name, pathname, len); |
42b3fa67 | 390 | |
42b3fa67 | 391 | close(fd); |
c9a8a613 | 392 | return fd >= 0 ? 0 : -1; |
42b3fa67 NK |
393 | } |
394 | ||
3c8a67f5 JO |
395 | /* |
396 | * Parses kernel module specified in @path and updates | |
397 | * @m argument like: | |
398 | * | |
399 | * @comp - true if @path contains supported compression suffix, | |
400 | * false otherwise | |
401 | * @kmod - true if @path contains '.ko' suffix in right position, | |
402 | * false otherwise | |
403 | * @name - if (@alloc_name && @kmod) is true, it contains strdup-ed base name | |
404 | * of the kernel module without suffixes, otherwise strudup-ed | |
405 | * base name of @path | |
406 | * @ext - if (@alloc_ext && @comp) is true, it contains strdup-ed string | |
407 | * the compression suffix | |
408 | * | |
409 | * Returns 0 if there's no strdup error, -ENOMEM otherwise. | |
410 | */ | |
411 | int __kmod_path__parse(struct kmod_path *m, const char *path, | |
b946cd37 | 412 | bool alloc_name) |
3c8a67f5 JO |
413 | { |
414 | const char *name = strrchr(path, '/'); | |
415 | const char *ext = strrchr(path, '.'); | |
1f121b03 | 416 | bool is_simple_name = false; |
3c8a67f5 JO |
417 | |
418 | memset(m, 0x0, sizeof(*m)); | |
419 | name = name ? name + 1 : path; | |
420 | ||
1f121b03 WN |
421 | /* |
422 | * '.' is also a valid character for module name. For example: | |
423 | * [aaa.bbb] is a valid module name. '[' should have higher | |
424 | * priority than '.ko' suffix. | |
425 | * | |
426 | * The kernel names are from machine__mmap_name. Such | |
427 | * name should belong to kernel itself, not kernel module. | |
428 | */ | |
429 | if (name[0] == '[') { | |
430 | is_simple_name = true; | |
431 | if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) || | |
432 | (strncmp(name, "[guest.kernel.kallsyms", 22) == 0) || | |
433 | (strncmp(name, "[vdso]", 6) == 0) || | |
aef4feac AH |
434 | (strncmp(name, "[vdso32]", 8) == 0) || |
435 | (strncmp(name, "[vdsox32]", 9) == 0) || | |
1f121b03 WN |
436 | (strncmp(name, "[vsyscall]", 10) == 0)) { |
437 | m->kmod = false; | |
438 | ||
439 | } else | |
440 | m->kmod = true; | |
441 | } | |
442 | ||
3c8a67f5 | 443 | /* No extension, just return name. */ |
1f121b03 | 444 | if ((ext == NULL) || is_simple_name) { |
3c8a67f5 JO |
445 | if (alloc_name) { |
446 | m->name = strdup(name); | |
447 | return m->name ? 0 : -ENOMEM; | |
448 | } | |
449 | return 0; | |
450 | } | |
451 | ||
4b838b0d JO |
452 | m->comp = is_supported_compression(ext + 1); |
453 | if (m->comp > COMP_ID__NONE) | |
3c8a67f5 | 454 | ext -= 3; |
3c8a67f5 JO |
455 | |
456 | /* Check .ko extension only if there's enough name left. */ | |
457 | if (ext > name) | |
458 | m->kmod = !strncmp(ext, ".ko", 3); | |
459 | ||
460 | if (alloc_name) { | |
461 | if (m->kmod) { | |
462 | if (asprintf(&m->name, "[%.*s]", (int) (ext - name), name) == -1) | |
463 | return -ENOMEM; | |
464 | } else { | |
465 | if (asprintf(&m->name, "%s", name) == -1) | |
466 | return -ENOMEM; | |
467 | } | |
468 | ||
af0de0c5 | 469 | strreplace(m->name, '-', '_'); |
3c8a67f5 JO |
470 | } |
471 | ||
3c8a67f5 JO |
472 | return 0; |
473 | } | |
474 | ||
6b335e8f NK |
475 | void dso__set_module_info(struct dso *dso, struct kmod_path *m, |
476 | struct machine *machine) | |
477 | { | |
478 | if (machine__is_host(machine)) | |
ee756ef7 | 479 | dso__set_symtab_type(dso, DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE); |
6b335e8f | 480 | else |
ee756ef7 | 481 | dso__set_symtab_type(dso, DSO_BINARY_TYPE__GUEST_KMODULE); |
6b335e8f NK |
482 | |
483 | /* _KMODULE_COMP should be next to _KMODULE */ | |
2af52475 | 484 | if (m->kmod && m->comp) { |
ee756ef7 IR |
485 | dso__set_symtab_type(dso, dso__symtab_type(dso) + 1); |
486 | dso__set_comp(dso, m->comp); | |
2af52475 | 487 | } |
6b335e8f | 488 | |
ee756ef7 | 489 | dso__set_is_kmod(dso); |
6b335e8f NK |
490 | dso__set_short_name(dso, strdup(m->name), true); |
491 | } | |
492 | ||
eba5102d | 493 | /* |
bda6ee4a | 494 | * Global list of open DSOs and the counter. |
eba5102d | 495 | */ |
5ac22c35 | 496 | struct mutex _dso__data_open_lock; |
eba5102d | 497 | static LIST_HEAD(dso__data_open); |
5ac22c35 | 498 | static long dso__data_open_cnt GUARDED_BY(_dso__data_open_lock); |
eba5102d | 499 | |
5ac22c35 IR |
500 | static void dso__data_open_lock_init(void) |
501 | { | |
502 | mutex_init(&_dso__data_open_lock); | |
503 | } | |
504 | ||
505 | static struct mutex *dso__data_open_lock(void) LOCK_RETURNED(_dso__data_open_lock) | |
506 | { | |
507 | static pthread_once_t data_open_lock_once = PTHREAD_ONCE_INIT; | |
508 | ||
509 | pthread_once(&data_open_lock_once, dso__data_open_lock_init); | |
510 | ||
511 | return &_dso__data_open_lock; | |
512 | } | |
513 | ||
514 | static void dso__list_add(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) | |
eba5102d | 515 | { |
ee756ef7 | 516 | list_add_tail(&dso__data(dso)->open_entry, &dso__data_open); |
37862d6f | 517 | #ifdef REFCNT_CHECKING |
ee756ef7 | 518 | dso__data(dso)->dso = dso__get(dso); |
37862d6f IR |
519 | #endif |
520 | /* Assume the dso is part of dsos, hence the optional reference count above. */ | |
521 | assert(dso__dsos(dso)); | |
bda6ee4a | 522 | dso__data_open_cnt++; |
eba5102d JO |
523 | } |
524 | ||
5ac22c35 | 525 | static void dso__list_del(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) |
eba5102d | 526 | { |
ee756ef7 | 527 | list_del_init(&dso__data(dso)->open_entry); |
37862d6f | 528 | #ifdef REFCNT_CHECKING |
5ac22c35 | 529 | mutex_unlock(dso__data_open_lock()); |
ee756ef7 | 530 | dso__put(dso__data(dso)->dso); |
5ac22c35 | 531 | mutex_lock(dso__data_open_lock()); |
37862d6f | 532 | #endif |
bda6ee4a JO |
533 | WARN_ONCE(dso__data_open_cnt <= 0, |
534 | "DSO data fd counter out of bounds."); | |
535 | dso__data_open_cnt--; | |
eba5102d JO |
536 | } |
537 | ||
a08cae03 JO |
538 | static void close_first_dso(void); |
539 | ||
5ac22c35 | 540 | static int do_open(char *name) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) |
a08cae03 JO |
541 | { |
542 | int fd; | |
6e81c74c | 543 | char sbuf[STRERR_BUFSIZE]; |
a08cae03 JO |
544 | |
545 | do { | |
4c0d8d27 | 546 | fd = open(name, O_RDONLY|O_CLOEXEC); |
a08cae03 JO |
547 | if (fd >= 0) |
548 | return fd; | |
549 | ||
a3c0cc2a | 550 | pr_debug("dso open failed: %s\n", |
c8b5f2c9 | 551 | str_error_r(errno, sbuf, sizeof(sbuf))); |
a08cae03 JO |
552 | if (!dso__data_open_cnt || errno != EMFILE) |
553 | break; | |
554 | ||
555 | close_first_dso(); | |
556 | } while (1); | |
557 | ||
558 | return -1; | |
559 | } | |
560 | ||
7031edac ACM |
561 | char *dso__filename_with_chroot(const struct dso *dso, const char *filename) |
562 | { | |
ee756ef7 | 563 | return filename_with_chroot(nsinfo__pid(dso__nsinfo_const(dso)), filename); |
7031edac ACM |
564 | } |
565 | ||
eba5102d | 566 | static int __open_dso(struct dso *dso, struct machine *machine) |
5ac22c35 | 567 | EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) |
cdd059d7 | 568 | { |
8ba29adf | 569 | int fd = -EINVAL; |
ee4e9625 ACM |
570 | char *root_dir = (char *)""; |
571 | char *name = malloc(PATH_MAX); | |
d68a29c2 | 572 | bool decomp = false; |
cdd059d7 | 573 | |
cdd059d7 JO |
574 | if (!name) |
575 | return -ENOMEM; | |
576 | ||
ee756ef7 | 577 | mutex_lock(dso__lock(dso)); |
cdd059d7 JO |
578 | if (machine) |
579 | root_dir = machine->root_dir; | |
580 | ||
ee756ef7 | 581 | if (dso__read_binary_type_filename(dso, dso__binary_type(dso), |
8ba29adf NK |
582 | root_dir, name, PATH_MAX)) |
583 | goto out; | |
cdd059d7 | 584 | |
67fd1892 NK |
585 | if (!is_regular_file(name)) { |
586 | char *new_name; | |
587 | ||
ee756ef7 | 588 | if (errno != ENOENT || dso__nsinfo(dso) == NULL) |
67fd1892 NK |
589 | goto out; |
590 | ||
7031edac | 591 | new_name = dso__filename_with_chroot(dso, name); |
67fd1892 NK |
592 | if (!new_name) |
593 | goto out; | |
594 | ||
595 | free(name); | |
596 | name = new_name; | |
597 | } | |
3c028a0c | 598 | |
1d6b3c9b NK |
599 | if (dso__needs_decompress(dso)) { |
600 | char newpath[KMOD_DECOMP_LEN]; | |
601 | size_t len = sizeof(newpath); | |
602 | ||
603 | if (dso__decompress_kmodule_path(dso, name, newpath, len) < 0) { | |
ee756ef7 | 604 | fd = -(*dso__load_errno(dso)); |
8ba29adf | 605 | goto out; |
1d6b3c9b NK |
606 | } |
607 | ||
d68a29c2 | 608 | decomp = true; |
1d6b3c9b NK |
609 | strcpy(name, newpath); |
610 | } | |
611 | ||
a08cae03 | 612 | fd = do_open(name); |
1d6b3c9b | 613 | |
d68a29c2 | 614 | if (decomp) |
1d6b3c9b NK |
615 | unlink(name); |
616 | ||
8ba29adf | 617 | out: |
ee756ef7 | 618 | mutex_unlock(dso__lock(dso)); |
cdd059d7 JO |
619 | free(name); |
620 | return fd; | |
621 | } | |
622 | ||
c6580451 JO |
623 | static void check_data_close(void); |
624 | ||
c1f9aa0a JO |
625 | /** |
626 | * dso_close - Open DSO data file | |
627 | * @dso: dso object | |
628 | * | |
629 | * Open @dso's data file descriptor and updates | |
630 | * list/count of open DSO objects. | |
631 | */ | |
eba5102d | 632 | static int open_dso(struct dso *dso, struct machine *machine) |
5ac22c35 | 633 | EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) |
eba5102d | 634 | { |
f045b8c4 KJ |
635 | int fd; |
636 | struct nscookie nsc; | |
637 | ||
ee756ef7 IR |
638 | if (dso__binary_type(dso) != DSO_BINARY_TYPE__BUILD_ID_CACHE) { |
639 | mutex_lock(dso__lock(dso)); | |
640 | nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); | |
641 | mutex_unlock(dso__lock(dso)); | |
e54dea69 | 642 | } |
f045b8c4 | 643 | fd = __open_dso(dso, machine); |
ee756ef7 | 644 | if (dso__binary_type(dso) != DSO_BINARY_TYPE__BUILD_ID_CACHE) |
f045b8c4 | 645 | nsinfo__mountns_exit(&nsc); |
eba5102d | 646 | |
a6f6ae99 | 647 | if (fd >= 0) { |
eba5102d | 648 | dso__list_add(dso); |
c6580451 JO |
649 | /* |
650 | * Check if we crossed the allowed number | |
651 | * of opened DSOs and close one if needed. | |
652 | */ | |
653 | check_data_close(); | |
654 | } | |
eba5102d JO |
655 | |
656 | return fd; | |
657 | } | |
658 | ||
5ac22c35 | 659 | static void close_data_fd(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) |
53fa8eaa | 660 | { |
ee756ef7 IR |
661 | if (dso__data(dso)->fd >= 0) { |
662 | close(dso__data(dso)->fd); | |
663 | dso__data(dso)->fd = -1; | |
664 | dso__data(dso)->file_size = 0; | |
eba5102d | 665 | dso__list_del(dso); |
53fa8eaa JO |
666 | } |
667 | } | |
668 | ||
c1f9aa0a JO |
669 | /** |
670 | * dso_close - Close DSO data file | |
671 | * @dso: dso object | |
672 | * | |
673 | * Close @dso's data file descriptor and updates | |
674 | * list/count of open DSO objects. | |
675 | */ | |
5ac22c35 | 676 | static void close_dso(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) |
eba5102d JO |
677 | { |
678 | close_data_fd(dso); | |
679 | } | |
680 | ||
5ac22c35 | 681 | static void close_first_dso(void) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) |
c6580451 | 682 | { |
ee756ef7 | 683 | struct dso_data *dso_data; |
37862d6f | 684 | struct dso *dso; |
c6580451 | 685 | |
ee756ef7 | 686 | dso_data = list_first_entry(&dso__data_open, struct dso_data, open_entry); |
37862d6f IR |
687 | #ifdef REFCNT_CHECKING |
688 | dso = dso_data->dso; | |
689 | #else | |
690 | dso = container_of(dso_data, struct dso, data); | |
691 | #endif | |
692 | close_dso(dso); | |
c6580451 JO |
693 | } |
694 | ||
695 | static rlim_t get_fd_limit(void) | |
696 | { | |
697 | struct rlimit l; | |
698 | rlim_t limit = 0; | |
699 | ||
700 | /* Allow half of the current open fd limit. */ | |
701 | if (getrlimit(RLIMIT_NOFILE, &l) == 0) { | |
702 | if (l.rlim_cur == RLIM_INFINITY) | |
703 | limit = l.rlim_cur; | |
704 | else | |
705 | limit = l.rlim_cur / 2; | |
706 | } else { | |
707 | pr_err("failed to get fd limit\n"); | |
708 | limit = 1; | |
709 | } | |
710 | ||
711 | return limit; | |
712 | } | |
713 | ||
f3069249 JO |
714 | static rlim_t fd_limit; |
715 | ||
716 | /* | |
717 | * Used only by tests/dso-data.c to reset the environment | |
718 | * for tests. I dont expect we should change this during | |
719 | * standard runtime. | |
720 | */ | |
721 | void reset_fd_limit(void) | |
c6580451 | 722 | { |
f3069249 JO |
723 | fd_limit = 0; |
724 | } | |
c6580451 | 725 | |
5ac22c35 | 726 | static bool may_cache_fd(void) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) |
f3069249 JO |
727 | { |
728 | if (!fd_limit) | |
729 | fd_limit = get_fd_limit(); | |
c6580451 | 730 | |
f3069249 | 731 | if (fd_limit == RLIM_INFINITY) |
c6580451 JO |
732 | return true; |
733 | ||
f3069249 | 734 | return fd_limit > (rlim_t) dso__data_open_cnt; |
c6580451 JO |
735 | } |
736 | ||
c1f9aa0a JO |
737 | /* |
738 | * Check and close LRU dso if we crossed allowed limit | |
739 | * for opened dso file descriptors. The limit is half | |
740 | * of the RLIMIT_NOFILE files opened. | |
741 | */ | |
5ac22c35 | 742 | static void check_data_close(void) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) |
c6580451 JO |
743 | { |
744 | bool cache_fd = may_cache_fd(); | |
745 | ||
746 | if (!cache_fd) | |
747 | close_first_dso(); | |
748 | } | |
749 | ||
c1f9aa0a JO |
750 | /** |
751 | * dso__data_close - Close DSO data file | |
752 | * @dso: dso object | |
753 | * | |
754 | * External interface to close @dso's data file descriptor. | |
755 | */ | |
eba5102d JO |
756 | void dso__data_close(struct dso *dso) |
757 | { | |
5ac22c35 | 758 | mutex_lock(dso__data_open_lock()); |
eba5102d | 759 | close_dso(dso); |
5ac22c35 | 760 | mutex_unlock(dso__data_open_lock()); |
eba5102d JO |
761 | } |
762 | ||
71ff824a | 763 | static void try_to_open_dso(struct dso *dso, struct machine *machine) |
5ac22c35 | 764 | EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) |
cdd059d7 | 765 | { |
631d34b5 | 766 | enum dso_binary_type binary_type_data[] = { |
cdd059d7 JO |
767 | DSO_BINARY_TYPE__BUILD_ID_CACHE, |
768 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, | |
769 | DSO_BINARY_TYPE__NOT_FOUND, | |
770 | }; | |
771 | int i = 0; | |
ee756ef7 | 772 | struct dso_data *dso_data = dso__data(dso); |
cdd059d7 | 773 | |
ee756ef7 | 774 | if (dso_data->fd >= 0) |
71ff824a | 775 | return; |
53fa8eaa | 776 | |
ee756ef7 IR |
777 | if (dso__binary_type(dso) != DSO_BINARY_TYPE__NOT_FOUND) { |
778 | dso_data->fd = open_dso(dso, machine); | |
c27697d6 | 779 | goto out; |
53fa8eaa | 780 | } |
cdd059d7 JO |
781 | |
782 | do { | |
ee756ef7 | 783 | dso__set_binary_type(dso, binary_type_data[i++]); |
cdd059d7 | 784 | |
ee756ef7 IR |
785 | dso_data->fd = open_dso(dso, machine); |
786 | if (dso_data->fd >= 0) | |
c27697d6 | 787 | goto out; |
cdd059d7 | 788 | |
ee756ef7 | 789 | } while (dso__binary_type(dso) != DSO_BINARY_TYPE__NOT_FOUND); |
c27697d6 | 790 | out: |
ee756ef7 IR |
791 | if (dso_data->fd >= 0) |
792 | dso_data->status = DSO_DATA_STATUS_OK; | |
c27697d6 | 793 | else |
ee756ef7 | 794 | dso_data->status = DSO_DATA_STATUS_ERROR; |
71ff824a NK |
795 | } |
796 | ||
797 | /** | |
4bb11d01 | 798 | * dso__data_get_fd - Get dso's data file descriptor |
71ff824a NK |
799 | * @dso: dso object |
800 | * @machine: machine object | |
801 | * | |
802 | * External interface to find dso's file, open it and | |
4bb11d01 NK |
803 | * returns file descriptor. It should be paired with |
804 | * dso__data_put_fd() if it returns non-negative value. | |
71ff824a | 805 | */ |
5ac22c35 | 806 | bool dso__data_get_fd(struct dso *dso, struct machine *machine, int *fd) |
71ff824a | 807 | { |
5ac22c35 | 808 | *fd = -1; |
ee756ef7 | 809 | if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR) |
5ac22c35 | 810 | return false; |
cdd059d7 | 811 | |
5ac22c35 | 812 | mutex_lock(dso__data_open_lock()); |
4bb11d01 | 813 | |
71ff824a | 814 | try_to_open_dso(dso, machine); |
4bb11d01 | 815 | |
5ac22c35 IR |
816 | *fd = dso__data(dso)->fd; |
817 | if (*fd >= 0) | |
818 | return true; | |
71ff824a | 819 | |
5ac22c35 IR |
820 | mutex_unlock(dso__data_open_lock()); |
821 | return false; | |
cdd059d7 JO |
822 | } |
823 | ||
4bb11d01 NK |
824 | void dso__data_put_fd(struct dso *dso __maybe_unused) |
825 | { | |
5ac22c35 | 826 | mutex_unlock(dso__data_open_lock()); |
4bb11d01 NK |
827 | } |
828 | ||
288be943 AH |
829 | bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by) |
830 | { | |
831 | u32 flag = 1 << by; | |
832 | ||
ee756ef7 | 833 | if (dso__data(dso)->status_seen & flag) |
288be943 AH |
834 | return true; |
835 | ||
ee756ef7 | 836 | dso__data(dso)->status_seen |= flag; |
288be943 AH |
837 | |
838 | return false; | |
839 | } | |
840 | ||
ef0580ec | 841 | #ifdef HAVE_LIBBPF_SUPPORT |
6c398d72 JO |
842 | static ssize_t bpf_read(struct dso *dso, u64 offset, char *data) |
843 | { | |
844 | struct bpf_prog_info_node *node; | |
845 | ssize_t size = DSO__DATA_CACHE_SIZE; | |
ee756ef7 | 846 | struct dso_bpf_prog *dso_bpf_prog = dso__bpf_prog(dso); |
6c398d72 JO |
847 | u64 len; |
848 | u8 *buf; | |
849 | ||
ee756ef7 | 850 | node = perf_env__find_bpf_prog_info(dso_bpf_prog->env, dso_bpf_prog->id); |
6c398d72 | 851 | if (!node || !node->info_linear) { |
ee756ef7 | 852 | dso__data(dso)->status = DSO_DATA_STATUS_ERROR; |
6c398d72 JO |
853 | return -1; |
854 | } | |
855 | ||
856 | len = node->info_linear->info.jited_prog_len; | |
857 | buf = (u8 *)(uintptr_t)node->info_linear->info.jited_prog_insns; | |
858 | ||
859 | if (offset >= len) | |
860 | return -1; | |
861 | ||
862 | size = (ssize_t)min(len - offset, (u64)size); | |
863 | memcpy(data, buf + offset, size); | |
864 | return size; | |
865 | } | |
866 | ||
867 | static int bpf_size(struct dso *dso) | |
868 | { | |
869 | struct bpf_prog_info_node *node; | |
ee756ef7 | 870 | struct dso_bpf_prog *dso_bpf_prog = dso__bpf_prog(dso); |
6c398d72 | 871 | |
ee756ef7 | 872 | node = perf_env__find_bpf_prog_info(dso_bpf_prog->env, dso_bpf_prog->id); |
6c398d72 | 873 | if (!node || !node->info_linear) { |
ee756ef7 | 874 | dso__data(dso)->status = DSO_DATA_STATUS_ERROR; |
6c398d72 JO |
875 | return -1; |
876 | } | |
877 | ||
ee756ef7 | 878 | dso__data(dso)->file_size = node->info_linear->info.jited_prog_len; |
6c398d72 JO |
879 | return 0; |
880 | } | |
ef0580ec | 881 | #endif // HAVE_LIBBPF_SUPPORT |
6c398d72 | 882 | |
cdd059d7 | 883 | static void |
8e67b725 | 884 | dso_cache__free(struct dso *dso) |
cdd059d7 | 885 | { |
ee756ef7 | 886 | struct rb_root *root = &dso__data(dso)->cache; |
cdd059d7 JO |
887 | struct rb_node *next = rb_first(root); |
888 | ||
ee756ef7 | 889 | mutex_lock(dso__lock(dso)); |
cdd059d7 JO |
890 | while (next) { |
891 | struct dso_cache *cache; | |
892 | ||
893 | cache = rb_entry(next, struct dso_cache, rb_node); | |
894 | next = rb_next(&cache->rb_node); | |
895 | rb_erase(&cache->rb_node, root); | |
896 | free(cache); | |
897 | } | |
ee756ef7 | 898 | mutex_unlock(dso__lock(dso)); |
cdd059d7 JO |
899 | } |
900 | ||
366df726 | 901 | static struct dso_cache *__dso_cache__find(struct dso *dso, u64 offset) |
cdd059d7 | 902 | { |
ee756ef7 | 903 | const struct rb_root *root = &dso__data(dso)->cache; |
3344996e ACM |
904 | struct rb_node * const *p = &root->rb_node; |
905 | const struct rb_node *parent = NULL; | |
cdd059d7 JO |
906 | struct dso_cache *cache; |
907 | ||
908 | while (*p != NULL) { | |
909 | u64 end; | |
910 | ||
911 | parent = *p; | |
912 | cache = rb_entry(parent, struct dso_cache, rb_node); | |
913 | end = cache->offset + DSO__DATA_CACHE_SIZE; | |
914 | ||
915 | if (offset < cache->offset) | |
916 | p = &(*p)->rb_left; | |
917 | else if (offset >= end) | |
918 | p = &(*p)->rb_right; | |
919 | else | |
920 | return cache; | |
921 | } | |
8e67b725 | 922 | |
cdd059d7 JO |
923 | return NULL; |
924 | } | |
925 | ||
8e67b725 NK |
926 | static struct dso_cache * |
927 | dso_cache__insert(struct dso *dso, struct dso_cache *new) | |
cdd059d7 | 928 | { |
ee756ef7 | 929 | struct rb_root *root = &dso__data(dso)->cache; |
cdd059d7 JO |
930 | struct rb_node **p = &root->rb_node; |
931 | struct rb_node *parent = NULL; | |
932 | struct dso_cache *cache; | |
933 | u64 offset = new->offset; | |
934 | ||
ee756ef7 | 935 | mutex_lock(dso__lock(dso)); |
cdd059d7 JO |
936 | while (*p != NULL) { |
937 | u64 end; | |
938 | ||
939 | parent = *p; | |
940 | cache = rb_entry(parent, struct dso_cache, rb_node); | |
941 | end = cache->offset + DSO__DATA_CACHE_SIZE; | |
942 | ||
943 | if (offset < cache->offset) | |
944 | p = &(*p)->rb_left; | |
945 | else if (offset >= end) | |
946 | p = &(*p)->rb_right; | |
8e67b725 NK |
947 | else |
948 | goto out; | |
cdd059d7 JO |
949 | } |
950 | ||
951 | rb_link_node(&new->rb_node, parent, p); | |
952 | rb_insert_color(&new->rb_node, root); | |
8e67b725 NK |
953 | |
954 | cache = NULL; | |
955 | out: | |
ee756ef7 | 956 | mutex_unlock(dso__lock(dso)); |
8e67b725 | 957 | return cache; |
cdd059d7 JO |
958 | } |
959 | ||
b86a9d91 AH |
960 | static ssize_t dso_cache__memcpy(struct dso_cache *cache, u64 offset, u8 *data, |
961 | u64 size, bool out) | |
cdd059d7 JO |
962 | { |
963 | u64 cache_offset = offset - cache->offset; | |
964 | u64 cache_size = min(cache->size - cache_offset, size); | |
965 | ||
b86a9d91 AH |
966 | if (out) |
967 | memcpy(data, cache->data + cache_offset, cache_size); | |
968 | else | |
969 | memcpy(cache->data + cache_offset, data, cache_size); | |
cdd059d7 JO |
970 | return cache_size; |
971 | } | |
972 | ||
ea5db1bd JO |
973 | static ssize_t file_read(struct dso *dso, struct machine *machine, |
974 | u64 offset, char *data) | |
975 | { | |
976 | ssize_t ret; | |
977 | ||
5ac22c35 | 978 | mutex_lock(dso__data_open_lock()); |
ea5db1bd JO |
979 | |
980 | /* | |
ee756ef7 | 981 | * dso__data(dso)->fd might be closed if other thread opened another |
ea5db1bd JO |
982 | * file (dso) due to open file limit (RLIMIT_NOFILE). |
983 | */ | |
984 | try_to_open_dso(dso, machine); | |
985 | ||
ee756ef7 IR |
986 | if (dso__data(dso)->fd < 0) { |
987 | dso__data(dso)->status = DSO_DATA_STATUS_ERROR; | |
ea5db1bd JO |
988 | ret = -errno; |
989 | goto out; | |
990 | } | |
991 | ||
ee756ef7 | 992 | ret = pread(dso__data(dso)->fd, data, DSO__DATA_CACHE_SIZE, offset); |
ea5db1bd | 993 | out: |
5ac22c35 | 994 | mutex_unlock(dso__data_open_lock()); |
ea5db1bd JO |
995 | return ret; |
996 | } | |
997 | ||
366df726 AH |
998 | static struct dso_cache *dso_cache__populate(struct dso *dso, |
999 | struct machine *machine, | |
1000 | u64 offset, ssize_t *ret) | |
cdd059d7 | 1001 | { |
cacddfe7 | 1002 | u64 cache_offset = offset & DSO__DATA_CACHE_MASK; |
cdd059d7 | 1003 | struct dso_cache *cache; |
8e67b725 | 1004 | struct dso_cache *old; |
cdd059d7 | 1005 | |
cacddfe7 | 1006 | cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE); |
366df726 AH |
1007 | if (!cache) { |
1008 | *ret = -ENOMEM; | |
1009 | return NULL; | |
1010 | } | |
ef0580ec | 1011 | #ifdef HAVE_LIBBPF_SUPPORT |
ee756ef7 | 1012 | if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) |
366df726 | 1013 | *ret = bpf_read(dso, cache_offset, cache->data); |
ef0580ec ACM |
1014 | else |
1015 | #endif | |
ee756ef7 | 1016 | if (dso__binary_type(dso) == DSO_BINARY_TYPE__OOL) |
789e2419 | 1017 | *ret = DSO__DATA_CACHE_SIZE; |
6c398d72 | 1018 | else |
366df726 | 1019 | *ret = file_read(dso, machine, cache_offset, cache->data); |
6c398d72 | 1020 | |
366df726 AH |
1021 | if (*ret <= 0) { |
1022 | free(cache); | |
1023 | return NULL; | |
1024 | } | |
33bdedce | 1025 | |
366df726 AH |
1026 | cache->offset = cache_offset; |
1027 | cache->size = *ret; | |
cdd059d7 | 1028 | |
366df726 AH |
1029 | old = dso_cache__insert(dso, cache); |
1030 | if (old) { | |
1031 | /* we lose the race */ | |
1032 | free(cache); | |
1033 | cache = old; | |
33bdedce | 1034 | } |
cdd059d7 | 1035 | |
366df726 AH |
1036 | return cache; |
1037 | } | |
cdd059d7 | 1038 | |
366df726 AH |
1039 | static struct dso_cache *dso_cache__find(struct dso *dso, |
1040 | struct machine *machine, | |
1041 | u64 offset, | |
1042 | ssize_t *ret) | |
1043 | { | |
1044 | struct dso_cache *cache = __dso_cache__find(dso, offset); | |
1045 | ||
1046 | return cache ? cache : dso_cache__populate(dso, machine, offset, ret); | |
cdd059d7 JO |
1047 | } |
1048 | ||
b86a9d91 AH |
1049 | static ssize_t dso_cache_io(struct dso *dso, struct machine *machine, |
1050 | u64 offset, u8 *data, ssize_t size, bool out) | |
cdd059d7 JO |
1051 | { |
1052 | struct dso_cache *cache; | |
366df726 | 1053 | ssize_t ret = 0; |
cdd059d7 | 1054 | |
366df726 AH |
1055 | cache = dso_cache__find(dso, machine, offset, &ret); |
1056 | if (!cache) | |
1057 | return ret; | |
1058 | ||
b86a9d91 | 1059 | return dso_cache__memcpy(cache, offset, data, size, out); |
cdd059d7 JO |
1060 | } |
1061 | ||
c1f9aa0a JO |
1062 | /* |
1063 | * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks | |
1064 | * in the rb_tree. Any read to already cached data is served | |
b86a9d91 | 1065 | * by cached data. Writes update the cache only, not the backing file. |
c1f9aa0a | 1066 | */ |
b86a9d91 AH |
1067 | static ssize_t cached_io(struct dso *dso, struct machine *machine, |
1068 | u64 offset, u8 *data, ssize_t size, bool out) | |
cdd059d7 JO |
1069 | { |
1070 | ssize_t r = 0; | |
1071 | u8 *p = data; | |
1072 | ||
1073 | do { | |
1074 | ssize_t ret; | |
1075 | ||
b86a9d91 | 1076 | ret = dso_cache_io(dso, machine, offset, p, size, out); |
cdd059d7 JO |
1077 | if (ret < 0) |
1078 | return ret; | |
1079 | ||
1080 | /* Reached EOF, return what we have. */ | |
1081 | if (!ret) | |
1082 | break; | |
1083 | ||
1084 | BUG_ON(ret > size); | |
1085 | ||
1086 | r += ret; | |
1087 | p += ret; | |
1088 | offset += ret; | |
1089 | size -= ret; | |
1090 | ||
1091 | } while (size); | |
1092 | ||
1093 | return r; | |
1094 | } | |
1095 | ||
5523769e | 1096 | static int file_size(struct dso *dso, struct machine *machine) |
c3fbd2a6 | 1097 | { |
33bdedce | 1098 | int ret = 0; |
c3fbd2a6 | 1099 | struct stat st; |
6e81c74c | 1100 | char sbuf[STRERR_BUFSIZE]; |
c3fbd2a6 | 1101 | |
5ac22c35 | 1102 | mutex_lock(dso__data_open_lock()); |
33bdedce NK |
1103 | |
1104 | /* | |
ee756ef7 | 1105 | * dso__data(dso)->fd might be closed if other thread opened another |
33bdedce NK |
1106 | * file (dso) due to open file limit (RLIMIT_NOFILE). |
1107 | */ | |
71ff824a NK |
1108 | try_to_open_dso(dso, machine); |
1109 | ||
ee756ef7 | 1110 | if (dso__data(dso)->fd < 0) { |
71ff824a | 1111 | ret = -errno; |
ee756ef7 | 1112 | dso__data(dso)->status = DSO_DATA_STATUS_ERROR; |
71ff824a | 1113 | goto out; |
c3fbd2a6 JO |
1114 | } |
1115 | ||
ee756ef7 | 1116 | if (fstat(dso__data(dso)->fd, &st) < 0) { |
33bdedce NK |
1117 | ret = -errno; |
1118 | pr_err("dso cache fstat failed: %s\n", | |
c8b5f2c9 | 1119 | str_error_r(errno, sbuf, sizeof(sbuf))); |
ee756ef7 | 1120 | dso__data(dso)->status = DSO_DATA_STATUS_ERROR; |
33bdedce NK |
1121 | goto out; |
1122 | } | |
ee756ef7 | 1123 | dso__data(dso)->file_size = st.st_size; |
33bdedce NK |
1124 | |
1125 | out: | |
5ac22c35 | 1126 | mutex_unlock(dso__data_open_lock()); |
33bdedce | 1127 | return ret; |
c3fbd2a6 JO |
1128 | } |
1129 | ||
5523769e JO |
1130 | int dso__data_file_size(struct dso *dso, struct machine *machine) |
1131 | { | |
ee756ef7 | 1132 | if (dso__data(dso)->file_size) |
5523769e JO |
1133 | return 0; |
1134 | ||
ee756ef7 | 1135 | if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR) |
5523769e | 1136 | return -1; |
ef0580ec | 1137 | #ifdef HAVE_LIBBPF_SUPPORT |
ee756ef7 | 1138 | if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) |
6c398d72 | 1139 | return bpf_size(dso); |
ef0580ec | 1140 | #endif |
5523769e JO |
1141 | return file_size(dso, machine); |
1142 | } | |
1143 | ||
6d363459 AH |
1144 | /** |
1145 | * dso__data_size - Return dso data size | |
1146 | * @dso: dso object | |
1147 | * @machine: machine object | |
1148 | * | |
1149 | * Return: dso data size | |
1150 | */ | |
1151 | off_t dso__data_size(struct dso *dso, struct machine *machine) | |
1152 | { | |
b5c2161c | 1153 | if (dso__data_file_size(dso, machine)) |
6d363459 AH |
1154 | return -1; |
1155 | ||
1156 | /* For now just estimate dso data size is close to file size */ | |
ee756ef7 | 1157 | return dso__data(dso)->file_size; |
6d363459 AH |
1158 | } |
1159 | ||
b86a9d91 AH |
1160 | static ssize_t data_read_write_offset(struct dso *dso, struct machine *machine, |
1161 | u64 offset, u8 *data, ssize_t size, | |
1162 | bool out) | |
c3fbd2a6 | 1163 | { |
b5c2161c | 1164 | if (dso__data_file_size(dso, machine)) |
c3fbd2a6 JO |
1165 | return -1; |
1166 | ||
1167 | /* Check the offset sanity. */ | |
ee756ef7 | 1168 | if (offset > dso__data(dso)->file_size) |
c3fbd2a6 JO |
1169 | return -1; |
1170 | ||
1171 | if (offset + size < offset) | |
1172 | return -1; | |
1173 | ||
b86a9d91 | 1174 | return cached_io(dso, machine, offset, data, size, out); |
c3fbd2a6 JO |
1175 | } |
1176 | ||
c1f9aa0a JO |
1177 | /** |
1178 | * dso__data_read_offset - Read data from dso file offset | |
1179 | * @dso: dso object | |
1180 | * @machine: machine object | |
1181 | * @offset: file offset | |
1182 | * @data: buffer to store data | |
1183 | * @size: size of the @data buffer | |
1184 | * | |
1185 | * External interface to read data from dso file offset. Open | |
1186 | * dso data file and use cached_read to get the data. | |
1187 | */ | |
c3fbd2a6 JO |
1188 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, |
1189 | u64 offset, u8 *data, ssize_t size) | |
1190 | { | |
ee756ef7 | 1191 | if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR) |
c3fbd2a6 JO |
1192 | return -1; |
1193 | ||
b86a9d91 | 1194 | return data_read_write_offset(dso, machine, offset, data, size, true); |
c3fbd2a6 JO |
1195 | } |
1196 | ||
afffec6f IR |
1197 | uint16_t dso__e_machine(struct dso *dso, struct machine *machine) |
1198 | { | |
1199 | uint16_t e_machine = EM_NONE; | |
1200 | int fd; | |
1201 | ||
1202 | switch (dso__binary_type(dso)) { | |
1203 | case DSO_BINARY_TYPE__KALLSYMS: | |
1204 | case DSO_BINARY_TYPE__GUEST_KALLSYMS: | |
1205 | case DSO_BINARY_TYPE__VMLINUX: | |
1206 | case DSO_BINARY_TYPE__GUEST_VMLINUX: | |
1207 | case DSO_BINARY_TYPE__GUEST_KMODULE: | |
1208 | case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: | |
1209 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: | |
1210 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: | |
1211 | case DSO_BINARY_TYPE__KCORE: | |
1212 | case DSO_BINARY_TYPE__GUEST_KCORE: | |
1213 | case DSO_BINARY_TYPE__BPF_PROG_INFO: | |
1214 | case DSO_BINARY_TYPE__BPF_IMAGE: | |
1215 | case DSO_BINARY_TYPE__OOL: | |
1216 | case DSO_BINARY_TYPE__JAVA_JIT: | |
1217 | return EM_HOST; | |
1218 | case DSO_BINARY_TYPE__DEBUGLINK: | |
1219 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: | |
1220 | case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: | |
1221 | case DSO_BINARY_TYPE__GNU_DEBUGDATA: | |
1222 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: | |
1223 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: | |
1224 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: | |
1225 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: | |
1226 | case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO: | |
1227 | case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: | |
1228 | break; | |
1229 | case DSO_BINARY_TYPE__NOT_FOUND: | |
1230 | default: | |
1231 | return EM_NONE; | |
1232 | } | |
1233 | ||
1234 | mutex_lock(dso__data_open_lock()); | |
1235 | ||
1236 | /* | |
1237 | * dso__data(dso)->fd might be closed if other thread opened another | |
1238 | * file (dso) due to open file limit (RLIMIT_NOFILE). | |
1239 | */ | |
1240 | try_to_open_dso(dso, machine); | |
1241 | fd = dso__data(dso)->fd; | |
1242 | if (fd >= 0) { | |
1243 | _Static_assert(offsetof(Elf32_Ehdr, e_machine) == 18, "Unexpected offset"); | |
1244 | _Static_assert(offsetof(Elf64_Ehdr, e_machine) == 18, "Unexpected offset"); | |
1245 | if (dso__needs_swap(dso) == DSO_SWAP__UNSET) { | |
1246 | unsigned char eidata; | |
1247 | ||
1248 | if (pread(fd, &eidata, sizeof(eidata), EI_DATA) == sizeof(eidata)) | |
1249 | dso__swap_init(dso, eidata); | |
1250 | } | |
1251 | if (dso__needs_swap(dso) != DSO_SWAP__UNSET && | |
1252 | pread(fd, &e_machine, sizeof(e_machine), 18) == sizeof(e_machine)) | |
1253 | e_machine = DSO__SWAP(dso, uint16_t, e_machine); | |
1254 | } | |
1255 | mutex_unlock(dso__data_open_lock()); | |
1256 | return e_machine; | |
1257 | } | |
1258 | ||
c1f9aa0a JO |
1259 | /** |
1260 | * dso__data_read_addr - Read data from dso address | |
1261 | * @dso: dso object | |
1262 | * @machine: machine object | |
1263 | * @add: virtual memory address | |
1264 | * @data: buffer to store data | |
1265 | * @size: size of the @data buffer | |
1266 | * | |
1267 | * External interface to read data from dso address. | |
1268 | */ | |
cdd059d7 JO |
1269 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, |
1270 | struct machine *machine, u64 addr, | |
1271 | u8 *data, ssize_t size) | |
1272 | { | |
78a1f7cd IR |
1273 | u64 offset = map__map_ip(map, addr); |
1274 | ||
cdd059d7 JO |
1275 | return dso__data_read_offset(dso, machine, offset, data, size); |
1276 | } | |
1277 | ||
b86a9d91 AH |
1278 | /** |
1279 | * dso__data_write_cache_offs - Write data to dso data cache at file offset | |
1280 | * @dso: dso object | |
1281 | * @machine: machine object | |
1282 | * @offset: file offset | |
1283 | * @data: buffer to write | |
1284 | * @size: size of the @data buffer | |
1285 | * | |
1286 | * Write into the dso file data cache, but do not change the file itself. | |
1287 | */ | |
1288 | ssize_t dso__data_write_cache_offs(struct dso *dso, struct machine *machine, | |
1289 | u64 offset, const u8 *data_in, ssize_t size) | |
1290 | { | |
1291 | u8 *data = (u8 *)data_in; /* cast away const to use same fns for r/w */ | |
1292 | ||
ee756ef7 | 1293 | if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR) |
b86a9d91 AH |
1294 | return -1; |
1295 | ||
1296 | return data_read_write_offset(dso, machine, offset, data, size, false); | |
1297 | } | |
1298 | ||
1299 | /** | |
1300 | * dso__data_write_cache_addr - Write data to dso data cache at dso address | |
1301 | * @dso: dso object | |
1302 | * @machine: machine object | |
1303 | * @add: virtual memory address | |
1304 | * @data: buffer to write | |
1305 | * @size: size of the @data buffer | |
1306 | * | |
1307 | * External interface to write into the dso file data cache, but do not change | |
1308 | * the file itself. | |
1309 | */ | |
1310 | ssize_t dso__data_write_cache_addr(struct dso *dso, struct map *map, | |
1311 | struct machine *machine, u64 addr, | |
1312 | const u8 *data, ssize_t size) | |
1313 | { | |
78a1f7cd IR |
1314 | u64 offset = map__map_ip(map, addr); |
1315 | ||
b86a9d91 AH |
1316 | return dso__data_write_cache_offs(dso, machine, offset, data, size); |
1317 | } | |
1318 | ||
cdd059d7 JO |
1319 | struct map *dso__new_map(const char *name) |
1320 | { | |
1321 | struct map *map = NULL; | |
1322 | struct dso *dso = dso__new(name); | |
1323 | ||
581e295a | 1324 | if (dso) { |
3183f8ca | 1325 | map = map__new2(0, dso); |
581e295a RM |
1326 | dso__put(dso); |
1327 | } | |
cdd059d7 JO |
1328 | |
1329 | return map; | |
1330 | } | |
1331 | ||
459ce518 ACM |
1332 | struct dso *machine__findnew_kernel(struct machine *machine, const char *name, |
1333 | const char *short_name, int dso_type) | |
cdd059d7 JO |
1334 | { |
1335 | /* | |
1336 | * The kernel dso could be created by build_id processing. | |
1337 | */ | |
aa7cc2ae | 1338 | struct dso *dso = machine__findnew_dso(machine, name); |
cdd059d7 JO |
1339 | |
1340 | /* | |
1341 | * We need to run this in all cases, since during the build_id | |
1342 | * processing we had no idea this was the kernel dso. | |
1343 | */ | |
1344 | if (dso != NULL) { | |
58a98c9c | 1345 | dso__set_short_name(dso, short_name, false); |
ee756ef7 | 1346 | dso__set_kernel(dso, dso_type); |
cdd059d7 JO |
1347 | } |
1348 | ||
1349 | return dso; | |
1350 | } | |
1351 | ||
ab2c742d IR |
1352 | static void __dso__set_long_name_id(struct dso *dso, const char *name, bool name_allocated) |
1353 | { | |
1354 | if (dso__long_name_allocated(dso)) | |
1355 | free((char *)dso__long_name(dso)); | |
1356 | ||
1357 | RC_CHK_ACCESS(dso)->long_name = name; | |
1358 | RC_CHK_ACCESS(dso)->long_name_len = strlen(name); | |
1359 | dso__set_long_name_allocated(dso, name_allocated); | |
1360 | } | |
1361 | ||
3f4ac23a | 1362 | static void dso__set_long_name_id(struct dso *dso, const char *name, bool name_allocated) |
cdd059d7 | 1363 | { |
ee756ef7 | 1364 | struct dsos *dsos = dso__dsos(dso); |
e266a753 | 1365 | |
cdd059d7 JO |
1366 | if (name == NULL) |
1367 | return; | |
7e155d4d | 1368 | |
3f4ac23a | 1369 | if (dsos) { |
e266a753 | 1370 | /* |
3f4ac23a IR |
1371 | * Need to avoid re-sorting the dsos breaking by non-atomically |
1372 | * renaming the dso. | |
e266a753 | 1373 | */ |
3f4ac23a | 1374 | down_write(&dsos->lock); |
ab2c742d | 1375 | __dso__set_long_name_id(dso, name, name_allocated); |
3f4ac23a IR |
1376 | dsos->sorted = false; |
1377 | up_write(&dsos->lock); | |
ab2c742d IR |
1378 | } else { |
1379 | __dso__set_long_name_id(dso, name, name_allocated); | |
3f4ac23a | 1380 | } |
0e3149f8 ACM |
1381 | } |
1382 | ||
3f4ac23a | 1383 | static int __dso_id__cmp(const struct dso_id *a, const struct dso_id *b) |
1d6eff93 IR |
1384 | { |
1385 | if (a->maj > b->maj) return -1; | |
1386 | if (a->maj < b->maj) return 1; | |
1387 | ||
1388 | if (a->min > b->min) return -1; | |
1389 | if (a->min < b->min) return 1; | |
1390 | ||
1391 | if (a->ino > b->ino) return -1; | |
1392 | if (a->ino < b->ino) return 1; | |
1393 | ||
1394 | /* | |
1395 | * Synthesized MMAP events have zero ino_generation, avoid comparing | |
1396 | * them with MMAP events with actual ino_generation. | |
1397 | * | |
1398 | * I found it harmful because the mismatch resulted in a new | |
1399 | * dso that did not have a build ID whereas the original dso did have a | |
1400 | * build ID. The build ID was essential because the object was not found | |
1401 | * otherwise. - Adrian | |
1402 | */ | |
1403 | if (a->ino_generation && b->ino_generation) { | |
1404 | if (a->ino_generation > b->ino_generation) return -1; | |
1405 | if (a->ino_generation < b->ino_generation) return 1; | |
1406 | } | |
1407 | ||
1408 | return 0; | |
1409 | } | |
1410 | ||
3f4ac23a | 1411 | bool dso_id__empty(const struct dso_id *id) |
1d6eff93 IR |
1412 | { |
1413 | if (!id) | |
1414 | return true; | |
1415 | ||
1416 | return !id->maj && !id->min && !id->ino && !id->ino_generation; | |
1417 | } | |
1418 | ||
e4bb4caa | 1419 | void __dso__inject_id(struct dso *dso, const struct dso_id *id) |
1d6eff93 | 1420 | { |
ee756ef7 IR |
1421 | struct dsos *dsos = dso__dsos(dso); |
1422 | struct dso_id *dso_id = dso__id(dso); | |
3f4ac23a IR |
1423 | |
1424 | /* dsos write lock held by caller. */ | |
1425 | ||
ee756ef7 IR |
1426 | dso_id->maj = id->maj; |
1427 | dso_id->min = id->min; | |
1428 | dso_id->ino = id->ino; | |
1429 | dso_id->ino_generation = id->ino_generation; | |
3f4ac23a IR |
1430 | |
1431 | if (dsos) | |
1432 | dsos->sorted = false; | |
1d6eff93 IR |
1433 | } |
1434 | ||
3f4ac23a | 1435 | int dso_id__cmp(const struct dso_id *a, const struct dso_id *b) |
1d6eff93 IR |
1436 | { |
1437 | /* | |
1438 | * The second is always dso->id, so zeroes if not set, assume passing | |
1439 | * NULL for a means a zeroed id | |
1440 | */ | |
1441 | if (dso_id__empty(a) || dso_id__empty(b)) | |
1442 | return 0; | |
1443 | ||
1444 | return __dso_id__cmp(a, b); | |
1445 | } | |
1446 | ||
1447 | int dso__cmp_id(struct dso *a, struct dso *b) | |
1448 | { | |
ee756ef7 | 1449 | return __dso_id__cmp(dso__id(a), dso__id(b)); |
1d6eff93 IR |
1450 | } |
1451 | ||
0e3149f8 ACM |
1452 | void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) |
1453 | { | |
3f4ac23a | 1454 | dso__set_long_name_id(dso, name, name_allocated); |
cdd059d7 JO |
1455 | } |
1456 | ||
ab2c742d IR |
1457 | static void __dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) |
1458 | { | |
1459 | if (dso__short_name_allocated(dso)) | |
1460 | free((char *)dso__short_name(dso)); | |
1461 | ||
1462 | RC_CHK_ACCESS(dso)->short_name = name; | |
1463 | RC_CHK_ACCESS(dso)->short_name_len = strlen(name); | |
1464 | dso__set_short_name_allocated(dso, name_allocated); | |
1465 | } | |
1466 | ||
58a98c9c | 1467 | void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) |
cdd059d7 | 1468 | { |
ee756ef7 | 1469 | struct dsos *dsos = dso__dsos(dso); |
3f4ac23a | 1470 | |
cdd059d7 JO |
1471 | if (name == NULL) |
1472 | return; | |
58a98c9c | 1473 | |
3f4ac23a IR |
1474 | if (dsos) { |
1475 | /* | |
1476 | * Need to avoid re-sorting the dsos breaking by non-atomically | |
1477 | * renaming the dso. | |
1478 | */ | |
1479 | down_write(&dsos->lock); | |
ab2c742d | 1480 | __dso__set_short_name(dso, name, name_allocated); |
3f4ac23a IR |
1481 | dsos->sorted = false; |
1482 | up_write(&dsos->lock); | |
ab2c742d IR |
1483 | } else { |
1484 | __dso__set_short_name(dso, name, name_allocated); | |
3f4ac23a | 1485 | } |
cdd059d7 JO |
1486 | } |
1487 | ||
cdd059d7 JO |
1488 | int dso__name_len(const struct dso *dso) |
1489 | { | |
1490 | if (!dso) | |
1491 | return strlen("[unknown]"); | |
bb963e16 | 1492 | if (verbose > 0) |
ee756ef7 | 1493 | return dso__long_name_len(dso); |
cdd059d7 | 1494 | |
ee756ef7 | 1495 | return dso__short_name_len(dso); |
cdd059d7 JO |
1496 | } |
1497 | ||
3183f8ca | 1498 | bool dso__loaded(const struct dso *dso) |
cdd059d7 | 1499 | { |
ee756ef7 | 1500 | return RC_CHK_ACCESS(dso)->loaded; |
cdd059d7 JO |
1501 | } |
1502 | ||
3183f8ca | 1503 | bool dso__sorted_by_name(const struct dso *dso) |
cdd059d7 | 1504 | { |
ee756ef7 | 1505 | return RC_CHK_ACCESS(dso)->sorted_by_name; |
cdd059d7 JO |
1506 | } |
1507 | ||
3183f8ca | 1508 | void dso__set_sorted_by_name(struct dso *dso) |
cdd059d7 | 1509 | { |
ee756ef7 | 1510 | RC_CHK_ACCESS(dso)->sorted_by_name = true; |
cdd059d7 JO |
1511 | } |
1512 | ||
e4bb4caa | 1513 | struct dso *dso__new_id(const char *name, const struct dso_id *id) |
cdd059d7 | 1514 | { |
ee756ef7 IR |
1515 | RC_STRUCT(dso) *dso = zalloc(sizeof(*dso) + strlen(name) + 1); |
1516 | struct dso *res; | |
1517 | struct dso_data *data; | |
cdd059d7 | 1518 | |
ee756ef7 IR |
1519 | if (!dso) |
1520 | return NULL; | |
1521 | ||
1522 | if (ADD_RC_CHK(res, dso)) { | |
cdd059d7 | 1523 | strcpy(dso->name, name); |
0e3149f8 ACM |
1524 | if (id) |
1525 | dso->id = *id; | |
ee756ef7 IR |
1526 | dso__set_long_name_id(res, dso->name, false); |
1527 | dso__set_short_name(res, dso->name, false); | |
259dce91 IR |
1528 | dso->symbols = RB_ROOT_CACHED; |
1529 | dso->symbol_names = NULL; | |
1530 | dso->symbol_names_len = 0; | |
55ecd631 DB |
1531 | dso->inlined_nodes = RB_ROOT_CACHED; |
1532 | dso->srclines = RB_ROOT_CACHED; | |
fc044c53 | 1533 | dso->data_types = RB_ROOT; |
55ee3d00 | 1534 | dso->global_vars = RB_ROOT; |
53fa8eaa | 1535 | dso->data.fd = -1; |
c27697d6 | 1536 | dso->data.status = DSO_DATA_STATUS_UNKNOWN; |
cdd059d7 | 1537 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; |
5f70619d | 1538 | dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; |
c6d8f2a4 | 1539 | dso->is_64_bit = (sizeof(void *) == 8); |
cdd059d7 | 1540 | dso->loaded = 0; |
0131c4ec | 1541 | dso->rel = 0; |
cdd059d7 JO |
1542 | dso->sorted_by_name = 0; |
1543 | dso->has_build_id = 0; | |
2cc9d0ef | 1544 | dso->has_srcline = 1; |
906049c8 | 1545 | dso->a2l_fails = 1; |
1c695c88 | 1546 | dso->kernel = DSO_SPACE__USER; |
6be5d828 | 1547 | dso->is_kmod = 0; |
cdd059d7 | 1548 | dso->needs_swap = DSO_SWAP__UNSET; |
2af52475 | 1549 | dso->comp = COMP_ID__NONE; |
d9a0d6b8 | 1550 | mutex_init(&dso->lock); |
7100810a | 1551 | refcount_set(&dso->refcnt, 1); |
ee756ef7 IR |
1552 | data = &dso->data; |
1553 | data->cache = RB_ROOT; | |
1554 | data->fd = -1; | |
1555 | data->status = DSO_DATA_STATUS_UNKNOWN; | |
1556 | INIT_LIST_HEAD(&data->open_entry); | |
37862d6f | 1557 | #ifdef REFCNT_CHECKING |
ee756ef7 | 1558 | data->dso = NULL; /* Set when on the open_entry list. */ |
37862d6f | 1559 | #endif |
cdd059d7 | 1560 | } |
ee756ef7 | 1561 | return res; |
cdd059d7 JO |
1562 | } |
1563 | ||
0e3149f8 ACM |
1564 | struct dso *dso__new(const char *name) |
1565 | { | |
1566 | return dso__new_id(name, NULL); | |
1567 | } | |
1568 | ||
cdd059d7 JO |
1569 | void dso__delete(struct dso *dso) |
1570 | { | |
ee756ef7 IR |
1571 | if (dso__dsos(dso)) |
1572 | pr_err("DSO %s is still in rbtree when being deleted!\n", dso__long_name(dso)); | |
11ea2515 MW |
1573 | |
1574 | /* free inlines first, as they reference symbols */ | |
ee756ef7 IR |
1575 | inlines__tree_delete(&RC_CHK_ACCESS(dso)->inlined_nodes); |
1576 | srcline__tree_delete(&RC_CHK_ACCESS(dso)->srclines); | |
1577 | symbols__delete(&RC_CHK_ACCESS(dso)->symbols); | |
1578 | RC_CHK_ACCESS(dso)->symbol_names_len = 0; | |
1579 | zfree(&RC_CHK_ACCESS(dso)->symbol_names); | |
1580 | annotated_data_type__tree_delete(dso__data_types(dso)); | |
1581 | global_var_type__tree_delete(dso__global_vars(dso)); | |
1582 | ||
1583 | if (RC_CHK_ACCESS(dso)->short_name_allocated) { | |
1584 | zfree((char **)&RC_CHK_ACCESS(dso)->short_name); | |
1585 | RC_CHK_ACCESS(dso)->short_name_allocated = false; | |
ee021d42 ACM |
1586 | } |
1587 | ||
ee756ef7 IR |
1588 | if (RC_CHK_ACCESS(dso)->long_name_allocated) { |
1589 | zfree((char **)&RC_CHK_ACCESS(dso)->long_name); | |
1590 | RC_CHK_ACCESS(dso)->long_name_allocated = false; | |
ee021d42 ACM |
1591 | } |
1592 | ||
53fa8eaa | 1593 | dso__data_close(dso); |
ee756ef7 | 1594 | auxtrace_cache__free(RC_CHK_ACCESS(dso)->auxtrace_cache); |
8e67b725 | 1595 | dso_cache__free(dso); |
454ff00f | 1596 | dso__free_a2l(dso); |
92717bc0 | 1597 | dso__free_symsrc_filename(dso); |
ee756ef7 IR |
1598 | nsinfo__zput(RC_CHK_ACCESS(dso)->nsinfo); |
1599 | mutex_destroy(dso__lock(dso)); | |
1600 | RC_CHK_FREE(dso); | |
cdd059d7 JO |
1601 | } |
1602 | ||
d3a7c489 ACM |
1603 | struct dso *dso__get(struct dso *dso) |
1604 | { | |
ee756ef7 IR |
1605 | struct dso *result; |
1606 | ||
1607 | if (RC_CHK_GET(result, dso)) | |
1608 | refcount_inc(&RC_CHK_ACCESS(dso)->refcnt); | |
1609 | ||
1610 | return result; | |
d3a7c489 ACM |
1611 | } |
1612 | ||
1613 | void dso__put(struct dso *dso) | |
1614 | { | |
ee756ef7 | 1615 | if (dso && refcount_dec_and_test(&RC_CHK_ACCESS(dso)->refcnt)) |
d3a7c489 | 1616 | dso__delete(dso); |
ee756ef7 IR |
1617 | else |
1618 | RC_CHK_PUT(dso); | |
d3a7c489 ACM |
1619 | } |
1620 | ||
afffec6f IR |
1621 | int dso__swap_init(struct dso *dso, unsigned char eidata) |
1622 | { | |
1623 | static unsigned int const endian = 1; | |
1624 | ||
1625 | dso__set_needs_swap(dso, DSO_SWAP__NO); | |
1626 | ||
1627 | switch (eidata) { | |
1628 | case ELFDATA2LSB: | |
1629 | /* We are big endian, DSO is little endian. */ | |
1630 | if (*(unsigned char const *)&endian != 1) | |
1631 | dso__set_needs_swap(dso, DSO_SWAP__YES); | |
1632 | break; | |
1633 | ||
1634 | case ELFDATA2MSB: | |
1635 | /* We are little endian, DSO is big endian. */ | |
1636 | if (*(unsigned char const *)&endian != 0) | |
1637 | dso__set_needs_swap(dso, DSO_SWAP__YES); | |
1638 | break; | |
1639 | ||
1640 | default: | |
1641 | pr_err("unrecognized DSO data encoding %d\n", eidata); | |
1642 | return -EINVAL; | |
1643 | } | |
1644 | ||
1645 | return 0; | |
1646 | } | |
1647 | ||
8dfdf440 | 1648 | void dso__set_build_id(struct dso *dso, struct build_id *bid) |
cdd059d7 | 1649 | { |
ee756ef7 IR |
1650 | RC_CHK_ACCESS(dso)->bid = *bid; |
1651 | RC_CHK_ACCESS(dso)->has_build_id = 1; | |
cdd059d7 JO |
1652 | } |
1653 | ||
39be8d01 | 1654 | bool dso__build_id_equal(const struct dso *dso, struct build_id *bid) |
cdd059d7 | 1655 | { |
ee756ef7 IR |
1656 | const struct build_id *dso_bid = dso__bid_const(dso); |
1657 | ||
1658 | if (dso_bid->size > bid->size && dso_bid->size == BUILD_ID_SIZE) { | |
4a86d414 NK |
1659 | /* |
1660 | * For the backward compatibility, it allows a build-id has | |
1661 | * trailing zeros. | |
1662 | */ | |
ee756ef7 IR |
1663 | return !memcmp(dso_bid->data, bid->data, bid->size) && |
1664 | !memchr_inv(&dso_bid->data[bid->size], 0, | |
1665 | dso_bid->size - bid->size); | |
4a86d414 NK |
1666 | } |
1667 | ||
ee756ef7 IR |
1668 | return dso_bid->size == bid->size && |
1669 | memcmp(dso_bid->data, bid->data, dso_bid->size) == 0; | |
cdd059d7 JO |
1670 | } |
1671 | ||
1672 | void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) | |
1673 | { | |
1674 | char path[PATH_MAX]; | |
1675 | ||
1676 | if (machine__is_default_guest(machine)) | |
1677 | return; | |
1678 | sprintf(path, "%s/sys/kernel/notes", machine->root_dir); | |
ee756ef7 IR |
1679 | if (sysfs__read_build_id(path, dso__bid(dso)) == 0) |
1680 | dso__set_has_build_id(dso); | |
cdd059d7 JO |
1681 | } |
1682 | ||
1683 | int dso__kernel_module_get_build_id(struct dso *dso, | |
1684 | const char *root_dir) | |
1685 | { | |
1686 | char filename[PATH_MAX]; | |
1687 | /* | |
1688 | * kernel module short names are of the form "[module]" and | |
1689 | * we need just "module" here. | |
1690 | */ | |
ee756ef7 | 1691 | const char *name = dso__short_name(dso) + 1; |
cdd059d7 JO |
1692 | |
1693 | snprintf(filename, sizeof(filename), | |
1694 | "%s/sys/module/%.*s/notes/.note.gnu.build-id", | |
1695 | root_dir, (int)strlen(name) - 1, name); | |
1696 | ||
ee756ef7 IR |
1697 | if (sysfs__read_build_id(filename, dso__bid(dso)) == 0) |
1698 | dso__set_has_build_id(dso); | |
cdd059d7 JO |
1699 | |
1700 | return 0; | |
1701 | } | |
1702 | ||
e9ad9438 | 1703 | static size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) |
cdd059d7 | 1704 | { |
b5d8bbe8 | 1705 | char sbuild_id[SBUILD_ID_SIZE]; |
cdd059d7 | 1706 | |
ee756ef7 | 1707 | build_id__sprintf(dso__bid(dso), sbuild_id); |
cdd059d7 JO |
1708 | return fprintf(fp, "%s", sbuild_id); |
1709 | } | |
1710 | ||
3183f8ca | 1711 | size_t dso__fprintf(struct dso *dso, FILE *fp) |
cdd059d7 JO |
1712 | { |
1713 | struct rb_node *nd; | |
ee756ef7 | 1714 | size_t ret = fprintf(fp, "dso: %s (", dso__short_name(dso)); |
cdd059d7 | 1715 | |
ee756ef7 IR |
1716 | if (dso__short_name(dso) != dso__long_name(dso)) |
1717 | ret += fprintf(fp, "%s, ", dso__long_name(dso)); | |
3183f8ca | 1718 | ret += fprintf(fp, "%sloaded, ", dso__loaded(dso) ? "" : "NOT "); |
cdd059d7 JO |
1719 | ret += dso__fprintf_buildid(dso, fp); |
1720 | ret += fprintf(fp, ")\n"); | |
ee756ef7 | 1721 | for (nd = rb_first_cached(dso__symbols(dso)); nd; nd = rb_next(nd)) { |
cdd059d7 JO |
1722 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); |
1723 | ret += symbol__fprintf(pos, fp); | |
1724 | } | |
1725 | ||
1726 | return ret; | |
1727 | } | |
2b5b8bb2 AH |
1728 | |
1729 | enum dso_type dso__type(struct dso *dso, struct machine *machine) | |
1730 | { | |
5ac22c35 | 1731 | int fd = -1; |
4bb11d01 | 1732 | enum dso_type type = DSO__TYPE_UNKNOWN; |
2b5b8bb2 | 1733 | |
5ac22c35 | 1734 | if (dso__data_get_fd(dso, machine, &fd)) { |
4bb11d01 NK |
1735 | type = dso__type_fd(fd); |
1736 | dso__data_put_fd(dso); | |
1737 | } | |
2b5b8bb2 | 1738 | |
4bb11d01 | 1739 | return type; |
2b5b8bb2 | 1740 | } |
18425f13 ACM |
1741 | |
1742 | int dso__strerror_load(struct dso *dso, char *buf, size_t buflen) | |
1743 | { | |
ee756ef7 | 1744 | int idx, errnum = *dso__load_errno(dso); |
18425f13 ACM |
1745 | /* |
1746 | * This must have a same ordering as the enum dso_load_errno. | |
1747 | */ | |
1748 | static const char *dso_load__error_str[] = { | |
1749 | "Internal tools/perf/ library error", | |
1750 | "Invalid ELF file", | |
1751 | "Can not read build id", | |
1752 | "Mismatching build id", | |
1753 | "Decompression failure", | |
1754 | }; | |
1755 | ||
1756 | BUG_ON(buflen == 0); | |
1757 | ||
1758 | if (errnum >= 0) { | |
c8b5f2c9 | 1759 | const char *err = str_error_r(errnum, buf, buflen); |
18425f13 ACM |
1760 | |
1761 | if (err != buf) | |
1762 | scnprintf(buf, buflen, "%s", err); | |
1763 | ||
1764 | return 0; | |
1765 | } | |
1766 | ||
1767 | if (errnum < __DSO_LOAD_ERRNO__START || errnum >= __DSO_LOAD_ERRNO__END) | |
1768 | return -1; | |
1769 | ||
1770 | idx = errnum - __DSO_LOAD_ERRNO__START; | |
1771 | scnprintf(buf, buflen, "%s", dso_load__error_str[idx]); | |
1772 | return 0; | |
1773 | } | |
b0979f00 AR |
1774 | |
1775 | bool perf_pid_map_tid(const char *dso_name, int *tid) | |
1776 | { | |
1777 | return sscanf(dso_name, "/tmp/perf-%d.map", tid) == 1; | |
1778 | } | |
1779 | ||
1780 | bool is_perf_pid_map_name(const char *dso_name) | |
1781 | { | |
1782 | int tid; | |
1783 | ||
1784 | return perf_pid_map_tid(dso_name, &tid); | |
1785 | } |