bool dso__is_object_file(conststruct dso *dso)
{ switch (dso__binary_type(dso)) { case DSO_BINARY_TYPE__KALLSYMS: case DSO_BINARY_TYPE__GUEST_KALLSYMS: case DSO_BINARY_TYPE__JAVA_JIT: case DSO_BINARY_TYPE__BPF_PROG_INFO: case DSO_BINARY_TYPE__BPF_IMAGE: case DSO_BINARY_TYPE__OOL: returnfalse; case DSO_BINARY_TYPE__VMLINUX: case DSO_BINARY_TYPE__GUEST_VMLINUX: case DSO_BINARY_TYPE__DEBUGLINK: case DSO_BINARY_TYPE__BUILD_ID_CACHE: case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO: case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: case DSO_BINARY_TYPE__GNU_DEBUGDATA: case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: case DSO_BINARY_TYPE__GUEST_KMODULE: case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: case DSO_BINARY_TYPE__KCORE: case DSO_BINARY_TYPE__GUEST_KCORE: case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: case DSO_BINARY_TYPE__NOT_FOUND: default: returntrue;
}
}
int dso__read_binary_type_filename(conststruct dso *dso, enum dso_binary_type type, char *root_dir, char *filename, size_t size)
{ char build_id_hex[SBUILD_ID_SIZE]; int ret = 0;
size_t len;
if (!is_regular_file(filename)) {
ret = -1; break;
}
ret = filename__read_debuglink(filename, symfile, PATH_MAX); if (ret) break;
/* Check predefined locations where debug file might reside */
ret = -1; for (i = 0; i < ARRAY_SIZE(debuglink_paths); i++) {
snprintf(filename, size,
debuglink_paths[i], dso_dir, symfile); if (is_regular_file(filename)) {
ret = 0; break;
}
}
break;
} case DSO_BINARY_TYPE__BUILD_ID_CACHE: if (dso__build_id_filename(dso, filename, size, false) == NULL)
ret = -1; break;
case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: if (dso__build_id_filename(dso, filename, size, true) == NULL)
ret = -1; break;
case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
snprintf(filename + len, size - len, "%s.debug", dso__long_name(dso)); break;
case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
snprintf(filename + len, size - len, "%s", dso__long_name(dso)); break;
case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO: /* * Ubuntu can mixup /usr/lib with /lib, putting debuginfo in * /usr/lib/debug/lib when it is expected to be in * /usr/lib/debug/usr/lib
*/ if (strlen(dso__long_name(dso)) < 9 ||
strncmp(dso__long_name(dso), "/usr/lib/", 9)) {
ret = -1; break;
}
len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
snprintf(filename + len, size - len, "%s", dso__long_name(dso) + 4); break;
case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
{ constchar *last_slash;
size_t dir_size;
case DSO_BINARY_TYPE__VMLINUX: case DSO_BINARY_TYPE__GUEST_VMLINUX: case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: case DSO_BINARY_TYPE__GNU_DEBUGDATA:
__symbol__join_symfs(filename, size, dso__long_name(dso)); break;
case DSO_BINARY_TYPE__GUEST_KMODULE: case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
path__join3(filename, size, symbol_conf.symfs,
root_dir, dso__long_name(dso)); break;
case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
__symbol__join_symfs(filename, size, dso__long_name(dso)); break;
case DSO_BINARY_TYPE__KCORE: case DSO_BINARY_TYPE__GUEST_KCORE:
snprintf(filename, size, "%s", dso__long_name(dso)); break;
default: case DSO_BINARY_TYPE__KALLSYMS: case DSO_BINARY_TYPE__GUEST_KALLSYMS: case DSO_BINARY_TYPE__JAVA_JIT: case DSO_BINARY_TYPE__BPF_PROG_INFO: case DSO_BINARY_TYPE__BPF_IMAGE: case DSO_BINARY_TYPE__OOL: case DSO_BINARY_TYPE__NOT_FOUND:
ret = -1; break;
}
switch (mode) { case PERF_RECORD_MISC_USER: case PERF_RECORD_MISC_HYPERVISOR: case PERF_RECORD_MISC_GUEST_USER: returnfalse; /* Treat PERF_RECORD_MISC_CPUMODE_UNKNOWN as kernel */ default: if (kmod_path__parse(&m, pathname)) {
pr_err("Failed to check whether %s is a kernel module or not. Assume it is.",
pathname); returntrue;
}
}
int filename__decompress(constchar *name, char *pathname,
size_t len, int comp, int *err)
{ char tmpbuf[] = KMOD_DECOMP_NAME; int fd = -1;
/* * We have proper compression id for DSO and yet the file * behind the 'name' can still be plain uncompressed object. * * The reason is behind the logic we open the DSO object files, * when we try all possible 'debug' objects until we find the * data. So even if the DSO is represented by 'krava.xz' module, * we can end up here opening ~/.debug/....23432432/debug' file * which is not compressed. * * To keep this transparent, we detect this and return the file * descriptor to the uncompressed file.
*/ if (!compressions[comp].is_compressed(name)) return open(name, O_RDONLY);
int dso__decompress_kmodule_path(struct dso *dso, constchar *name, char *pathname, size_t len)
{ int fd = decompress_kmodule(dso, name, pathname, len);
close(fd); return fd >= 0 ? 0 : -1;
}
/* * Parses kernel module specified in @path and updates * @m argument like: * * @comp - true if @path contains supported compression suffix, * false otherwise * @kmod - true if @path contains '.ko' suffix in right position, * false otherwise * @name - if (@alloc_name && @kmod) is true, it contains strdup-ed base name * of the kernel module without suffixes, otherwise strudup-ed * base name of @path * @ext - if (@alloc_ext && @comp) is true, it contains strdup-ed string * the compression suffix * * Returns 0 if there's no strdup error, -ENOMEM otherwise.
*/ int __kmod_path__parse(struct kmod_path *m, constchar *path, bool alloc_name)
{ constchar *name = strrchr(path, '/'); constchar *ext = strrchr(path, '.'); bool is_simple_name = false;
memset(m, 0x0, sizeof(*m));
name = name ? name + 1 : path;
/* * '.' is also a valid character for module name. For example: * [aaa.bbb] is a valid module name. '[' should have higher * priority than '.ko' suffix. * * The kernel names are from machine__mmap_name. Such * name should belong to kernel itself, not kernel module.
*/ if (name[0] == '[') {
is_simple_name = true; if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) ||
(strncmp(name, "[guest.kernel.kallsyms", 22) == 0) ||
(strncmp(name, "[vdso]", 6) == 0) ||
(strncmp(name, "[vdso32]", 8) == 0) ||
(strncmp(name, "[vdsox32]", 9) == 0) ||
(strncmp(name, "[vsyscall]", 10) == 0)) {
m->kmod = false;
} else
m->kmod = true;
}
/* No extension, just return name. */ if ((ext == NULL) || is_simple_name) { if (alloc_name) {
m->name = strdup(name); return m->name ? 0 : -ENOMEM;
} return 0;
}
/* _KMODULE_COMP should be next to _KMODULE */ if (m->kmod && m->comp) {
dso__set_symtab_type(dso, dso__symtab_type(dso) + 1);
dso__set_comp(dso, m->comp);
}
/* * Global list of open DSOs and the counter.
*/ struct mutex _dso__data_open_lock; static LIST_HEAD(dso__data_open); staticlong dso__data_open_cnt GUARDED_BY(_dso__data_open_lock);
/* Allow half of the current open fd limit. */ if (getrlimit(RLIMIT_NOFILE, &l) == 0) { if (l.rlim_cur == RLIM_INFINITY)
limit = l.rlim_cur; else
limit = l.rlim_cur / 2;
} else {
pr_err("failed to get fd limit\n");
limit = 1;
}
return limit;
}
static rlim_t fd_limit;
/* * Used only by tests/dso-data.c to reset the environment * for tests. I dont expect we should change this during * standard runtime.
*/ void reset_fd_limit(void)
{
fd_limit = 0;
}
staticbool may_cache_fd(void) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
{ if (!fd_limit)
fd_limit = get_fd_limit();
if (fd_limit == RLIM_INFINITY) returntrue;
return fd_limit > (rlim_t) dso__data_open_cnt;
}
/* * Check and close LRU dso if we crossed allowed limit * for opened dso file descriptors. The limit is half * of the RLIMIT_NOFILE files opened.
*/ staticvoid check_data_close(void) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock)
{ bool cache_fd = may_cache_fd();
if (!cache_fd)
close_first_dso();
}
/** * dso__data_close - Close DSO data file * @dso: dso object * * External interface to close @dso's data file descriptor.
*/ void dso__data_close(struct dso *dso)
{
mutex_lock(dso__data_open_lock());
close_dso(dso);
mutex_unlock(dso__data_open_lock());
}
do {
dso__set_binary_type(dso, binary_type_data[i++]);
dso_data->fd = open_dso(dso, machine); if (dso_data->fd >= 0) goto out;
} while (dso__binary_type(dso) != DSO_BINARY_TYPE__NOT_FOUND);
out: if (dso_data->fd >= 0)
dso_data->status = DSO_DATA_STATUS_OK; else
dso_data->status = DSO_DATA_STATUS_ERROR;
}
/** * dso__data_get_fd - Get dso's data file descriptor * @dso: dso object * @machine: machine object * * External interface to find dso's file, open it and * returns file descriptor. It should be paired with * dso__data_put_fd() if it returns non-negative value.
*/ bool dso__data_get_fd(struct dso *dso, struct machine *machine, int *fd)
{
*fd = -1; if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR) returnfalse;
mutex_lock(dso__data_open_lock());
try_to_open_dso(dso, machine);
*fd = dso__data(dso)->fd; if (*fd >= 0) returntrue;
/* * dso__data(dso)->fd might be closed if other thread opened another * file (dso) due to open file limit (RLIMIT_NOFILE).
*/
try_to_open_dso(dso, machine);
if (dso__data(dso)->fd < 0) {
dso__data(dso)->status = DSO_DATA_STATUS_ERROR;
ret = -errno; goto out;
}
/* * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks * in the rb_tree. Any read to already cached data is served * by cached data. Writes update the cache only, not the backing file.
*/ static ssize_t cached_io(struct dso *dso, struct machine *machine,
u64 offset, u8 *data, ssize_t size, bool out)
{
ssize_t r = 0;
u8 *p = data;
do {
ssize_t ret;
ret = dso_cache_io(dso, machine, offset, p, size, out); if (ret < 0) return ret;
/* Reached EOF, return what we have. */ if (!ret) break;
BUG_ON(ret > size);
r += ret;
p += ret;
offset += ret;
size -= ret;
} while (size);
return r;
}
staticint file_size(struct dso *dso, struct machine *machine)
{ int ret = 0; struct stat st; char sbuf[STRERR_BUFSIZE];
mutex_lock(dso__data_open_lock());
/* * dso__data(dso)->fd might be closed if other thread opened another * file (dso) due to open file limit (RLIMIT_NOFILE).
*/
try_to_open_dso(dso, machine);
if (dso__data(dso)->fd < 0) {
ret = -errno;
dso__data(dso)->status = DSO_DATA_STATUS_ERROR; goto out;
}
/** * dso__data_read_offset - Read data from dso file offset * @dso: dso object * @machine: machine object * @offset: file offset * @data: buffer to store data * @size: size of the @data buffer * * External interface to read data from dso file offset. Open * dso data file and use cached_read to get the data.
*/
ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
u64 offset, u8 *data, ssize_t size)
{ if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR) return -1;
switch (dso__binary_type(dso)) { case DSO_BINARY_TYPE__KALLSYMS: case DSO_BINARY_TYPE__GUEST_KALLSYMS: case DSO_BINARY_TYPE__VMLINUX: case DSO_BINARY_TYPE__GUEST_VMLINUX: case DSO_BINARY_TYPE__GUEST_KMODULE: case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: case DSO_BINARY_TYPE__KCORE: case DSO_BINARY_TYPE__GUEST_KCORE: case DSO_BINARY_TYPE__BPF_PROG_INFO: case DSO_BINARY_TYPE__BPF_IMAGE: case DSO_BINARY_TYPE__OOL: case DSO_BINARY_TYPE__JAVA_JIT: return EM_HOST; case DSO_BINARY_TYPE__DEBUGLINK: case DSO_BINARY_TYPE__BUILD_ID_CACHE: case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: case DSO_BINARY_TYPE__GNU_DEBUGDATA: case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO: case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: break; case DSO_BINARY_TYPE__NOT_FOUND: default: return EM_NONE;
}
mutex_lock(dso__data_open_lock());
/* * dso__data(dso)->fd might be closed if other thread opened another * file (dso) due to open file limit (RLIMIT_NOFILE).
*/
try_to_open_dso(dso, machine);
fd = dso__data(dso)->fd; if (fd >= 0) {
_Static_assert(offsetof(Elf32_Ehdr, e_machine) == 18, "Unexpected offset");
_Static_assert(offsetof(Elf64_Ehdr, e_machine) == 18, "Unexpected offset"); if (dso__needs_swap(dso) == DSO_SWAP__UNSET) { unsignedchar eidata;
/** * dso__data_write_cache_offs - Write data to dso data cache at file offset * @dso: dso object * @machine: machine object * @offset: file offset * @data: buffer to write * @size: size of the @data buffer * * Write into the dso file data cache, but do not change the file itself.
*/
ssize_t dso__data_write_cache_offs(struct dso *dso, struct machine *machine,
u64 offset, const u8 *data_in, ssize_t size)
{
u8 *data = (u8 *)data_in; /* cast away const to use same fns for r/w */
if (dso__data(dso)->status == DSO_DATA_STATUS_ERROR) return -1;
if (dso) {
map = map__new2(0, dso);
dso__put(dso);
}
return map;
}
struct dso *machine__findnew_kernel(struct machine *machine, constchar *name, constchar *short_name, int dso_type)
{ /* * The kernel dso could be created by build_id processing.
*/ struct dso *dso = machine__findnew_dso(machine, name);
/* * We need to run this in all cases, since during the build_id * processing we had no idea this was the kernel dso.
*/ if (dso != NULL) {
dso__set_short_name(dso, short_name, false);
dso__set_kernel(dso, dso_type);
}
int dso_id__cmp(conststruct dso_id *a, conststruct dso_id *b)
{ if (a == &dso_id_empty || b == &dso_id_empty) { /* There is no valid data to compare so the comparison always returns identical. */ return 0;
}
switch (eidata) { case ELFDATA2LSB: /* We are big endian, DSO is little endian. */ if (*(unsignedcharconst *)&endian != 1)
dso__set_needs_swap(dso, DSO_SWAP__YES); break;
case ELFDATA2MSB: /* We are little endian, DSO is big endian. */ if (*(unsignedcharconst *)&endian != 0)
dso__set_needs_swap(dso, DSO_SWAP__YES); break;
default:
pr_err("unrecognized DSO data encoding %d\n", eidata); return -EINVAL;
}
int dso__kernel_module_get_build_id(struct dso *dso, constchar *root_dir)
{ char filename[PATH_MAX]; struct build_id bid = { .size = 0, }; /* * kernel module short names are of the form "[module]" and * we need just "module" here.
*/ constchar *name = dso__short_name(dso) + 1;
if (dso__short_name(dso) != dso__long_name(dso))
ret += fprintf(fp, "%s, ", dso__long_name(dso));
ret += fprintf(fp, "%sloaded, ", dso__loaded(dso) ? "" : "NOT ");
ret += dso__fprintf_buildid(dso, fp);
ret += fprintf(fp, ")\n"); for (nd = rb_first_cached(dso__symbols(dso)); nd; nd = rb_next(nd)) { struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
ret += symbol__fprintf(pos, fp);
}
return ret;
}
enum dso_type dso__type(struct dso *dso, struct machine *machine)
{ int fd = -1; enum dso_type type = DSO__TYPE_UNKNOWN;
if (dso__data_get_fd(dso, machine, &fd)) {
type = dso__type_fd(fd);
dso__data_put_fd(dso);
}
return type;
}
int dso__strerror_load(struct dso *dso, char *buf, size_t buflen)
{ int idx, errnum = *dso__load_errno(dso); /* * This must have a same ordering as the enum dso_load_errno.
*/ staticconstchar *dso_load__error_str[] = { "Internal tools/perf/ library error", "Invalid ELF file", "Can not read build id", "Mismatching build id", "Decompression failure",
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.