| 1 | |
| 2 | #include <asm/bug.h>
|
| 3 | #include <linux/kernel.h>
|
| 4 | #include <linux/string.h>
|
| 5 | #include <linux/zalloc.h>
|
| 6 | #include <sys/time.h>
|
| 7 | #include <sys/resource.h>
|
| 8 | #include <sys/types.h>
|
| 9 | #include <sys/stat.h>
|
| 10 | #include <unistd.h>
|
| 11 | #include <errno.h>
|
| 12 | #include <fcntl.h>
|
| 13 | #include <stdlib.h>
|
| 14 | #ifdef HAVE_LIBBPF_SUPPORT
|
| 15 | #include <bpf/libbpf.h>
|
| 16 | #include "bpf-event.h"
|
| 17 | #include "bpf-utils.h"
|
| 18 | #endif
|
| 19 | #include "compress.h"
|
| 20 | #include "env.h"
|
| 21 | #include "namespaces.h"
|
| 22 | #include "path.h"
|
| 23 | #include "map.h"
|
| 24 | #include "symbol.h"
|
| 25 | #include "srcline.h"
|
| 26 | #include "dso.h"
|
| 27 | #include "dsos.h"
|
| 28 | #include "machine.h"
|
| 29 | #include "auxtrace.h"
|
| 30 | #include "util.h"
|
| 31 | #include "debug.h"
|
| 32 | #include "string2.h"
|
| 33 | #include "vdso.h"
|
| 34 | #include "annotate-data.h"
|
| 35 | #include "libdw.h"
|
| 36 |
|
| 37 | static const char * const debuglink_paths[] = {
|
| 38 | "%.0s%s",
|
| 39 | "%s/%s",
|
| 40 | "%s/.debug/%s",
|
| 41 | "/usr/lib/debug%s/%s"
|
| 42 | };
|
| 43 |
|
| 44 | void dso__set_nsinfo(struct dso *dso, struct nsinfo *nsi)
|
| 45 | {
|
| 46 | nsinfo__put(RC_CHK_ACCESS(dso)->nsinfo);
|
| 47 | RC_CHK_ACCESS(dso)->nsinfo = nsi;
|
| 48 | }
|
| 49 |
|
| 50 | char dso__symtab_origin(const struct dso *dso)
|
| 51 | {
|
| 52 | static const char origin[] = {
|
| 53 | [DSO_BINARY_TYPE__KALLSYMS] = 'k',
|
| 54 | [DSO_BINARY_TYPE__VMLINUX] = 'v',
|
| 55 | [DSO_BINARY_TYPE__JAVA_JIT] = 'j',
|
| 56 | [DSO_BINARY_TYPE__DEBUGLINK] = 'l',
|
| 57 | [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
|
| 58 | [DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO] = 'D',
|
| 59 | [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
|
| 60 | [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
|
| 61 | [DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO] = 'x',
|
| 62 | [DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO] = 'o',
|
| 63 | [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
|
| 64 | [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
|
| 65 | [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
|
| 66 | [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP] = 'm',
|
| 67 | [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
|
| 68 | [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
|
| 69 | [DSO_BINARY_TYPE__GUEST_KMODULE_COMP] = 'M',
|
| 70 | [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
|
| 71 | [DSO_BINARY_TYPE__GNU_DEBUGDATA] = 'n',
|
| 72 | };
|
| 73 |
|
| 74 | if (dso == NULL || dso__symtab_type(dso) == DSO_BINARY_TYPE__NOT_FOUND)
|
| 75 | return '!';
|
| 76 | return origin[dso__symtab_type(dso)];
|
| 77 | }
|
| 78 |
|
| 79 | bool dso__is_object_file(const struct dso *dso)
|
| 80 | {
|
| 81 | switch (dso__binary_type(dso)) {
|
| 82 | case DSO_BINARY_TYPE__KALLSYMS:
|
| 83 | case DSO_BINARY_TYPE__GUEST_KALLSYMS:
|
| 84 | case DSO_BINARY_TYPE__JAVA_JIT:
|
| 85 | case DSO_BINARY_TYPE__BPF_PROG_INFO:
|
| 86 | case DSO_BINARY_TYPE__BPF_IMAGE:
|
| 87 | case DSO_BINARY_TYPE__OOL:
|
| 88 | return false;
|
| 89 | case DSO_BINARY_TYPE__VMLINUX:
|
| 90 | case DSO_BINARY_TYPE__GUEST_VMLINUX:
|
| 91 | case DSO_BINARY_TYPE__DEBUGLINK:
|
| 92 | case DSO_BINARY_TYPE__BUILD_ID_CACHE:
|
| 93 | case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
|
| 94 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
|
| 95 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
|
| 96 | case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO:
|
| 97 | case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
|
| 98 | case DSO_BINARY_TYPE__GNU_DEBUGDATA:
|
| 99 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
|
| 100 | case DSO_BINARY_TYPE__GUEST_KMODULE:
|
| 101 | case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
|
| 102 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
|
| 103 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
|
| 104 | case DSO_BINARY_TYPE__KCORE:
|
| 105 | case DSO_BINARY_TYPE__GUEST_KCORE:
|
| 106 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
|
| 107 | case DSO_BINARY_TYPE__NOT_FOUND:
|
| 108 | default:
|
| 109 | return true;
|
| 110 | }
|
| 111 | }
|
| 112 |
|
| 113 | int dso__read_binary_type_filename(const struct dso *dso,
|
| 114 | enum dso_binary_type type,
|
| 115 | const char *root_dir, char *filename, size_t size)
|
| 116 | {
|
| 117 | char build_id_hex[SBUILD_ID_SIZE];
|
| 118 | int ret = 0;
|
| 119 | size_t len;
|
| 120 |
|
| 121 | switch (type) {
|
| 122 | case DSO_BINARY_TYPE__DEBUGLINK:
|
| 123 | {
|
| 124 | const char *last_slash;
|
| 125 | char dso_dir[PATH_MAX];
|
| 126 | char symfile[PATH_MAX];
|
| 127 | unsigned int i;
|
| 128 |
|
| 129 | len = __symbol__join_symfs(filename, size, dso__long_name(dso));
|
| 130 | last_slash = filename + len;
|
| 131 | while (last_slash != filename && *last_slash != '/')
|
| 132 | last_slash--;
|
| 133 |
|
| 134 | strncpy(dso_dir, filename, last_slash - filename);
|
| 135 | dso_dir[last_slash-filename] = '\0';
|
| 136 |
|
| 137 | if (!is_regular_file(filename)) {
|
| 138 | ret = -1;
|
| 139 | break;
|
| 140 | }
|
| 141 |
|
| 142 | ret = filename__read_debuglink(filename, symfile, PATH_MAX);
|
| 143 | if (ret)
|
| 144 | break;
|
| 145 |
|
| 146 |
|
| 147 | ret = -1;
|
| 148 | for (i = 0; i < ARRAY_SIZE(debuglink_paths); i++) {
|
| 149 | snprintf(filename, size,
|
| 150 | debuglink_paths[i], dso_dir, symfile);
|
| 151 | if (is_regular_file(filename)) {
|
| 152 | ret = 0;
|
| 153 | break;
|
| 154 | }
|
| 155 | }
|
| 156 |
|
| 157 | break;
|
| 158 | }
|
| 159 | case DSO_BINARY_TYPE__BUILD_ID_CACHE:
|
| 160 | if (dso__build_id_filename(dso, filename, size, false) == NULL)
|
| 161 | ret = -1;
|
| 162 | break;
|
| 163 |
|
| 164 | case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
|
| 165 | if (dso__build_id_filename(dso, filename, size, true) == NULL)
|
| 166 | ret = -1;
|
| 167 | break;
|
| 168 |
|
| 169 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
|
| 170 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
|
| 171 | snprintf(filename + len, size - len, "%s.debug", dso__long_name(dso));
|
| 172 | break;
|
| 173 |
|
| 174 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
|
| 175 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
|
| 176 | snprintf(filename + len, size - len, "%s", dso__long_name(dso));
|
| 177 | break;
|
| 178 |
|
| 179 | case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO:
|
| 180 | |
| 181 | * Ubuntu can mixup /usr/lib with /lib, putting debuginfo in
|
| 182 | * /usr/lib/debug/lib when it is expected to be in
|
| 183 | * /usr/lib/debug/usr/lib
|
| 184 |
|
| 185 | if (strlen(dso__long_name(dso)) < 9 ||
|
| 186 | strncmp(dso__long_name(dso), "/usr/lib/", 9)) {
|
| 187 | ret = -1;
|
| 188 | break;
|
| 189 | }
|
| 190 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
|
| 191 | snprintf(filename + len, size - len, "%s", dso__long_name(dso) + 4);
|
| 192 | break;
|
| 193 |
|
| 194 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
|
| 195 | {
|
| 196 | const char *last_slash;
|
| 197 | size_t dir_size;
|
| 198 |
|
| 199 | last_slash = dso__long_name(dso) + dso__long_name_len(dso);
|
| 200 | while (last_slash != dso__long_name(dso) && *last_slash != '/')
|
| 201 | last_slash--;
|
| 202 |
|
| 203 | len = __symbol__join_symfs(filename, size, "");
|
| 204 | dir_size = last_slash - dso__long_name(dso) + 2;
|
| 205 | if (dir_size > (size - len)) {
|
| 206 | ret = -1;
|
| 207 | break;
|
| 208 | }
|
| 209 | len += scnprintf(filename + len, dir_size, "%s", dso__long_name(dso));
|
| 210 | len += scnprintf(filename + len , size - len, ".debug%s",
|
| 211 | last_slash);
|
| 212 | break;
|
| 213 | }
|
| 214 |
|
| 215 | case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
|
| 216 | if (!dso__has_build_id(dso)) {
|
| 217 | ret = -1;
|
| 218 | break;
|
| 219 | }
|
| 220 |
|
| 221 | build_id__snprintf(dso__bid(dso), build_id_hex, sizeof(build_id_hex));
|
| 222 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/");
|
| 223 | snprintf(filename + len, size - len, "%.2s/%s.debug",
|
| 224 | build_id_hex, build_id_hex + 2);
|
| 225 | break;
|
| 226 |
|
| 227 | case DSO_BINARY_TYPE__VMLINUX:
|
| 228 | case DSO_BINARY_TYPE__GUEST_VMLINUX:
|
| 229 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
|
| 230 | case DSO_BINARY_TYPE__GNU_DEBUGDATA:
|
| 231 | __symbol__join_symfs(filename, size, dso__long_name(dso));
|
| 232 | break;
|
| 233 |
|
| 234 | case DSO_BINARY_TYPE__GUEST_KMODULE:
|
| 235 | case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
|
| 236 | path__join3(filename, size, symbol_conf.symfs,
|
| 237 | root_dir, dso__long_name(dso));
|
| 238 | break;
|
| 239 |
|
| 240 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
|
| 241 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
|
| 242 | __symbol__join_symfs(filename, size, dso__long_name(dso));
|
| 243 | break;
|
| 244 |
|
| 245 | case DSO_BINARY_TYPE__KCORE:
|
| 246 | case DSO_BINARY_TYPE__GUEST_KCORE:
|
| 247 | snprintf(filename, size, "%s", dso__long_name(dso));
|
| 248 | break;
|
| 249 |
|
| 250 | default:
|
| 251 | case DSO_BINARY_TYPE__KALLSYMS:
|
| 252 | case DSO_BINARY_TYPE__GUEST_KALLSYMS:
|
| 253 | case DSO_BINARY_TYPE__JAVA_JIT:
|
| 254 | case DSO_BINARY_TYPE__BPF_PROG_INFO:
|
| 255 | case DSO_BINARY_TYPE__BPF_IMAGE:
|
| 256 | case DSO_BINARY_TYPE__OOL:
|
| 257 | case DSO_BINARY_TYPE__NOT_FOUND:
|
| 258 | ret = -1;
|
| 259 | break;
|
| 260 | }
|
| 261 |
|
| 262 | return ret;
|
| 263 | }
|
| 264 |
|
| 265 | enum {
|
| 266 | COMP_ID__NONE = 0,
|
| 267 | };
|
| 268 |
|
| 269 | static const struct {
|
| 270 | const char *fmt;
|
| 271 | int (*decompress)(const char *input, int output);
|
| 272 | bool (*is_compressed)(const char *input);
|
| 273 | } compressions[] = {
|
| 274 | [COMP_ID__NONE] = { .fmt = NULL, },
|
| 275 | #ifdef HAVE_ZLIB_SUPPORT
|
| 276 | { "gz", gzip_decompress_to_file, gzip_is_compressed },
|
| 277 | #endif
|
| 278 | #ifdef HAVE_LZMA_SUPPORT
|
| 279 | { "xz", lzma_decompress_to_file, lzma_is_compressed },
|
| 280 | #endif
|
| 281 | { NULL, NULL, NULL },
|
| 282 | };
|
| 283 |
|
| 284 | static int is_supported_compression(const char *ext)
|
| 285 | {
|
| 286 | unsigned i;
|
| 287 |
|
| 288 | for (i = 1; compressions[i].fmt; i++) {
|
| 289 | if (!strcmp(ext, compressions[i].fmt))
|
| 290 | return i;
|
| 291 | }
|
| 292 | return COMP_ID__NONE;
|
| 293 | }
|
| 294 |
|
| 295 | bool is_kernel_module(const char *pathname, int cpumode)
|
| 296 | {
|
| 297 | struct kmod_path m;
|
| 298 | int mode = cpumode & PERF_RECORD_MISC_CPUMODE_MASK;
|
| 299 |
|
| 300 | WARN_ONCE(mode != cpumode,
|
| 301 | "Internal error: passing unmasked cpumode (%x) to is_kernel_module",
|
| 302 | cpumode);
|
| 303 |
|
| 304 | switch (mode) {
|
| 305 | case PERF_RECORD_MISC_USER:
|
| 306 | case PERF_RECORD_MISC_HYPERVISOR:
|
| 307 | case PERF_RECORD_MISC_GUEST_USER:
|
| 308 | return false;
|
| 309 |
|
| 310 | default:
|
| 311 | if (kmod_path__parse(&m, pathname)) {
|
| 312 | pr_err("Failed to check whether %s is a kernel module or not. Assume it is.",
|
| 313 | pathname);
|
| 314 | return true;
|
| 315 | }
|
| 316 | }
|
| 317 |
|
| 318 | return m.kmod;
|
| 319 | }
|
| 320 |
|
| 321 | bool dso__needs_decompress(struct dso *dso)
|
| 322 | {
|
| 323 | return dso__symtab_type(dso) == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
|
| 324 | dso__symtab_type(dso) == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
|
| 325 | }
|
| 326 |
|
| 327 | int filename__decompress(const char *name, char *pathname,
|
| 328 | size_t len, int comp, int *err)
|
| 329 | {
|
| 330 | char tmpbuf[] = KMOD_DECOMP_NAME;
|
| 331 | int fd = -1;
|
| 332 |
|
| 333 | |
| 334 | * We have proper compression id for DSO and yet the file
|
| 335 | * behind the 'name' can still be plain uncompressed object.
|
| 336 | *
|
| 337 | * The reason is behind the logic we open the DSO object files,
|
| 338 | * when we try all possible 'debug' objects until we find the
|
| 339 | * data. So even if the DSO is represented by 'krava.xz' module,
|
| 340 | * we can end up here opening ~/.debug/....23432432/debug' file
|
| 341 | * which is not compressed.
|
| 342 | *
|
| 343 | * To keep this transparent, we detect this and return the file
|
| 344 | * descriptor to the uncompressed file.
|
| 345 |
|
| 346 | if (!compressions[comp].is_compressed(name)) {
|
| 347 | fd = open(name, O_RDONLY | O_CLOEXEC);
|
| 348 | if (fd < 0)
|
| 349 | *err = errno;
|
| 350 | if (pathname && len > 0)
|
| 351 | pathname[0] = '\0';
|
| 352 | return fd;
|
| 353 | }
|
| 354 |
|
| 355 | fd = mkostemp(tmpbuf, O_CLOEXEC);
|
| 356 | if (fd < 0) {
|
| 357 | *err = errno;
|
| 358 | return -1;
|
| 359 | }
|
| 360 |
|
| 361 | if (compressions[comp].decompress(name, fd)) {
|
| 362 | *err = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
|
| 363 | close(fd);
|
| 364 | fd = -1;
|
| 365 | }
|
| 366 |
|
| 367 | if (!pathname || (fd < 0))
|
| 368 | unlink(tmpbuf);
|
| 369 |
|
| 370 | if (pathname && (fd >= 0))
|
| 371 | strlcpy(pathname, tmpbuf, len);
|
| 372 |
|
| 373 | return fd;
|
| 374 | }
|
| 375 |
|
| 376 | static int decompress_kmodule(struct dso *dso, const char *name,
|
| 377 | char *pathname, size_t len)
|
| 378 | {
|
| 379 | if (!dso__needs_decompress(dso))
|
| 380 | return -1;
|
| 381 |
|
| 382 | if (dso__comp(dso) == COMP_ID__NONE)
|
| 383 | return -1;
|
| 384 |
|
| 385 | return filename__decompress(name, pathname, len, dso__comp(dso), dso__load_errno(dso));
|
| 386 | }
|
| 387 |
|
| 388 | int dso__decompress_kmodule_fd(struct dso *dso, const char *name)
|
| 389 | {
|
| 390 | return decompress_kmodule(dso, name, NULL, 0);
|
| 391 | }
|
| 392 |
|
| 393 | int dso__decompress_kmodule_path(struct dso *dso, const char *name,
|
| 394 | char *pathname, size_t len)
|
| 395 | {
|
| 396 | int fd = decompress_kmodule(dso, name, pathname, len);
|
| 397 |
|
| 398 |
|
| 399 | if (fd >= 0)
|
| 400 | close(fd);
|
| 401 | return fd >= 0 ? 0 : -1;
|
| 402 | }
|
| 403 |
|
| 404 | |
| 405 | * Parses kernel module specified in @path and updates
|
| 406 | * @m argument like:
|
| 407 | *
|
| 408 | * @comp - true if @path contains supported compression suffix,
|
| 409 | * false otherwise
|
| 410 | * @kmod - true if @path contains '.ko' suffix in right position,
|
| 411 | * false otherwise
|
| 412 | * @name - if (@alloc_name && @kmod) is true, it contains strdup-ed base name
|
| 413 | * of the kernel module without suffixes, otherwise strudup-ed
|
| 414 | * base name of @path
|
| 415 | * @ext - if (@alloc_ext && @comp) is true, it contains strdup-ed string
|
| 416 | * the compression suffix
|
| 417 | *
|
| 418 | * Returns 0 if there's no strdup error, -ENOMEM otherwise.
|
| 419 |
|
| 420 | int __kmod_path__parse(struct kmod_path *m, const char *path,
|
| 421 | bool alloc_name)
|
| 422 | {
|
| 423 | const char *name = strrchr(path, '/');
|
| 424 | const char *ext = strrchr(path, '.');
|
| 425 | bool is_simple_name = false;
|
| 426 |
|
| 427 | memset(m, 0x0, sizeof(*m));
|
| 428 | name = name ? name + 1 : path;
|
| 429 |
|
| 430 | |
| 431 | * '.' is also a valid character for module name. For example:
|
| 432 | * [aaa.bbb] is a valid module name. '[' should have higher
|
| 433 | * priority than '.ko' suffix.
|
| 434 | *
|
| 435 | * The kernel names are from machine__mmap_name. Such
|
| 436 | * name should belong to kernel itself, not kernel module.
|
| 437 |
|
| 438 | if (name[0] == '[') {
|
| 439 | is_simple_name = true;
|
| 440 | if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) ||
|
| 441 | (strncmp(name, "[guest.kernel.kallsyms", 22) == 0) ||
|
| 442 | (strncmp(name, "[vdso]", 6) == 0) ||
|
| 443 | (strncmp(name, "[vdso32]", 8) == 0) ||
|
| 444 | (strncmp(name, "[vdsox32]", 9) == 0) ||
|
| 445 | (strncmp(name, "[vsyscall]", 10) == 0)) {
|
| 446 | m->kmod = false;
|
| 447 |
|
| 448 | } else
|
| 449 | m->kmod = true;
|
| 450 | }
|
| 451 |
|
| 452 |
|
| 453 | if ((ext == NULL) || is_simple_name) {
|
| 454 | if (alloc_name) {
|
| 455 | m->name = strdup(name);
|
| 456 | return m->name ? 0 : -ENOMEM;
|
| 457 | }
|
| 458 | return 0;
|
| 459 | }
|
| 460 |
|
| 461 | m->comp = is_supported_compression(ext + 1);
|
| 462 | if (m->comp > COMP_ID__NONE)
|
| 463 | ext -= 3;
|
| 464 |
|
| 465 |
|
| 466 | if (ext > name)
|
| 467 | m->kmod = !strncmp(ext, ".ko", 3);
|
| 468 |
|
| 469 | if (alloc_name) {
|
| 470 | if (m->kmod) {
|
| 471 | if (asprintf(&m->name, "[%.*s]", (int) (ext - name), name) == -1)
|
| 472 | return -ENOMEM;
|
| 473 | } else {
|
| 474 | if (asprintf(&m->name, "%s", name) == -1)
|
| 475 | return -ENOMEM;
|
| 476 | }
|
| 477 |
|
| 478 | strreplace(m->name, '-', '_');
|
| 479 | }
|
| 480 |
|
| 481 | return 0;
|
| 482 | }
|
| 483 |
|
| 484 | void dso__set_module_info(struct dso *dso, struct kmod_path *m,
|
| 485 | struct machine *machine)
|
| 486 | {
|
| 487 | if (machine__is_host(machine))
|
| 488 | dso__set_symtab_type(dso, DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE);
|
| 489 | else
|
| 490 | dso__set_symtab_type(dso, DSO_BINARY_TYPE__GUEST_KMODULE);
|
| 491 |
|
| 492 |
|
| 493 | if (m->kmod && m->comp) {
|
| 494 | dso__set_symtab_type(dso, dso__symtab_type(dso) + 1);
|
| 495 | dso__set_comp(dso, m->comp);
|
| 496 | }
|
| 497 |
|
| 498 | dso__set_is_kmod(dso);
|
| 499 | dso__set_short_name(dso, strdup(m->name), true);
|
| 500 | }
|
| 501 |
|
| 502 | |
| 503 | * Global list of open DSOs and the counter.
|
| 504 |
|
| 505 | struct mutex _dso__data_open_lock;
|
| 506 | static LIST_HEAD(dso__data_open);
|
| 507 | static long dso__data_open_cnt GUARDED_BY(_dso__data_open_lock);
|
| 508 |
|
| 509 | static void dso__data_open_lock_init(void)
|
| 510 | {
|
| 511 | mutex_init(&_dso__data_open_lock);
|
| 512 | }
|
| 513 |
|
| 514 | static struct mutex *dso__data_open_lock(void) LOCK_RETURNED(_dso__data_open_lock)
|
| 515 | {
|
| 516 | static pthread_once_t data_open_lock_once = PTHREAD_ONCE_INIT;
|
| 517 |
|
| 518 | pthread_once(&data_open_lock_once, dso__data_open_lock_init);
|
| 519 |
|
| 520 | return &_dso__data_open_lock;
|
| 521 | }
|
| 522 |
|
| 523 | static void dso__list_add(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
|
| 524 | {
|
| 525 | list_add_tail(&dso__data(dso)->open_entry, &dso__data_open);
|
| 526 | #ifdef REFCNT_CHECKING
|
| 527 | dso__data(dso)->dso = dso__get(dso);
|
| 528 | #endif
|
| 529 |
|
| 530 | assert(dso__dsos(dso));
|
| 531 | dso__data_open_cnt++;
|
| 532 | }
|
| 533 |
|
| 534 | static void dso__list_del(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
|
| 535 | {
|
| 536 | list_del_init(&dso__data(dso)->open_entry);
|
| 537 | #ifdef REFCNT_CHECKING
|
| 538 | mutex_unlock(dso__data_open_lock());
|
| 539 | dso__put(dso__data(dso)->dso);
|
| 540 | mutex_lock(dso__data_open_lock());
|
| 541 | #endif
|
| 542 | WARN_ONCE(dso__data_open_cnt <= 0,
|
| 543 | "DSO data fd counter out of bounds.");
|
| 544 | dso__data_open_cnt--;
|
| 545 | }
|
| 546 |
|
| 547 | static void close_first_dso(void);
|
| 548 |
|
| 549 | static int do_open(char *name) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
|
| 550 | {
|
| 551 | do {
|
| 552 | int fd = open(name, O_RDONLY|O_CLOEXEC);
|
| 553 |
|
| 554 | if (fd >= 0)
|
| 555 | return fd;
|
| 556 |
|
| 557 | pr_debug("dso open failed: %m\n");
|
| 558 | if (!dso__data_open_cnt || errno != EMFILE)
|
| 559 | break;
|
| 560 |
|
| 561 | close_first_dso();
|
| 562 | } while (1);
|
| 563 |
|
| 564 | return -1;
|
| 565 | }
|
| 566 |
|
| 567 | char *dso__filename_with_chroot(const struct dso *dso, const char *filename)
|
| 568 | {
|
| 569 | return filename_with_chroot(nsinfo__pid(dso__nsinfo_const(dso)), filename);
|
| 570 | }
|
| 571 |
|
| 572 | static char *dso__get_filename(struct dso *dso, const char *root_dir,
|
| 573 | bool *decomp)
|
| 574 | {
|
| 575 | char *name = malloc(PATH_MAX);
|
| 576 |
|
| 577 | *decomp = false;
|
| 578 |
|
| 579 | if (name == NULL)
|
| 580 | return NULL;
|
| 581 |
|
| 582 | if (dso__read_binary_type_filename(dso, dso__binary_type(dso),
|
| 583 | root_dir, name, PATH_MAX))
|
| 584 | goto out;
|
| 585 |
|
| 586 | if (!is_regular_file(name)) {
|
| 587 | struct stat st;
|
| 588 | char *new_name;
|
| 589 |
|
| 590 | |
| 591 | * errno only reflects the failure reason when stat() itself
|
| 592 | * failed: a successful stat() on a non-regular file (e.g. a
|
| 593 | * directory) leaves a stale errno, which a previous failed
|
| 594 | * iteration of the try_to_open_dso() fallback loop may have
|
| 595 | * set to ENOENT.
|
| 596 |
|
| 597 | if (stat(name, &st) == 0 || errno != ENOENT ||
|
| 598 | dso__nsinfo(dso) == NULL)
|
| 599 | goto out;
|
| 600 |
|
| 601 | new_name = dso__filename_with_chroot(dso, name);
|
| 602 | if (!new_name)
|
| 603 | goto out;
|
| 604 |
|
| 605 | free(name);
|
| 606 | name = new_name;
|
| 607 | }
|
| 608 |
|
| 609 | if (dso__needs_decompress(dso)) {
|
| 610 | char newpath[KMOD_DECOMP_LEN];
|
| 611 | size_t len = sizeof(newpath);
|
| 612 |
|
| 613 | if (dso__decompress_kmodule_path(dso, name, newpath, len) < 0) {
|
| 614 | |
| 615 | * Use a standard errno value, not the negative custom
|
| 616 | * DSO_LOAD_ERRNO stored in dso__load_errno(dso):
|
| 617 | * __open_dso() computes fd = -errno, so a negative
|
| 618 | * errno produces a positive fd that looks valid.
|
| 619 |
|
| 620 | errno = EIO;
|
| 621 | goto out;
|
| 622 | }
|
| 623 |
|
| 624 |
|
| 625 | if (newpath[0] != '\0') {
|
| 626 | char *tmp = strdup(newpath);
|
| 627 |
|
| 628 | if (!tmp) {
|
| 629 | unlink(newpath);
|
| 630 | goto out;
|
| 631 | }
|
| 632 | free(name);
|
| 633 | name = tmp;
|
| 634 | *decomp = true;
|
| 635 | }
|
| 636 | }
|
| 637 | return name;
|
| 638 |
|
| 639 | out:
|
| 640 | free(name);
|
| 641 | return NULL;
|
| 642 | }
|
| 643 |
|
| 644 | static int __open_dso(struct dso *dso, struct machine *machine)
|
| 645 | EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
|
| 646 | {
|
| 647 | int fd = -EINVAL;
|
| 648 | char *name;
|
| 649 | bool decomp = false;
|
| 650 |
|
| 651 | mutex_lock(dso__lock(dso));
|
| 652 |
|
| 653 | name = dso__get_filename(dso, machine ? machine->root_dir : "", &decomp);
|
| 654 | if (name) {
|
| 655 | fd = do_open(name);
|
| 656 | } else {
|
| 657 | if (errno == 0)
|
| 658 | errno = ENOENT;
|
| 659 | fd = -errno;
|
| 660 | }
|
| 661 |
|
| 662 | if (decomp)
|
| 663 | unlink(name);
|
| 664 |
|
| 665 | mutex_unlock(dso__lock(dso));
|
| 666 | free(name);
|
| 667 | return fd;
|
| 668 | }
|
| 669 |
|
| 670 | static void check_data_close(void);
|
| 671 |
|
| 672 | |
| 673 | * dso_close - Open DSO data file
|
| 674 | * @dso: dso object
|
| 675 | *
|
| 676 | * Open @dso's data file descriptor and updates
|
| 677 | * list/count of open DSO objects.
|
| 678 |
|
| 679 | static int open_dso(struct dso *dso, struct machine *machine)
|
| 680 | EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
|
| 681 | {
|
| 682 | int fd;
|
| 683 | struct nscookie nsc;
|
| 684 |
|
| 685 | if (dso__binary_type(dso) != DSO_BINARY_TYPE__BUILD_ID_CACHE) {
|
| 686 | mutex_lock(dso__lock(dso));
|
| 687 | nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
|
| 688 | mutex_unlock(dso__lock(dso));
|
| 689 | }
|
| 690 | fd = __open_dso(dso, machine);
|
| 691 | if (dso__binary_type(dso) != DSO_BINARY_TYPE__BUILD_ID_CACHE)
|
| 692 | nsinfo__mountns_exit(&nsc);
|
| 693 |
|
| 694 | if (fd >= 0) {
|
| 695 | dso__list_add(dso);
|
| 696 | |
| 697 | * Check if we crossed the allowed number
|
| 698 | * of opened DSOs and close one if needed.
|
| 699 |
|
| 700 | check_data_close();
|
| 701 | }
|
| 702 |
|
| 703 | return fd;
|
| 704 | }
|
| 705 |
|
| 706 | static void close_data_fd(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
|
| 707 | {
|
| 708 | if (dso__data(dso)->fd >= 0) {
|
| 709 | close(dso__data(dso)->fd);
|
| 710 | dso__data(dso)->fd = -1;
|
| 711 | dso__data(dso)->file_size = 0;
|
| 712 | dso__list_del(dso);
|
| 713 | }
|
| 714 | }
|
| 715 |
|
| 716 | |
| 717 | * dso_close - Close DSO data file
|
| 718 | * @dso: dso object
|
| 719 | *
|
| 720 | * Close @dso's data file descriptor and updates
|
| 721 | * list/count of open DSO objects.
|
| 722 |
|
| 723 | static void close_dso(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
|
| 724 | {
|
| 725 | close_data_fd(dso);
|
| 726 | }
|
| 727 |
|
| 728 | static void close_first_dso(void) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
|
| 729 | {
|
| 730 | struct dso_data *dso_data;
|
| 731 | struct dso *dso;
|
| 732 |
|
| 733 | dso_data = list_first_entry(&dso__data_open, struct dso_data, open_entry);
|
| 734 | #ifdef REFCNT_CHECKING
|
| 735 | dso = dso_data->dso;
|
| 736 | #else
|
| 737 | dso = container_of(dso_data, struct dso, data);
|
| 738 | #endif
|
| 739 | close_dso(dso);
|
| 740 | }
|
| 741 |
|
| 742 | static rlim_t get_fd_limit(void)
|
| 743 | {
|
| 744 | struct rlimit l;
|
| 745 | rlim_t limit = 0;
|
| 746 |
|
| 747 |
|
| 748 | if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
|
| 749 | if (l.rlim_cur == RLIM_INFINITY)
|
| 750 | limit = l.rlim_cur;
|
| 751 | else
|
| 752 | limit = l.rlim_cur / 2;
|
| 753 | } else {
|
| 754 | pr_err("failed to get fd limit\n");
|
| 755 | limit = 1;
|
| 756 | }
|
| 757 |
|
| 758 | return limit;
|
| 759 | }
|
| 760 |
|
| 761 | static rlim_t fd_limit;
|
| 762 |
|
| 763 | |
| 764 | * Used only by tests/dso-data.c to reset the environment
|
| 765 | * for tests. I dont expect we should change this during
|
| 766 | * standard runtime.
|
| 767 |
|
| 768 | void reset_fd_limit(void)
|
| 769 | {
|
| 770 | fd_limit = 0;
|
| 771 | }
|
| 772 |
|
| 773 | static bool may_cache_fd(void) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
|
| 774 | {
|
| 775 | if (!fd_limit)
|
| 776 | fd_limit = get_fd_limit();
|
| 777 |
|
| 778 | if (fd_limit == RLIM_INFINITY)
|
| 779 | return true;
|
| 780 |
|
| 781 | return fd_limit > (rlim_t) dso__data_open_cnt;
|
| 782 | }
|
| 783 |
|
| 784 | |
| 785 | * Check and close LRU dso if we crossed allowed limit
|
| 786 | * for opened dso file descriptors. The limit is half
|
| 787 | * of the RLIMIT_NOFILE files opened.
|
| 788 |
|
| 789 | static void check_data_close(void) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
|
| 790 | {
|
| 791 | bool cache_fd = may_cache_fd();
|
| 792 |
|
| 793 | if (!cache_fd)
|
| 794 | close_first_dso();
|
| 795 | }
|
| 796 |
|
| 797 | |
| 798 | * dso__data_close - Close DSO data file
|
| 799 | * @dso: dso object
|
| 800 | *
|
| 801 | * External interface to close @dso's data file descriptor.
|
| 802 |
|
| 803 | void dso__data_close(struct dso *dso)
|
| 804 | {
|
| 805 | mutex_lock(dso__data_open_lock());
|
| 806 | close_dso(dso);
|
| 807 | mutex_unlock(dso__data_open_lock());
|
| 808 | }
|
| 809 |
|
| 810 | static void try_to_open_dso(struct dso *dso, struct machine *machine)
|
| 811 | EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
|
| 812 | {
|
| 813 | enum dso_binary_type binary_type_data[] = {
|
| 814 | DSO_BINARY_TYPE__BUILD_ID_CACHE,
|
| 815 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
|
| 816 | DSO_BINARY_TYPE__NOT_FOUND,
|
| 817 | };
|
| 818 | int i = 0;
|
| 819 | struct dso_data *dso_data = dso__data(dso);
|
| 820 |
|
| 821 | if (dso_data->fd >= 0)
|
| 822 | return;
|
| 823 |
|
| 824 | if (dso__binary_type(dso) != DSO_BINARY_TYPE__NOT_FOUND) {
|
| 825 | dso_data->fd = open_dso(dso, machine);
|
| 826 | goto out;
|
| 827 | }
|
| 828 |
|
| 829 | do {
|
| 830 | dso__set_binary_type(dso, binary_type_data[i++]);
|
| 831 |
|
| 832 | dso_data->fd = open_dso(dso, machine);
|
| 833 | if (dso_data->fd >= 0)
|
| 834 | goto out;
|
| 835 |
|
| 836 | } while (dso__binary_type(dso) != DSO_BINARY_TYPE__NOT_FOUND);
|
| 837 | out:
|
| 838 | if (dso_data->fd >= 0)
|
| 839 | dso_data->status = DSO_DATA_STATUS_OK;
|
| 840 | else
|
| 841 | dso_data->status = DSO_DATA_STATUS_ERROR;
|
| 842 | }
|
| 843 |
|
| 844 | |
| 845 | * dso__data_get_fd - Get dso's data file descriptor
|
| 846 | * @dso: dso object
|
| 847 | * @machine: machine object
|
| 848 | *
|
| 849 | * External interface to find dso's file, open it and
|
| 850 | * returns file descriptor. It should be paired with
|
| 851 | * dso__data_put_fd() if it returns non-negative value.
|
| 852 |
|
| 853 | bool dso__data_get_fd(struct dso *dso, struct machine *machine, int *fd)
|
| 854 | {
|
| 855 | *fd = -1;
|
| 856 | if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR)
|
| 857 | return false;
|
| 858 |
|
| 859 | mutex_lock(dso__data_open_lock());
|
| 860 |
|
| 861 | try_to_open_dso(dso, machine);
|
| 862 |
|
| 863 | *fd = dso__data(dso)->fd;
|
| 864 | if (*fd >= 0)
|
| 865 | return true;
|
| 866 |
|
| 867 | mutex_unlock(dso__data_open_lock());
|
| 868 | return false;
|
| 869 | }
|
| 870 |
|
| 871 | void dso__data_put_fd(struct dso *dso __maybe_unused)
|
| 872 | {
|
| 873 | mutex_unlock(dso__data_open_lock());
|
| 874 | }
|
| 875 |
|
| 876 | bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by)
|
| 877 | {
|
| 878 | u32 flag = 1 << by;
|
| 879 |
|
| 880 | if (dso__data(dso)->status_seen & flag)
|
| 881 | return true;
|
| 882 |
|
| 883 | dso__data(dso)->status_seen |= flag;
|
| 884 |
|
| 885 | return false;
|
| 886 | }
|
| 887 |
|
| 888 | #ifdef HAVE_LIBBPF_SUPPORT
|
| 889 | static ssize_t bpf_read(struct dso *dso, u64 offset, char *data)
|
| 890 | {
|
| 891 | struct bpf_prog_info_node *node;
|
| 892 | ssize_t size = DSO__DATA_CACHE_SIZE;
|
| 893 | struct dso_bpf_prog *dso_bpf_prog = dso__bpf_prog(dso);
|
| 894 | u64 len;
|
| 895 | u8 *buf;
|
| 896 |
|
| 897 | node = perf_env__find_bpf_prog_info(dso_bpf_prog->env, dso_bpf_prog->id);
|
| 898 | if (!node || !node->info_linear) {
|
| 899 | dso__data(dso)->status = DSO_DATA_STATUS_ERROR;
|
| 900 | return -1;
|
| 901 | }
|
| 902 |
|
| 903 |
|
| 904 | if (!(node->info_linear->arrays & (1UL << PERF_BPIL_JITED_INSNS))) {
|
| 905 | dso__data(dso)->status = DSO_DATA_STATUS_ERROR;
|
| 906 | return -1;
|
| 907 | }
|
| 908 |
|
| 909 | len = node->info_linear->info.jited_prog_len;
|
| 910 | buf = (u8 *)(uintptr_t)node->info_linear->info.jited_prog_insns;
|
| 911 |
|
| 912 | if (offset >= len)
|
| 913 | return -1;
|
| 914 |
|
| 915 | size = (ssize_t)min(len - offset, (u64)size);
|
| 916 | memcpy(data, buf + offset, size);
|
| 917 | return size;
|
| 918 | }
|
| 919 |
|
| 920 | static int bpf_size(struct dso *dso)
|
| 921 | {
|
| 922 | struct bpf_prog_info_node *node;
|
| 923 | struct dso_bpf_prog *dso_bpf_prog = dso__bpf_prog(dso);
|
| 924 |
|
| 925 | node = perf_env__find_bpf_prog_info(dso_bpf_prog->env, dso_bpf_prog->id);
|
| 926 | if (!node || !node->info_linear) {
|
| 927 | dso__data(dso)->status = DSO_DATA_STATUS_ERROR;
|
| 928 | return -1;
|
| 929 | }
|
| 930 |
|
| 931 | dso__data(dso)->file_size = node->info_linear->info.jited_prog_len;
|
| 932 | return 0;
|
| 933 | }
|
| 934 | #endif |
| 935 |
|
| 936 | static void
|
| 937 | dso_cache__free(struct dso *dso)
|
| 938 | {
|
| 939 | struct rb_root *root = &dso__data(dso)->cache;
|
| 940 | struct rb_node *next = rb_first(root);
|
| 941 |
|
| 942 | mutex_lock(dso__lock(dso));
|
| 943 | while (next) {
|
| 944 | struct dso_cache *cache;
|
| 945 |
|
| 946 | cache = rb_entry(next, struct dso_cache, rb_node);
|
| 947 | next = rb_next(&cache->rb_node);
|
| 948 | rb_erase(&cache->rb_node, root);
|
| 949 | free(cache);
|
| 950 | }
|
| 951 | mutex_unlock(dso__lock(dso));
|
| 952 | }
|
| 953 |
|
| 954 | static struct dso_cache *__dso_cache__find(struct dso *dso, u64 offset)
|
| 955 | {
|
| 956 | const struct rb_root *root = &dso__data(dso)->cache;
|
| 957 | struct rb_node * const *p = &root->rb_node;
|
| 958 | const struct rb_node *parent = NULL;
|
| 959 | struct dso_cache *cache;
|
| 960 |
|
| 961 | while (*p != NULL) {
|
| 962 | u64 end;
|
| 963 |
|
| 964 | parent = *p;
|
| 965 | cache = rb_entry(parent, struct dso_cache, rb_node);
|
| 966 | end = cache->offset + DSO__DATA_CACHE_SIZE;
|
| 967 |
|
| 968 | if (offset < cache->offset)
|
| 969 | p = &(*p)->rb_left;
|
| 970 | else if (offset >= end)
|
| 971 | p = &(*p)->rb_right;
|
| 972 | else
|
| 973 | return cache;
|
| 974 | }
|
| 975 |
|
| 976 | return NULL;
|
| 977 | }
|
| 978 |
|
| 979 | static struct dso_cache *
|
| 980 | dso_cache__insert(struct dso *dso, struct dso_cache *new)
|
| 981 | {
|
| 982 | struct rb_root *root = &dso__data(dso)->cache;
|
| 983 | struct rb_node **p = &root->rb_node;
|
| 984 | struct rb_node *parent = NULL;
|
| 985 | struct dso_cache *cache;
|
| 986 | u64 offset = new->offset;
|
| 987 |
|
| 988 | mutex_lock(dso__lock(dso));
|
| 989 | while (*p != NULL) {
|
| 990 | u64 end;
|
| 991 |
|
| 992 | parent = *p;
|
| 993 | cache = rb_entry(parent, struct dso_cache, rb_node);
|
| 994 | end = cache->offset + DSO__DATA_CACHE_SIZE;
|
| 995 |
|
| 996 | if (offset < cache->offset)
|
| 997 | p = &(*p)->rb_left;
|
| 998 | else if (offset >= end)
|
| 999 | p = &(*p)->rb_right;
|
| 1000 | else
|
| 1001 | goto out;
|
| 1002 | }
|
| 1003 |
|
| 1004 | rb_link_node(&new->rb_node, parent, p);
|
| 1005 | rb_insert_color(&new->rb_node, root);
|
| 1006 |
|
| 1007 | cache = NULL;
|
| 1008 | out:
|
| 1009 | mutex_unlock(dso__lock(dso));
|
| 1010 | return cache;
|
| 1011 | }
|
| 1012 |
|
| 1013 | static ssize_t dso_cache__memcpy(struct dso_cache *cache, u64 offset, u8 *data,
|
| 1014 | u64 size, bool out)
|
| 1015 | {
|
| 1016 | u64 cache_offset = offset - cache->offset;
|
| 1017 | u64 cache_size;
|
| 1018 |
|
| 1019 | |
| 1020 | * The RB tree matches using DSO__DATA_CACHE_SIZE, but a short
|
| 1021 | * pread may leave cache->size smaller. For a regular file a
|
| 1022 | * short pread only happens at end-of-file, so an offset past
|
| 1023 | * the valid data is EOF: return 0, matching what a direct
|
| 1024 | * pread() at that offset would return, and cached_io() then
|
| 1025 | * stops its read loop.
|
| 1026 |
|
| 1027 | if (cache_offset >= cache->size)
|
| 1028 | return 0;
|
| 1029 |
|
| 1030 | cache_size = min(cache->size - cache_offset, size);
|
| 1031 |
|
| 1032 | if (out)
|
| 1033 | memcpy(data, cache->data + cache_offset, cache_size);
|
| 1034 | else
|
| 1035 | memcpy(cache->data + cache_offset, data, cache_size);
|
| 1036 | return cache_size;
|
| 1037 | }
|
| 1038 |
|
| 1039 | static ssize_t file_read(struct dso *dso, struct machine *machine,
|
| 1040 | u64 offset, char *data)
|
| 1041 | {
|
| 1042 | ssize_t ret;
|
| 1043 |
|
| 1044 | mutex_lock(dso__data_open_lock());
|
| 1045 |
|
| 1046 | |
| 1047 | * dso__data(dso)->fd might be closed if other thread opened another
|
| 1048 | * file (dso) due to open file limit (RLIMIT_NOFILE).
|
| 1049 |
|
| 1050 | try_to_open_dso(dso, machine);
|
| 1051 |
|
| 1052 | if (dso__data(dso)->fd < 0) {
|
| 1053 | dso__data(dso)->status = DSO_DATA_STATUS_ERROR;
|
| 1054 | ret = dso__data(dso)->fd;
|
| 1055 | goto out;
|
| 1056 | }
|
| 1057 |
|
| 1058 | ret = pread(dso__data(dso)->fd, data, DSO__DATA_CACHE_SIZE, offset);
|
| 1059 | out:
|
| 1060 | mutex_unlock(dso__data_open_lock());
|
| 1061 | return ret;
|
| 1062 | }
|
| 1063 |
|
| 1064 | static struct dso_cache *dso_cache__populate(struct dso *dso,
|
| 1065 | struct machine *machine,
|
| 1066 | u64 offset, ssize_t *ret)
|
| 1067 | {
|
| 1068 | u64 cache_offset = offset & DSO__DATA_CACHE_MASK;
|
| 1069 | struct dso_cache *cache;
|
| 1070 | struct dso_cache *old;
|
| 1071 |
|
| 1072 | cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
|
| 1073 | if (!cache) {
|
| 1074 | *ret = -ENOMEM;
|
| 1075 | return NULL;
|
| 1076 | }
|
| 1077 | #ifdef HAVE_LIBBPF_SUPPORT
|
| 1078 | if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO)
|
| 1079 | *ret = bpf_read(dso, cache_offset, cache->data);
|
| 1080 | else
|
| 1081 | #endif
|
| 1082 | if (dso__binary_type(dso) == DSO_BINARY_TYPE__OOL)
|
| 1083 | *ret = DSO__DATA_CACHE_SIZE;
|
| 1084 | else
|
| 1085 | *ret = file_read(dso, machine, cache_offset, cache->data);
|
| 1086 |
|
| 1087 | if (*ret <= 0) {
|
| 1088 | free(cache);
|
| 1089 | return NULL;
|
| 1090 | }
|
| 1091 |
|
| 1092 | cache->offset = cache_offset;
|
| 1093 | cache->size = *ret;
|
| 1094 |
|
| 1095 | old = dso_cache__insert(dso, cache);
|
| 1096 | if (old) {
|
| 1097 |
|
| 1098 | free(cache);
|
| 1099 | cache = old;
|
| 1100 | }
|
| 1101 |
|
| 1102 | return cache;
|
| 1103 | }
|
| 1104 |
|
| 1105 | static struct dso_cache *dso_cache__find(struct dso *dso,
|
| 1106 | struct machine *machine,
|
| 1107 | u64 offset,
|
| 1108 | ssize_t *ret)
|
| 1109 | {
|
| 1110 | struct dso_cache *cache = __dso_cache__find(dso, offset);
|
| 1111 |
|
| 1112 | return cache ? cache : dso_cache__populate(dso, machine, offset, ret);
|
| 1113 | }
|
| 1114 |
|
| 1115 | static ssize_t dso_cache_io(struct dso *dso, struct machine *machine,
|
| 1116 | u64 offset, u8 *data, ssize_t size, bool out)
|
| 1117 | {
|
| 1118 | struct dso_cache *cache;
|
| 1119 | ssize_t ret = 0;
|
| 1120 |
|
| 1121 | cache = dso_cache__find(dso, machine, offset, &ret);
|
| 1122 | if (!cache)
|
| 1123 | return ret;
|
| 1124 |
|
| 1125 | return dso_cache__memcpy(cache, offset, data, size, out);
|
| 1126 | }
|
| 1127 |
|
| 1128 | |
| 1129 | * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks
|
| 1130 | * in the rb_tree. Any read to already cached data is served
|
| 1131 | * by cached data. Writes update the cache only, not the backing file.
|
| 1132 |
|
| 1133 | static ssize_t cached_io(struct dso *dso, struct machine *machine,
|
| 1134 | u64 offset, u8 *data, ssize_t size, bool out)
|
| 1135 | {
|
| 1136 | ssize_t r = 0;
|
| 1137 | u8 *p = data;
|
| 1138 |
|
| 1139 | do {
|
| 1140 | ssize_t ret;
|
| 1141 |
|
| 1142 | ret = dso_cache_io(dso, machine, offset, p, size, out);
|
| 1143 | if (ret < 0)
|
| 1144 | return ret;
|
| 1145 |
|
| 1146 |
|
| 1147 | if (!ret)
|
| 1148 | break;
|
| 1149 |
|
| 1150 | BUG_ON(ret > size);
|
| 1151 |
|
| 1152 | r += ret;
|
| 1153 | p += ret;
|
| 1154 | offset += ret;
|
| 1155 | size -= ret;
|
| 1156 |
|
| 1157 | } while (size);
|
| 1158 |
|
| 1159 | return r;
|
| 1160 | }
|
| 1161 |
|
| 1162 | static int file_size(struct dso *dso, struct machine *machine)
|
| 1163 | {
|
| 1164 | int ret = 0;
|
| 1165 | struct stat st;
|
| 1166 |
|
| 1167 | mutex_lock(dso__data_open_lock());
|
| 1168 |
|
| 1169 | |
| 1170 | * dso__data(dso)->fd might be closed if other thread opened another
|
| 1171 | * file (dso) due to open file limit (RLIMIT_NOFILE).
|
| 1172 |
|
| 1173 | try_to_open_dso(dso, machine);
|
| 1174 |
|
| 1175 | if (dso__data(dso)->fd < 0) {
|
| 1176 | dso__data(dso)->status = DSO_DATA_STATUS_ERROR;
|
| 1177 | ret = dso__data(dso)->fd;
|
| 1178 | goto out;
|
| 1179 | }
|
| 1180 |
|
| 1181 | if (fstat(dso__data(dso)->fd, &st) < 0) {
|
| 1182 | ret = -errno;
|
| 1183 | pr_err("dso cache fstat failed: %m\n");
|
| 1184 | dso__data(dso)->status = DSO_DATA_STATUS_ERROR;
|
| 1185 | goto out;
|
| 1186 | }
|
| 1187 | dso__data(dso)->file_size = st.st_size;
|
| 1188 |
|
| 1189 | out:
|
| 1190 | mutex_unlock(dso__data_open_lock());
|
| 1191 | return ret;
|
| 1192 | }
|
| 1193 |
|
| 1194 | int dso__data_file_size(struct dso *dso, struct machine *machine)
|
| 1195 | {
|
| 1196 | if (dso__data(dso)->file_size)
|
| 1197 | return 0;
|
| 1198 |
|
| 1199 | if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR)
|
| 1200 | return -1;
|
| 1201 | #ifdef HAVE_LIBBPF_SUPPORT
|
| 1202 | if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO)
|
| 1203 | return bpf_size(dso);
|
| 1204 | #endif
|
| 1205 | return file_size(dso, machine);
|
| 1206 | }
|
| 1207 |
|
| 1208 | |
| 1209 | * dso__data_size - Return dso data size
|
| 1210 | * @dso: dso object
|
| 1211 | * @machine: machine object
|
| 1212 | *
|
| 1213 | * Return: dso data size
|
| 1214 |
|
| 1215 | off_t dso__data_size(struct dso *dso, struct machine *machine)
|
| 1216 | {
|
| 1217 | if (dso__data_file_size(dso, machine))
|
| 1218 | return -1;
|
| 1219 |
|
| 1220 |
|
| 1221 | return dso__data(dso)->file_size;
|
| 1222 | }
|
| 1223 |
|
| 1224 | static ssize_t data_read_write_offset(struct dso *dso, struct machine *machine,
|
| 1225 | u64 offset, u8 *data, ssize_t size,
|
| 1226 | bool out)
|
| 1227 | {
|
| 1228 | if (dso__data_file_size(dso, machine))
|
| 1229 | return -1;
|
| 1230 |
|
| 1231 |
|
| 1232 | if (offset > dso__data(dso)->file_size)
|
| 1233 | return -1;
|
| 1234 |
|
| 1235 | if (offset + size < offset)
|
| 1236 | return -1;
|
| 1237 |
|
| 1238 | return cached_io(dso, machine, offset, data, size, out);
|
| 1239 | }
|
| 1240 |
|
| 1241 | |
| 1242 | * dso__data_read_offset - Read data from dso file offset
|
| 1243 | * @dso: dso object
|
| 1244 | * @machine: machine object
|
| 1245 | * @offset: file offset
|
| 1246 | * @data: buffer to store data
|
| 1247 | * @size: size of the @data buffer
|
| 1248 | *
|
| 1249 | * External interface to read data from dso file offset. Open
|
| 1250 | * dso data file and use cached_read to get the data.
|
| 1251 |
|
| 1252 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
|
| 1253 | u64 offset, u8 *data, ssize_t size)
|
| 1254 | {
|
| 1255 | if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR)
|
| 1256 | return -1;
|
| 1257 |
|
| 1258 | return data_read_write_offset(dso, machine, offset, data, size, true);
|
| 1259 | }
|
| 1260 |
|
| 1261 | static enum dso_swap_type dso_swap_type__from_elf_data(unsigned char eidata)
|
| 1262 | {
|
| 1263 | static const unsigned int endian = 1;
|
| 1264 |
|
| 1265 | switch (eidata) {
|
| 1266 | case ELFDATA2LSB:
|
| 1267 |
|
| 1268 | return (*(unsigned char const *)&endian != 1) ? DSO_SWAP__YES : DSO_SWAP__NO;
|
| 1269 | case ELFDATA2MSB:
|
| 1270 |
|
| 1271 | return (*(unsigned char const *)&endian != 0) ? DSO_SWAP__YES : DSO_SWAP__NO;
|
| 1272 | default:
|
| 1273 | return DSO_SWAP__UNSET;
|
| 1274 | }
|
| 1275 | }
|
| 1276 |
|
| 1277 |
|
| 1278 | uint16_t dso__read_e_machine_endian(struct dso *optional_dso, int fd, uint32_t *e_flags,
|
| 1279 | bool *is_big_endian)
|
| 1280 | {
|
| 1281 | uint16_t e_machine = EM_NONE;
|
| 1282 | unsigned char e_ident[EI_NIDENT];
|
| 1283 | enum dso_swap_type swap_type;
|
| 1284 | bool need_e_flags;
|
| 1285 |
|
| 1286 | if (e_flags)
|
| 1287 | *e_flags = 0;
|
| 1288 |
|
| 1289 | {
|
| 1290 | _Static_assert(offsetof(Elf32_Ehdr, e_ident) == 0, "Unexpected offset");
|
| 1291 | _Static_assert(offsetof(Elf64_Ehdr, e_ident) == 0, "Unexpected offset");
|
| 1292 | }
|
| 1293 | if (pread(fd, &e_ident, sizeof(e_ident), 0) != sizeof(e_ident))
|
| 1294 | return EM_NONE; |
| 1295 |
|
| 1296 | if (memcmp(e_ident, ELFMAG, SELFMAG) != 0)
|
| 1297 | return EM_NONE; |
| 1298 |
|
| 1299 | if (e_ident[EI_CLASS] == ELFCLASSNONE || e_ident[EI_CLASS] >= ELFCLASSNUM)
|
| 1300 | return EM_NONE; |
| 1301 |
|
| 1302 | if (e_ident[EI_VERSION] != EV_CURRENT)
|
| 1303 | return EM_NONE; |
| 1304 |
|
| 1305 | swap_type = dso_swap_type__from_elf_data(e_ident[EI_DATA]);
|
| 1306 | if (swap_type == DSO_SWAP__UNSET)
|
| 1307 | return EM_NONE; |
| 1308 |
|
| 1309 | if (is_big_endian)
|
| 1310 | *is_big_endian = (e_ident[EI_DATA] == ELFDATA2MSB);
|
| 1311 |
|
| 1312 |
|
| 1313 | if (optional_dso) {
|
| 1314 | assert(dso__needs_swap(optional_dso) == DSO_SWAP__UNSET ||
|
| 1315 | dso__needs_swap(optional_dso) == swap_type);
|
| 1316 | dso__set_needs_swap(optional_dso, swap_type);
|
| 1317 | }
|
| 1318 |
|
| 1319 | {
|
| 1320 | _Static_assert(offsetof(Elf32_Ehdr, e_machine) == 18, "Unexpected offset");
|
| 1321 | _Static_assert(offsetof(Elf64_Ehdr, e_machine) == 18, "Unexpected offset");
|
| 1322 | }
|
| 1323 | if (pread(fd, &e_machine, sizeof(e_machine), 18) != sizeof(e_machine))
|
| 1324 | return EM_NONE; |
| 1325 |
|
| 1326 | e_machine = DSO_SWAP_TYPE__SWAP(swap_type, uint16_t, e_machine);
|
| 1327 | if (e_machine >= EM_NUM)
|
| 1328 | return EM_NONE; |
| 1329 |
|
| 1330 | #ifdef NDEBUG
|
| 1331 |
|
| 1332 | need_e_flags = e_flags && e_machine == EM_CSKY;
|
| 1333 | #else
|
| 1334 |
|
| 1335 | need_e_flags = e_flags != NULL;
|
| 1336 | #endif
|
| 1337 | if (need_e_flags) {
|
| 1338 | off_t offset = e_ident[EI_CLASS] == ELFCLASS32
|
| 1339 | ? offsetof(Elf32_Ehdr, e_flags)
|
| 1340 | : offsetof(Elf64_Ehdr, e_flags);
|
| 1341 |
|
| 1342 | if (pread(fd, e_flags, sizeof(*e_flags), offset) != sizeof(*e_flags)) {
|
| 1343 | *e_flags = 0;
|
| 1344 | return EM_NONE; |
| 1345 | }
|
| 1346 | }
|
| 1347 | return e_machine;
|
| 1348 | }
|
| 1349 |
|
| 1350 | uint16_t dso__e_machine_endian(struct dso *dso, struct machine *machine, uint32_t *e_flags,
|
| 1351 | bool *is_big_endian)
|
| 1352 | {
|
| 1353 | uint16_t e_machine = EM_NONE;
|
| 1354 | int fd;
|
| 1355 |
|
| 1356 | switch (dso__binary_type(dso)) {
|
| 1357 | case DSO_BINARY_TYPE__KALLSYMS:
|
| 1358 | case DSO_BINARY_TYPE__GUEST_KALLSYMS:
|
| 1359 | case DSO_BINARY_TYPE__VMLINUX:
|
| 1360 | case DSO_BINARY_TYPE__GUEST_VMLINUX:
|
| 1361 | case DSO_BINARY_TYPE__GUEST_KMODULE:
|
| 1362 | case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
|
| 1363 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
|
| 1364 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
|
| 1365 | case DSO_BINARY_TYPE__KCORE:
|
| 1366 | case DSO_BINARY_TYPE__GUEST_KCORE:
|
| 1367 | case DSO_BINARY_TYPE__BPF_PROG_INFO:
|
| 1368 | case DSO_BINARY_TYPE__BPF_IMAGE:
|
| 1369 | case DSO_BINARY_TYPE__OOL:
|
| 1370 | case DSO_BINARY_TYPE__JAVA_JIT:
|
| 1371 | if (is_big_endian) {
|
| 1372 | *is_big_endian = perf_arch_is_big_endian(
|
| 1373 | machine && machine->env ? perf_env__arch(machine->env) : NULL);
|
| 1374 | }
|
| 1375 | return perf_env__e_machine(machine ? machine->env : NULL, e_flags);
|
| 1376 | case DSO_BINARY_TYPE__DEBUGLINK:
|
| 1377 | case DSO_BINARY_TYPE__BUILD_ID_CACHE:
|
| 1378 | case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
|
| 1379 | case DSO_BINARY_TYPE__GNU_DEBUGDATA:
|
| 1380 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
|
| 1381 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
|
| 1382 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
|
| 1383 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
|
| 1384 | case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO:
|
| 1385 | case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
|
| 1386 | break;
|
| 1387 | case DSO_BINARY_TYPE__NOT_FOUND:
|
| 1388 | default:
|
| 1389 | if (e_flags)
|
| 1390 | *e_flags = 0;
|
| 1391 | return EM_NONE;
|
| 1392 | }
|
| 1393 |
|
| 1394 | mutex_lock(dso__data_open_lock());
|
| 1395 |
|
| 1396 | |
| 1397 | * dso__data(dso)->fd might be closed if other thread opened another
|
| 1398 | * file (dso) due to open file limit (RLIMIT_NOFILE).
|
| 1399 |
|
| 1400 | try_to_open_dso(dso, machine);
|
| 1401 | fd = dso__data(dso)->fd;
|
| 1402 | if (fd >= 0)
|
| 1403 | e_machine = dso__read_e_machine_endian(dso, fd, e_flags, is_big_endian);
|
| 1404 | else if (e_flags)
|
| 1405 | *e_flags = 0;
|
| 1406 |
|
| 1407 | mutex_unlock(dso__data_open_lock());
|
| 1408 | return e_machine;
|
| 1409 | }
|
| 1410 |
|
| 1411 | |
| 1412 | * dso__data_read_addr - Read data from dso address
|
| 1413 | * @dso: dso object
|
| 1414 | * @machine: machine object
|
| 1415 | * @add: virtual memory address
|
| 1416 | * @data: buffer to store data
|
| 1417 | * @size: size of the @data buffer
|
| 1418 | *
|
| 1419 | * External interface to read data from dso address.
|
| 1420 |
|
| 1421 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
|
| 1422 | struct machine *machine, u64 addr,
|
| 1423 | u8 *data, ssize_t size)
|
| 1424 | {
|
| 1425 | u64 offset = map__map_ip(map, addr);
|
| 1426 |
|
| 1427 | return dso__data_read_offset(dso, machine, offset, data, size);
|
| 1428 | }
|
| 1429 |
|
| 1430 | |
| 1431 | * dso__data_write_cache_offs - Write data to dso data cache at file offset
|
| 1432 | * @dso: dso object
|
| 1433 | * @machine: machine object
|
| 1434 | * @offset: file offset
|
| 1435 | * @data: buffer to write
|
| 1436 | * @size: size of the @data buffer
|
| 1437 | *
|
| 1438 | * Write into the dso file data cache, but do not change the file itself.
|
| 1439 |
|
| 1440 | ssize_t dso__data_write_cache_offs(struct dso *dso, struct machine *machine,
|
| 1441 | u64 offset, const u8 *data_in, ssize_t size)
|
| 1442 | {
|
| 1443 | u8 *data = (u8 *)data_in;
|
| 1444 |
|
| 1445 | if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR)
|
| 1446 | return -1;
|
| 1447 |
|
| 1448 | return data_read_write_offset(dso, machine, offset, data, size, false);
|
| 1449 | }
|
| 1450 |
|
| 1451 | |
| 1452 | * dso__data_write_cache_addr - Write data to dso data cache at dso address
|
| 1453 | * @dso: dso object
|
| 1454 | * @machine: machine object
|
| 1455 | * @add: virtual memory address
|
| 1456 | * @data: buffer to write
|
| 1457 | * @size: size of the @data buffer
|
| 1458 | *
|
| 1459 | * External interface to write into the dso file data cache, but do not change
|
| 1460 | * the file itself.
|
| 1461 |
|
| 1462 | ssize_t dso__data_write_cache_addr(struct dso *dso, struct map *map,
|
| 1463 | struct machine *machine, u64 addr,
|
| 1464 | const u8 *data, ssize_t size)
|
| 1465 | {
|
| 1466 | u64 offset = map__map_ip(map, addr);
|
| 1467 |
|
| 1468 | return dso__data_write_cache_offs(dso, machine, offset, data, size);
|
| 1469 | }
|
| 1470 |
|
| 1471 | struct map *dso__new_map(const char *name)
|
| 1472 | {
|
| 1473 | struct map *map = NULL;
|
| 1474 | struct dso *dso = dso__new(name);
|
| 1475 |
|
| 1476 | if (dso) {
|
| 1477 | map = map__new2(0, dso);
|
| 1478 | dso__put(dso);
|
| 1479 | }
|
| 1480 |
|
| 1481 | return map;
|
| 1482 | }
|
| 1483 |
|
| 1484 | struct dso *machine__findnew_kernel(struct machine *machine, const char *name,
|
| 1485 | const char *short_name, int dso_type)
|
| 1486 | {
|
| 1487 | |
| 1488 | * The kernel dso could be created by build_id processing.
|
| 1489 |
|
| 1490 | struct dso *dso = machine__findnew_dso(machine, name);
|
| 1491 |
|
| 1492 | |
| 1493 | * We need to run this in all cases, since during the build_id
|
| 1494 | * processing we had no idea this was the kernel dso.
|
| 1495 |
|
| 1496 | if (dso != NULL) {
|
| 1497 | dso__set_short_name(dso, short_name, false);
|
| 1498 | dso__set_kernel(dso, dso_type);
|
| 1499 | }
|
| 1500 |
|
| 1501 | return dso;
|
| 1502 | }
|
| 1503 |
|
| 1504 | static void __dso__set_long_name_id(struct dso *dso, const char *name, bool name_allocated)
|
| 1505 | {
|
| 1506 | if (dso__long_name_allocated(dso))
|
| 1507 | free((char *)dso__long_name(dso));
|
| 1508 |
|
| 1509 | RC_CHK_ACCESS(dso)->long_name = name;
|
| 1510 | RC_CHK_ACCESS(dso)->long_name_len = strlen(name);
|
| 1511 | dso__set_long_name_allocated(dso, name_allocated);
|
| 1512 | }
|
| 1513 |
|
| 1514 | static void dso__set_long_name_id(struct dso *dso, const char *name, bool name_allocated)
|
| 1515 | {
|
| 1516 | struct dsos *dsos = dso__dsos(dso);
|
| 1517 |
|
| 1518 | if (name == NULL)
|
| 1519 | return;
|
| 1520 |
|
| 1521 | if (dsos) {
|
| 1522 | |
| 1523 | * Need to avoid re-sorting the dsos breaking by non-atomically
|
| 1524 | * renaming the dso.
|
| 1525 |
|
| 1526 | down_write(&dsos->lock);
|
| 1527 | __dso__set_long_name_id(dso, name, name_allocated);
|
| 1528 | dsos->sorted = false;
|
| 1529 | up_write(&dsos->lock);
|
| 1530 | } else {
|
| 1531 | __dso__set_long_name_id(dso, name, name_allocated);
|
| 1532 | }
|
| 1533 | }
|
| 1534 |
|
| 1535 | static int __dso_id__cmp(const struct dso_id *a, const struct dso_id *b)
|
| 1536 | {
|
| 1537 | if (a->mmap2_valid && b->mmap2_valid) {
|
| 1538 | if (a->maj > b->maj) return -1;
|
| 1539 | if (a->maj < b->maj) return 1;
|
| 1540 |
|
| 1541 | if (a->min > b->min) return -1;
|
| 1542 | if (a->min < b->min) return 1;
|
| 1543 |
|
| 1544 | if (a->ino > b->ino) return -1;
|
| 1545 | if (a->ino < b->ino) return 1;
|
| 1546 | }
|
| 1547 | if (a->mmap2_ino_generation_valid && b->mmap2_ino_generation_valid) {
|
| 1548 | if (a->ino_generation > b->ino_generation) return -1;
|
| 1549 | if (a->ino_generation < b->ino_generation) return 1;
|
| 1550 | }
|
| 1551 | if (build_id__is_defined(&a->build_id) && build_id__is_defined(&b->build_id)) {
|
| 1552 | if (a->build_id.size != b->build_id.size)
|
| 1553 | return a->build_id.size < b->build_id.size ? -1 : 1;
|
| 1554 | return memcmp(a->build_id.data, b->build_id.data, a->build_id.size);
|
| 1555 | }
|
| 1556 | return 0;
|
| 1557 | }
|
| 1558 |
|
| 1559 | const struct dso_id dso_id_empty = {
|
| 1560 | {
|
| 1561 | .maj = 0,
|
| 1562 | .min = 0,
|
| 1563 | .ino = 0,
|
| 1564 | .ino_generation = 0,
|
| 1565 | },
|
| 1566 | .mmap2_valid = false,
|
| 1567 | .mmap2_ino_generation_valid = false,
|
| 1568 | {
|
| 1569 | .size = 0,
|
| 1570 | }
|
| 1571 | };
|
| 1572 |
|
| 1573 | void __dso__improve_id(struct dso *dso, const struct dso_id *id)
|
| 1574 | {
|
| 1575 | struct dsos *dsos = dso__dsos(dso);
|
| 1576 | struct dso_id *dso_id = dso__id(dso);
|
| 1577 | bool changed = false;
|
| 1578 |
|
| 1579 |
|
| 1580 |
|
| 1581 | if (id->mmap2_valid && !dso_id->mmap2_valid) {
|
| 1582 | dso_id->maj = id->maj;
|
| 1583 | dso_id->min = id->min;
|
| 1584 | dso_id->ino = id->ino;
|
| 1585 | dso_id->mmap2_valid = true;
|
| 1586 | changed = true;
|
| 1587 | }
|
| 1588 | if (id->mmap2_ino_generation_valid && !dso_id->mmap2_ino_generation_valid) {
|
| 1589 | dso_id->ino_generation = id->ino_generation;
|
| 1590 | dso_id->mmap2_ino_generation_valid = true;
|
| 1591 | changed = true;
|
| 1592 | }
|
| 1593 | if (build_id__is_defined(&id->build_id) && !build_id__is_defined(&dso_id->build_id)) {
|
| 1594 | dso_id->build_id = id->build_id;
|
| 1595 | changed = true;
|
| 1596 | }
|
| 1597 | if (changed && dsos)
|
| 1598 | dsos->sorted = false;
|
| 1599 | }
|
| 1600 |
|
| 1601 | int dso_id__cmp(const struct dso_id *a, const struct dso_id *b)
|
| 1602 | {
|
| 1603 | if (a == &dso_id_empty || b == &dso_id_empty) {
|
| 1604 |
|
| 1605 | return 0;
|
| 1606 | }
|
| 1607 |
|
| 1608 | return __dso_id__cmp(a, b);
|
| 1609 | }
|
| 1610 |
|
| 1611 | int dso__cmp_id(struct dso *a, struct dso *b)
|
| 1612 | {
|
| 1613 | return __dso_id__cmp(dso__id(a), dso__id(b));
|
| 1614 | }
|
| 1615 |
|
| 1616 | void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
|
| 1617 | {
|
| 1618 | dso__set_long_name_id(dso, name, name_allocated);
|
| 1619 | }
|
| 1620 |
|
| 1621 | static void __dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
|
| 1622 | {
|
| 1623 | if (dso__short_name_allocated(dso))
|
| 1624 | free((char *)dso__short_name(dso));
|
| 1625 |
|
| 1626 | RC_CHK_ACCESS(dso)->short_name = name;
|
| 1627 | RC_CHK_ACCESS(dso)->short_name_len = strlen(name);
|
| 1628 | dso__set_short_name_allocated(dso, name_allocated);
|
| 1629 | }
|
| 1630 |
|
| 1631 | void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
|
| 1632 | {
|
| 1633 | struct dsos *dsos = dso__dsos(dso);
|
| 1634 |
|
| 1635 | if (name == NULL)
|
| 1636 | return;
|
| 1637 |
|
| 1638 | if (dsos) {
|
| 1639 | |
| 1640 | * Need to avoid re-sorting the dsos breaking by non-atomically
|
| 1641 | * renaming the dso.
|
| 1642 |
|
| 1643 | down_write(&dsos->lock);
|
| 1644 | __dso__set_short_name(dso, name, name_allocated);
|
| 1645 | dsos->sorted = false;
|
| 1646 | up_write(&dsos->lock);
|
| 1647 | } else {
|
| 1648 | __dso__set_short_name(dso, name, name_allocated);
|
| 1649 | }
|
| 1650 | }
|
| 1651 |
|
| 1652 | int dso__name_len(const struct dso *dso)
|
| 1653 | {
|
| 1654 | if (!dso)
|
| 1655 | return strlen("[unknown]");
|
| 1656 | if (verbose > 0)
|
| 1657 | return dso__long_name_len(dso);
|
| 1658 |
|
| 1659 | return dso__short_name_len(dso);
|
| 1660 | }
|
| 1661 |
|
| 1662 | bool dso__loaded(const struct dso *dso)
|
| 1663 | {
|
| 1664 | return RC_CHK_ACCESS(dso)->loaded;
|
| 1665 | }
|
| 1666 |
|
| 1667 | bool dso__sorted_by_name(const struct dso *dso)
|
| 1668 | {
|
| 1669 | return RC_CHK_ACCESS(dso)->sorted_by_name;
|
| 1670 | }
|
| 1671 |
|
| 1672 | void dso__set_sorted_by_name(struct dso *dso)
|
| 1673 | {
|
| 1674 | RC_CHK_ACCESS(dso)->sorted_by_name = true;
|
| 1675 | }
|
| 1676 |
|
| 1677 | struct dso *dso__new_id(const char *name, const struct dso_id *id)
|
| 1678 | {
|
| 1679 | RC_STRUCT(dso) *dso = zalloc(sizeof(*dso) + strlen(name) + 1);
|
| 1680 | struct dso *res;
|
| 1681 | struct dso_data *data;
|
| 1682 |
|
| 1683 | if (!dso)
|
| 1684 | return NULL;
|
| 1685 |
|
| 1686 | if (ADD_RC_CHK(res, dso)) {
|
| 1687 | strcpy(dso->name, name);
|
| 1688 | if (id)
|
| 1689 | dso->id = *id;
|
| 1690 | dso__set_long_name_id(res, dso->name, false);
|
| 1691 | dso__set_short_name(res, dso->name, false);
|
| 1692 | dso->symbols = RB_ROOT_CACHED;
|
| 1693 | dso->symbol_names = NULL;
|
| 1694 | dso->symbol_names_len = 0;
|
| 1695 | dso->inlined_nodes = RB_ROOT_CACHED;
|
| 1696 | dso->srclines = RB_ROOT_CACHED;
|
| 1697 | dso->data_types = RB_ROOT;
|
| 1698 | dso->global_vars = RB_ROOT;
|
| 1699 | dso->data.fd = -1;
|
| 1700 | dso->data.status = DSO_DATA_STATUS_UNKNOWN;
|
| 1701 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
|
| 1702 | dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
|
| 1703 | dso->is_64_bit = (sizeof(void *) == 8);
|
| 1704 | dso->loaded = 0;
|
| 1705 | dso->rel = 0;
|
| 1706 | dso->sorted_by_name = 0;
|
| 1707 | dso->has_srcline = 1;
|
| 1708 | dso->a2l_fails = 1;
|
| 1709 | dso->kernel = DSO_SPACE__USER;
|
| 1710 | dso->is_kmod = 0;
|
| 1711 | dso->needs_swap = DSO_SWAP__UNSET;
|
| 1712 | dso->comp = COMP_ID__NONE;
|
| 1713 | mutex_init(&dso->lock);
|
| 1714 | refcount_set(&dso->refcnt, 1);
|
| 1715 | data = &dso->data;
|
| 1716 | data->cache = RB_ROOT;
|
| 1717 | data->fd = -1;
|
| 1718 | data->status = DSO_DATA_STATUS_UNKNOWN;
|
| 1719 | INIT_LIST_HEAD(&data->open_entry);
|
| 1720 | #ifdef REFCNT_CHECKING
|
| 1721 | data->dso = NULL;
|
| 1722 | #endif
|
| 1723 | }
|
| 1724 | return res;
|
| 1725 | }
|
| 1726 |
|
| 1727 | struct dso *dso__new(const char *name)
|
| 1728 | {
|
| 1729 | return dso__new_id(name, NULL);
|
| 1730 | }
|
| 1731 |
|
| 1732 | void dso__delete(struct dso *dso)
|
| 1733 | {
|
| 1734 | if (dso__dsos(dso))
|
| 1735 | pr_err("DSO %s is still in rbtree when being deleted!\n", dso__long_name(dso));
|
| 1736 |
|
| 1737 |
|
| 1738 | inlines__tree_delete(&RC_CHK_ACCESS(dso)->inlined_nodes);
|
| 1739 | srcline__tree_delete(&RC_CHK_ACCESS(dso)->srclines);
|
| 1740 | symbols__delete(&RC_CHK_ACCESS(dso)->symbols);
|
| 1741 | RC_CHK_ACCESS(dso)->symbol_names_len = 0;
|
| 1742 | zfree(&RC_CHK_ACCESS(dso)->symbol_names);
|
| 1743 | annotated_data_type__tree_delete(dso__data_types(dso));
|
| 1744 | global_var_type__tree_delete(dso__global_vars(dso));
|
| 1745 |
|
| 1746 | if (RC_CHK_ACCESS(dso)->short_name_allocated) {
|
| 1747 | zfree((char **)&RC_CHK_ACCESS(dso)->short_name);
|
| 1748 | RC_CHK_ACCESS(dso)->short_name_allocated = false;
|
| 1749 | }
|
| 1750 |
|
| 1751 | if (RC_CHK_ACCESS(dso)->long_name_allocated) {
|
| 1752 | zfree((char **)&RC_CHK_ACCESS(dso)->long_name);
|
| 1753 | RC_CHK_ACCESS(dso)->long_name_allocated = false;
|
| 1754 | }
|
| 1755 |
|
| 1756 | dso__data_close(dso);
|
| 1757 | auxtrace_cache__free(RC_CHK_ACCESS(dso)->auxtrace_cache);
|
| 1758 | dso_cache__free(dso);
|
| 1759 | dso__free_a2l(dso);
|
| 1760 | dso__free_libdw(dso);
|
| 1761 | dso__free_symsrc_filename(dso);
|
| 1762 | nsinfo__zput(RC_CHK_ACCESS(dso)->nsinfo);
|
| 1763 | mutex_destroy(dso__lock(dso));
|
| 1764 | RC_CHK_FREE(dso);
|
| 1765 | }
|
| 1766 |
|
| 1767 | struct dso *dso__get(struct dso *dso)
|
| 1768 | {
|
| 1769 | struct dso *result;
|
| 1770 |
|
| 1771 | if (RC_CHK_GET(result, dso))
|
| 1772 | refcount_inc(&RC_CHK_ACCESS(dso)->refcnt);
|
| 1773 |
|
| 1774 | return result;
|
| 1775 | }
|
| 1776 |
|
| 1777 | void dso__put(struct dso *dso)
|
| 1778 | {
|
| 1779 | #ifdef REFCNT_CHECKING
|
| 1780 | if (dso && dso__data(dso) && refcount_read(&RC_CHK_ACCESS(dso)->refcnt) == 2)
|
| 1781 | dso__data_close(dso);
|
| 1782 | #endif
|
| 1783 | if (dso && refcount_dec_and_test(&RC_CHK_ACCESS(dso)->refcnt))
|
| 1784 | dso__delete(dso);
|
| 1785 | else
|
| 1786 | RC_CHK_PUT(dso);
|
| 1787 | }
|
| 1788 |
|
| 1789 | int dso__swap_init(struct dso *dso, unsigned char eidata)
|
| 1790 | {
|
| 1791 | enum dso_swap_type type = dso_swap_type__from_elf_data(eidata);
|
| 1792 |
|
| 1793 | dso__set_needs_swap(dso, type);
|
| 1794 | if (type == DSO_SWAP__UNSET) {
|
| 1795 | pr_err("unrecognized DSO data encoding %d\n", eidata);
|
| 1796 | return -EINVAL;
|
| 1797 | }
|
| 1798 | return 0;
|
| 1799 | }
|
| 1800 |
|
| 1801 | void dso__set_build_id(struct dso *dso, const struct build_id *bid)
|
| 1802 | {
|
| 1803 | dso__id(dso)->build_id = *bid;
|
| 1804 | }
|
| 1805 |
|
| 1806 | bool dso__build_id_equal(const struct dso *dso, const struct build_id *bid)
|
| 1807 | {
|
| 1808 | const struct build_id *dso_bid = dso__bid(dso);
|
| 1809 |
|
| 1810 | if (dso_bid->size > bid->size && dso_bid->size == BUILD_ID_SIZE) {
|
| 1811 | |
| 1812 | * For the backward compatibility, it allows a build-id has
|
| 1813 | * trailing zeros.
|
| 1814 |
|
| 1815 | return !memcmp(dso_bid->data, bid->data, bid->size) &&
|
| 1816 | !memchr_inv(&dso_bid->data[bid->size], 0,
|
| 1817 | dso_bid->size - bid->size);
|
| 1818 | }
|
| 1819 |
|
| 1820 | return dso_bid->size == bid->size &&
|
| 1821 | memcmp(dso_bid->data, bid->data, dso_bid->size) == 0;
|
| 1822 | }
|
| 1823 |
|
| 1824 | void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
|
| 1825 | {
|
| 1826 | char path[PATH_MAX];
|
| 1827 | struct build_id bid = { .size = 0, };
|
| 1828 |
|
| 1829 | if (machine__is_default_guest(machine))
|
| 1830 | return;
|
| 1831 | snprintf(path, sizeof(path), "%s/sys/kernel/notes", machine->root_dir);
|
| 1832 | sysfs__read_build_id(path, &bid);
|
| 1833 | dso__set_build_id(dso, &bid);
|
| 1834 | }
|
| 1835 |
|
| 1836 | int dso__kernel_module_get_build_id(struct dso *dso,
|
| 1837 | const char *root_dir)
|
| 1838 | {
|
| 1839 | char filename[PATH_MAX];
|
| 1840 | struct build_id bid = { .size = 0, };
|
| 1841 | |
| 1842 | * kernel module short names are of the form "[module]" and
|
| 1843 | * we need just "module" here.
|
| 1844 |
|
| 1845 | const char *name = dso__short_name(dso) + 1;
|
| 1846 |
|
| 1847 | snprintf(filename, sizeof(filename),
|
| 1848 | "%s/sys/module/%.*s/notes/.note.gnu.build-id",
|
| 1849 | root_dir, (int)strlen(name) - 1, name);
|
| 1850 |
|
| 1851 | sysfs__read_build_id(filename, &bid);
|
| 1852 | dso__set_build_id(dso, &bid);
|
| 1853 | return 0;
|
| 1854 | }
|
| 1855 |
|
| 1856 | static size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
|
| 1857 | {
|
| 1858 | char sbuild_id[SBUILD_ID_SIZE];
|
| 1859 |
|
| 1860 | build_id__snprintf(dso__bid(dso), sbuild_id, sizeof(sbuild_id));
|
| 1861 | return fprintf(fp, "%s", sbuild_id);
|
| 1862 | }
|
| 1863 |
|
| 1864 | size_t dso__fprintf(struct dso *dso, FILE *fp)
|
| 1865 | {
|
| 1866 | struct rb_node *nd;
|
| 1867 | size_t ret = fprintf(fp, "dso: %s (", dso__short_name(dso));
|
| 1868 |
|
| 1869 | if (dso__short_name(dso) != dso__long_name(dso))
|
| 1870 | ret += fprintf(fp, "%s, ", dso__long_name(dso));
|
| 1871 | ret += fprintf(fp, "%sloaded, ", dso__loaded(dso) ? "" : "NOT ");
|
| 1872 | ret += dso__fprintf_buildid(dso, fp);
|
| 1873 | ret += fprintf(fp, ")\n");
|
| 1874 | for (nd = rb_first_cached(dso__symbols(dso)); nd; nd = rb_next(nd)) {
|
| 1875 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
|
| 1876 | ret += symbol__fprintf(pos, fp);
|
| 1877 | }
|
| 1878 |
|
| 1879 | return ret;
|
| 1880 | }
|
| 1881 |
|
| 1882 | enum dso_type dso__type(struct dso *dso, struct machine *machine)
|
| 1883 | {
|
| 1884 | int fd = -1;
|
| 1885 | enum dso_type type = DSO__TYPE_UNKNOWN;
|
| 1886 |
|
| 1887 | if (dso__data_get_fd(dso, machine, &fd)) {
|
| 1888 | type = dso__type_fd(fd);
|
| 1889 | dso__data_put_fd(dso);
|
| 1890 | }
|
| 1891 |
|
| 1892 | return type;
|
| 1893 | }
|
| 1894 |
|
| 1895 | int dso__strerror_load(struct dso *dso, char *buf, size_t buflen)
|
| 1896 | {
|
| 1897 | int idx, errnum = *dso__load_errno(dso);
|
| 1898 | |
| 1899 | * This must have a same ordering as the enum dso_load_errno.
|
| 1900 |
|
| 1901 | static const char *dso_load__error_str[] = {
|
| 1902 | "Internal tools/perf/ library error",
|
| 1903 | "Invalid ELF file",
|
| 1904 | "Can not read build id",
|
| 1905 | "Mismatching build id",
|
| 1906 | "Decompression failure",
|
| 1907 | };
|
| 1908 |
|
| 1909 | BUG_ON(buflen == 0);
|
| 1910 |
|
| 1911 | if (errnum >= 0) {
|
| 1912 | errno = errnum;
|
| 1913 | scnprintf(buf, buflen, "%m");
|
| 1914 |
|
| 1915 | return 0;
|
| 1916 | }
|
| 1917 |
|
| 1918 | if (errnum < __DSO_LOAD_ERRNO__START || errnum >= __DSO_LOAD_ERRNO__END)
|
| 1919 | return -1;
|
| 1920 |
|
| 1921 | idx = errnum - __DSO_LOAD_ERRNO__START;
|
| 1922 | scnprintf(buf, buflen, "%s", dso_load__error_str[idx]);
|
| 1923 | return 0;
|
| 1924 | }
|
| 1925 |
|
| 1926 | bool perf_pid_map_tid(const char *dso_name, int *tid)
|
| 1927 | {
|
| 1928 | return sscanf(dso_name, "/tmp/perf-%d.map", tid) == 1;
|
| 1929 | }
|
| 1930 |
|
| 1931 | bool is_perf_pid_map_name(const char *dso_name)
|
| 1932 | {
|
| 1933 | int tid;
|
| 1934 |
|
| 1935 | return perf_pid_map_tid(dso_name, &tid);
|
| 1936 | }
|
| 1937 |
|
| 1938 | struct find_file_offset_data {
|
| 1939 | u64 ip;
|
| 1940 | u64 offset;
|
| 1941 | };
|
| 1942 |
|
| 1943 |
|
| 1944 | static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg)
|
| 1945 | {
|
| 1946 | struct find_file_offset_data *data = arg;
|
| 1947 |
|
| 1948 | if (start <= data->ip && data->ip < start + len) {
|
| 1949 | data->offset = pgoff + data->ip - start;
|
| 1950 | return 1;
|
| 1951 | }
|
| 1952 | return 0;
|
| 1953 | }
|
| 1954 |
|
| 1955 | static const u8 *__dso__read_symbol(struct dso *dso, const char *symfs_filename,
|
| 1956 | u64 start, size_t len,
|
| 1957 | u8 **out_buf, u64 *out_buf_len, bool *is_64bit)
|
| 1958 | {
|
| 1959 | struct nscookie nsc;
|
| 1960 | int fd;
|
| 1961 | ssize_t count;
|
| 1962 | struct find_file_offset_data data = {
|
| 1963 | .ip = start,
|
| 1964 | };
|
| 1965 | u8 *code_buf = NULL;
|
| 1966 | int saved_errno;
|
| 1967 |
|
| 1968 | nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
|
| 1969 | fd = open(symfs_filename, O_RDONLY | O_CLOEXEC);
|
| 1970 | saved_errno = errno;
|
| 1971 | nsinfo__mountns_exit(&nsc);
|
| 1972 | if (fd < 0) {
|
| 1973 | errno = saved_errno;
|
| 1974 | return NULL;
|
| 1975 | }
|
| 1976 | if (file__read_maps(fd, true, find_file_offset, &data, is_64bit) <= 0) {
|
| 1977 | close(fd);
|
| 1978 | errno = ENOENT;
|
| 1979 | return NULL;
|
| 1980 | }
|
| 1981 | code_buf = malloc(len);
|
| 1982 | if (code_buf == NULL) {
|
| 1983 | close(fd);
|
| 1984 | errno = ENOMEM;
|
| 1985 | return NULL;
|
| 1986 | }
|
| 1987 | count = pread(fd, code_buf, len, data.offset);
|
| 1988 | saved_errno = errno;
|
| 1989 | close(fd);
|
| 1990 | if ((u64)count != len) {
|
| 1991 | free(code_buf);
|
| 1992 | errno = saved_errno;
|
| 1993 | return NULL;
|
| 1994 | }
|
| 1995 | *out_buf = code_buf;
|
| 1996 | *out_buf_len = len;
|
| 1997 | return code_buf;
|
| 1998 | }
|
| 1999 |
|
| 2000 | |
| 2001 | * Read a symbol into memory for disassembly by a library like capstone of
|
| 2002 | * libLLVM. If memory is allocated out_buf holds it.
|
| 2003 |
|
| 2004 | const u8 *dso__read_symbol(struct dso *dso, const char *symfs_filename,
|
| 2005 | const struct map *map, const struct symbol *sym,
|
| 2006 | u8 **out_buf, u64 *out_buf_len, bool *is_64bit)
|
| 2007 | {
|
| 2008 | u64 start = map__rip_2objdump(map, sym->start);
|
| 2009 | u64 end = map__rip_2objdump(map, sym->end);
|
| 2010 | size_t len = end - start;
|
| 2011 |
|
| 2012 | *out_buf = NULL;
|
| 2013 | *out_buf_len = 0;
|
| 2014 | *is_64bit = false;
|
| 2015 |
|
| 2016 | if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_IMAGE) {
|
| 2017 | |
| 2018 | * Note, there is fallback BPF image disassembly in the objdump
|
| 2019 | * version but it currently does nothing.
|
| 2020 |
|
| 2021 | errno = EOPNOTSUPP;
|
| 2022 | return NULL;
|
| 2023 | }
|
| 2024 | if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) {
|
| 2025 | #ifdef HAVE_LIBBPF_SUPPORT
|
| 2026 | struct bpf_prog_info_node *info_node;
|
| 2027 | struct perf_bpil *info_linear;
|
| 2028 |
|
| 2029 | *is_64bit = sizeof(void *) == sizeof(u64);
|
| 2030 | info_node = perf_env__find_bpf_prog_info(dso__bpf_prog(dso)->env,
|
| 2031 | dso__bpf_prog(dso)->id);
|
| 2032 | if (!info_node) {
|
| 2033 | errno = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF;
|
| 2034 | return NULL;
|
| 2035 | }
|
| 2036 | info_linear = info_node->info_linear;
|
| 2037 | if (!(info_linear->arrays & (1UL << PERF_BPIL_JITED_INSNS))) {
|
| 2038 | errno = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF;
|
| 2039 | return NULL;
|
| 2040 | }
|
| 2041 | if (len > info_linear->info.jited_prog_len) {
|
| 2042 | pr_debug("BPF symbol length %zu exceeds jited_prog_len %u\n",
|
| 2043 | len, info_linear->info.jited_prog_len);
|
| 2044 | errno = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF;
|
| 2045 | return NULL;
|
| 2046 | }
|
| 2047 | *out_buf_len = len;
|
| 2048 | return (const u8 *)(uintptr_t)(info_linear->info.jited_prog_insns);
|
| 2049 | #else
|
| 2050 | pr_debug("No BPF program disassembly support\n");
|
| 2051 | errno = EOPNOTSUPP;
|
| 2052 | return NULL;
|
| 2053 | #endif
|
| 2054 | }
|
| 2055 | return __dso__read_symbol(dso, symfs_filename, start, len,
|
| 2056 | out_buf, out_buf_len, is_64bit);
|
| 2057 | }
|
| 2058 |
|
| 2059 | struct debuginfo *dso__debuginfo(struct dso *dso)
|
| 2060 | {
|
| 2061 | char *name;
|
| 2062 | bool decomp = false;
|
| 2063 | struct debuginfo *dinfo = NULL;
|
| 2064 |
|
| 2065 | mutex_lock(dso__lock(dso));
|
| 2066 |
|
| 2067 | name = dso__get_filename(dso, "", &decomp);
|
| 2068 | if (name)
|
| 2069 | dinfo = debuginfo__new(name);
|
| 2070 |
|
| 2071 | if (decomp)
|
| 2072 | unlink(name);
|
| 2073 |
|
| 2074 | mutex_unlock(dso__lock(dso));
|
| 2075 | free(name);
|
| 2076 | return dinfo;
|
| 2077 | }
|