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