Release 4.10 tools/perf/util/build-id.c
/*
* build-id.c
*
* build-id support
*
* Copyright (C) 2009, 2010 Red Hat Inc.
* Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
*/
#include "util.h"
#include <stdio.h>
#include "build-id.h"
#include "event.h"
#include "symbol.h"
#include <linux/kernel.h>
#include "debug.h"
#include "session.h"
#include "tool.h"
#include "header.h"
#include "vdso.h"
#include "probe-file.h"
static bool no_buildid_cache;
int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample,
struct perf_evsel *evsel __maybe_unused,
struct machine *machine)
{
struct addr_location al;
struct thread *thread = machine__findnew_thread(machine, sample->pid,
sample->tid);
if (thread == NULL) {
pr_err("problem processing %d event, skipping it.\n",
event->header.type);
return -1;
}
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, &al);
if (al.map != NULL)
al.map->dso->hit = 1;
thread__put(thread);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 113 | 93.39% | 10 | 71.43% |
adrian hunter | adrian hunter | 5 | 4.13% | 2 | 14.29% |
irina tirdea | irina tirdea | 2 | 1.65% | 1 | 7.14% |
namhyung kim | namhyung kim | 1 | 0.83% | 1 | 7.14% |
| Total | 121 | 100.00% | 14 | 100.00% |
static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample
__maybe_unused,
struct machine *machine)
{
struct thread *thread = machine__findnew_thread(machine,
event->fork.pid,
event->fork.tid);
dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
event->fork.ppid, event->fork.ptid);
if (thread) {
machine__remove_thread(machine, thread);
thread__put(thread);
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 90 | 90.00% | 9 | 75.00% |
adrian hunter | adrian hunter | 6 | 6.00% | 1 | 8.33% |
irina tirdea | irina tirdea | 2 | 2.00% | 1 | 8.33% |
he kuang | he kuang | 2 | 2.00% | 1 | 8.33% |
| Total | 100 | 100.00% | 12 | 100.00% |
struct perf_tool build_id__mark_dso_hit_ops = {
.sample = build_id__mark_dso_hit,
.mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2,
.fork = perf_event__process_fork,
.exit = perf_event__exit_del_thread,
.attr = perf_event__process_attr,
.build_id = perf_event__process_build_id,
.ordered_events = true,
};
int build_id__sprintf(const u8 *build_id, int len, char *bf)
{
char *bid = bf;
const u8 *raw = build_id;
int i;
for (i = 0; i < len; ++i) {
sprintf(bid, "%02x", *raw);
++raw;
bid += 2;
}
return (bid - bf) + 1;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jiri olsa | jiri olsa | 68 | 91.89% | 1 | 50.00% |
michael petlan | michael petlan | 6 | 8.11% | 1 | 50.00% |
| Total | 74 | 100.00% | 2 | 100.00% |
int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
{
char notes[PATH_MAX];
u8 build_id[BUILD_ID_SIZE];
int ret;
if (!root_dir)
root_dir = "";
scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
ret = sysfs__read_build_id(notes, build_id, sizeof(build_id));
if (ret < 0)
return ret;
return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 88 | 100.00% | 1 | 100.00% |
| Total | 88 | 100.00% | 1 | 100.00% |
int filename__sprintf_build_id(const char *pathname, char *sbuild_id)
{
u8 build_id[BUILD_ID_SIZE];
int ret;
ret = filename__read_build_id(pathname, build_id, sizeof(build_id));
if (ret < 0)
return ret;
else if (ret != sizeof(build_id))
return -EINVAL;
return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 73 | 100.00% | 1 | 100.00% |
| Total | 73 | 100.00% | 1 | 100.00% |
/* asnprintf consolidates asprintf and snprintf */
static int asnprintf(char **strp, size_t size, const char *fmt, ...)
{
va_list ap;
int ret;
if (!strp)
return -EINVAL;
va_start(ap, fmt);
if (*strp)
ret = vsnprintf(*strp, size, fmt, ap);
else
ret = vasprintf(strp, fmt, ap);
va_end(ap);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 82 | 100.00% | 1 | 100.00% |
| Total | 82 | 100.00% | 1 | 100.00% |
char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
size_t size)
{
bool retry_old = true;
snprintf(bf, size, "%s/%s/%s/kallsyms",
buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
retry:
if (!access(bf, F_OK))
return bf;
if (retry_old) {
/* Try old style kallsyms cache */
snprintf(bf, size, "%s/%s/%s",
buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
retry_old = false;
goto retry;
}
return NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 83 | 97.65% | 1 | 50.00% |
wang nan | wang nan | 2 | 2.35% | 1 | 50.00% |
| Total | 85 | 100.00% | 2 | 100.00% |
char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size)
{
char *tmp = bf;
int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
sbuild_id, sbuild_id + 2);
if (ret < 0 || (tmp && size < (unsigned int)ret))
return NULL;
return bf;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 69 | 100.00% | 2 | 100.00% |
| Total | 69 | 100.00% | 2 | 100.00% |
char *build_id_cache__origname(const char *sbuild_id)
{
char *linkname;
char buf[PATH_MAX];
char *ret = NULL, *p;
size_t offs = 5; /* == strlen("../..") */
linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
if (!linkname)
return NULL;
if (readlink(linkname, buf, PATH_MAX) < 0)
goto out;
/* The link should be "../..<origpath>/<sbuild_id>" */
p = strrchr(buf, '/'); /* Cut off the "/<sbuild_id>" */
if (p && (p > buf + offs)) {
*p = '\0';
if (buf[offs + 1] == '[')
offs++; /*
* This is a DSO name, like [kernel.kallsyms].
* Skip the first '/', since this is not the
* cache of a regular file.
*/
ret = strdup(buf + offs); /* Skip "../..[/]" */
}
out:
free(linkname);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 136 | 100.00% | 1 | 100.00% |
| Total | 136 | 100.00% | 1 | 100.00% |
/* Check if the given build_id cache is valid on current running system */
static bool build_id_cache__valid_id(char *sbuild_id)
{
char real_sbuild_id[SBUILD_ID_SIZE] = "";
char *pathname;
int ret = 0;
bool result = false;
pathname = build_id_cache__origname(sbuild_id);
if (!pathname)
return false;
if (!strcmp(pathname, DSO__NAME_KALLSYMS))
ret = sysfs__sprintf_build_id("/", real_sbuild_id);
else if (pathname[0] == '/')
ret = filename__sprintf_build_id(pathname, real_sbuild_id);
else
ret = -EINVAL; /* Should we support other special DSO cache? */
if (ret >= 0)
result = (strcmp(sbuild_id, real_sbuild_id) == 0);
free(pathname);
return result;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 119 | 100.00% | 1 | 100.00% |
| Total | 119 | 100.00% | 1 | 100.00% |
static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
{
return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 27 | 100.00% | 1 | 100.00% |
| Total | 27 | 100.00% | 1 | 100.00% |
char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
{
bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
bool is_vdso = dso__is_vdso((struct dso *)dso);
char sbuild_id[SBUILD_ID_SIZE];
char *linkname;
bool alloc = (bf == NULL);
int ret;
if (!dso->has_build_id)
return NULL;
build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
if (!linkname)
return NULL;
/* Check if old style build_id cache */
if (is_regular_file(linkname))
ret = asnprintf(&bf, size, "%s", linkname);
else
ret = asnprintf(&bf, size, "%s/%s", linkname,
build_id_cache__basename(is_kallsyms, is_vdso));
if (ret < 0 || (!alloc && size < (unsigned int)ret))
bf = NULL;
free(linkname);
return bf;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 132 | 70.59% | 3 | 50.00% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 55 | 29.41% | 3 | 50.00% |
| Total | 187 | 100.00% | 6 | 100.00% |
bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
{
char *id_name = NULL, *ch;
struct stat sb;
char sbuild_id[SBUILD_ID_SIZE];
if (!dso->has_build_id)
goto err;
build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
id_name = build_id_cache__linkname(sbuild_id, NULL, 0);
if (!id_name)
goto err;
if (access(id_name, F_OK))
goto err;
if (lstat(id_name, &sb) == -1)
goto err;
if ((size_t)sb.st_size > size - 1)
goto err;
if (readlink(id_name, bf, size - 1) < 0)
goto err;
bf[sb.st_size] = '\0';
/*
* link should be:
* ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92
*/
ch = strrchr(bf, '/');
if (!ch)
goto err;
if (ch - 3 < bf)
goto err;
free(id_name);
return strncmp(".ko", ch - 3, 3) == 0;
err:
pr_err("Invalid build id: %s\n", id_name ? :
dso->long_name ? :
dso->short_name ? :
"[unknown]");
free(id_name);
return false;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
wang nan | wang nan | 183 | 79.22% | 1 | 50.00% |
masami hiramatsu | masami hiramatsu | 48 | 20.78% | 1 | 50.00% |
| Total | 231 | 100.00% | 2 | 100.00% |
#define dsos__for_each_with_build_id(pos, head) \
list_for_each_entry(pos, head, node) \
if (!pos->has_build_id) \
continue; \
else
static int write_buildid(const char *name, size_t name_len, u8 *build_id,
pid_t pid, u16 misc, int fd)
{
int err;
struct build_id_event b;
size_t len;
len = name_len + 1;
len = PERF_ALIGN(len, NAME_ALIGN);
memset(&b, 0, sizeof(b));
memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
b.pid = pid;
b.header.misc = misc;
b.header.size = sizeof(b) + len;
err = writen(fd, &b, sizeof(b));
if (err < 0)
return err;
return write_padded(fd, name, name_len + 1, len);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 142 | 100.00% | 1 | 100.00% |
| Total | 142 | 100.00% | 1 | 100.00% |
static int machine__write_buildid_table(struct machine *machine, int fd)
{
int err = 0;
char nm[PATH_MAX];
struct dso *pos;
u16 kmisc = PERF_RECORD_MISC_KERNEL,
umisc = PERF_RECORD_MISC_USER;
if (!machine__is_host(machine)) {
kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
umisc = PERF_RECORD_MISC_GUEST_USER;
}
dsos__for_each_with_build_id(pos, &machine->dsos.head) {
const char *name;
size_t name_len;
bool in_kernel = false;
if (!pos->hit && !dso__is_vdso(pos))
continue;
if (dso__is_vdso(pos)) {
name = pos->short_name;
name_len = pos->short_name_len;
} else if (dso__is_kcore(pos)) {
machine__mmap_name(machine, nm, sizeof(nm));
name = nm;
name_len = strlen(nm);
} else {
name = pos->long_name;
name_len = pos->long_name_len;
}
in_kernel = pos->kernel ||
is_kernel_module(name,
PERF_RECORD_MISC_CPUMODE_UNKNOWN);
err = write_buildid(name, name_len, pos->build_id, machine->pid,
in_kernel ? kmisc : umisc, fd);
if (err)
break;
}
return err;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 143 | 69.08% | 1 | 25.00% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 39 | 18.84% | 1 | 25.00% |
wang nan | wang nan | 19 | 9.18% | 1 | 25.00% |
he kuang | he kuang | 6 | 2.90% | 1 | 25.00% |
| Total | 207 | 100.00% | 4 | 100.00% |
int perf_session__write_buildid_table(struct perf_session *session, int fd)
{
struct rb_node *nd;
int err = machine__write_buildid_table(&session->machines.host, fd);
if (err)
return err;
for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
struct machine *pos = rb_entry(nd, struct machine, rb_node);
err = machine__write_buildid_table(pos, fd);
if (err)
break;
}
return err;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 97 | 100.00% | 1 | 100.00% |
| Total | 97 | 100.00% | 1 | 100.00% |
static int __dsos__hit_all(struct list_head *head)
{
struct dso *pos;
list_for_each_entry(pos, head, node)
pos->hit = true;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 33 | 100.00% | 1 | 100.00% |
| Total | 33 | 100.00% | 1 | 100.00% |
static int machine__hit_all_dsos(struct machine *machine)
{
return __dsos__hit_all(&machine->dsos.head);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 21 | 95.45% | 1 | 50.00% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 1 | 4.55% | 1 | 50.00% |
| Total | 22 | 100.00% | 2 | 100.00% |
int dsos__hit_all(struct perf_session *session)
{
struct rb_node *nd;
int err;
err = machine__hit_all_dsos(&session->machines.host);
if (err)
return err;
for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
struct machine *pos = rb_entry(nd, struct machine, rb_node);
err = machine__hit_all_dsos(pos);
if (err)
return err;
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 94 | 100.00% | 1 | 100.00% |
| Total | 94 | 100.00% | 1 | 100.00% |
void disable_buildid_cache(void)
{
no_buildid_cache = true;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 11 | 100.00% | 1 | 100.00% |
| Total | 11 | 100.00% | 1 | 100.00% |
static bool lsdir_bid_head_filter(const char *name __maybe_unused,
struct dirent *d __maybe_unused)
{
return (strlen(d->d_name) == 2) &&
isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 50 | 100.00% | 1 | 100.00% |
| Total | 50 | 100.00% | 1 | 100.00% |
static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
struct dirent *d __maybe_unused)
{
int i = 0;
while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
i++;
return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 64 | 100.00% | 1 | 100.00% |
| Total | 64 | 100.00% | 1 | 100.00% |
struct strlist *build_id_cache__list_all(bool validonly)
{
struct strlist *toplist, *linklist = NULL, *bidlist;
struct str_node *nd, *nd2;
char *topdir, *linkdir = NULL;
char sbuild_id[SBUILD_ID_SIZE];
/* for filename__ functions */
if (validonly)
symbol__init(NULL);
/* Open the top-level directory */
if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
return NULL;
bidlist = strlist__new(NULL, NULL);
if (!bidlist)
goto out;
toplist = lsdir(topdir, lsdir_bid_head_filter);
if (!toplist) {
pr_debug("Error in lsdir(%s): %d\n", topdir, errno);
/* If there is no buildid cache, return an empty list */
if (errno == ENOENT)
goto out;
goto err_out;
}
strlist__for_each_entry(nd, toplist) {
if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0)
goto err_out;
/* Open the lower-level directory */
linklist = lsdir(linkdir, lsdir_bid_tail_filter);
if (!linklist) {
pr_debug("Error in lsdir(%s): %d\n", linkdir, errno);
goto err_out;
}
strlist__for_each_entry(nd2, linklist) {
if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
goto err_out;
if (validonly && !build_id_cache__valid_id(sbuild_id))
continue;
if (strlist__add(bidlist, sbuild_id) < 0)
goto err_out;
}
strlist__delete(linklist);
zfree(&linkdir);
}
out_free:
strlist__delete(toplist);
out:
free(topdir);
return bidlist;
err_out:
strlist__delete(linklist);
zfree(&linkdir);
strlist__delete(bidlist);
bidlist = NULL;
goto out_free;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 299 | 100.00% | 2 | 100.00% |
| Total | 299 | 100.00% | 2 | 100.00% |
static bool str_is_build_id(const char *maybe_sbuild_id, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
if (!isxdigit(maybe_sbuild_id[i]))
return false;
}
return true;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 49 | 100.00% | 1 | 100.00% |
| Total | 49 | 100.00% | 1 | 100.00% |
/* Return the valid complete build-id */
char *build_id_cache__complement(const char *incomplete_sbuild_id)
{
struct strlist *bidlist;
struct str_node *nd, *cand = NULL;
char *sbuild_id = NULL;
size_t len = strlen(incomplete_sbuild_id);
if (len >= SBUILD_ID_SIZE ||
!str_is_build_id(incomplete_sbuild_id, len))
return NULL;
bidlist = build_id_cache__list_all(true);
if (!bidlist)
return NULL;
strlist__for_each_entry(nd, bidlist) {
if (strncmp(nd->s, incomplete_sbuild_id, len) != 0)
continue;
if (cand) { /* Error: There are more than 2 candidates. */
cand = NULL;
break;
}
cand = nd;
}
if (cand)
sbuild_id = strdup(cand->s);
strlist__delete(bidlist);
return sbuild_id;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 133 | 100.00% | 1 | 100.00% |
| Total | 133 | 100.00% | 1 | 100.00% |
char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
bool is_kallsyms, bool is_vdso)
{
char *realname = (char *)name, *filename;
bool slash = is_kallsyms || is_vdso;
if (!slash) {
realname = realpath(name, NULL);
if (!realname)
return NULL;
}
if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "",
is_vdso ? DSO__NAME_VDSO : realname,
sbuild_id ? "/" : "", sbuild_id ?: "") < 0)
filename = NULL;
if (!slash)
free(realname);
return filename;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masami hiramatsu | masami hiramatsu | 120 | 100.00% | 3 | 100.00% |
| Total | 120 | 100.00% | 3 | 100.00% |
int build_id_cache__list_build_ids(const char