// SPDX-License-Identifier: GPL-2.0
/*
* 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" // lsdir(), mkdir_p(), rm_rf()
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "util/copyfile.h"
#include "dso.h"
#include "build-id.h"
#include "event.h"
#include "namespaces.h"
#include "map.h"
#include "symbol.h"
#include "thread.h"
#include <linux/kernel.h>
#include "debug.h"
#include "session.h"
#include "tool.h"
#include "header.h"
#include "vdso.h"
#include "path.h"
#include "probe-file.h"
#include "strlist.h"
#ifdef HAVE_DEBUGINFOD_SUPPORT
#include <elfutils/debuginfod.h>
#endif
#include <linux/ctype.h>
#include <linux/zalloc.h>
#include <linux/string.h>
#include <asm/bug.h>
static bool no_buildid_cache;
static int mark_dso_hit_callback(struct callchain_cursor_node *node, void *data __maybe_unused)
{
struct map *map = node->ms.map;
if (map)
dso__set_hit(map__dso(map));
return 0;
}
int build_id__mark_dso_hit(const struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample,
struct evsel *evsel,
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;
}
addr_location__init(&al);
if (thread__find_map(thread, sample->cpumode, sample->ip, &al))
dso__set_hit(map__dso(al.map));
addr_location__exit(&al);
sample__for_each_callchain_node(thread, evsel, sample, PERF_MAX_STACK_DEPTH,
/*symbols=*/false, mark_dso_hit_callback, /*data=*/NULL);
thread__put(thread);
return 0;
}
int build_id__snprintf(const struct build_id *build_id, char *bf, size_t bf_size)
{
size_t offs = 0;
if (build_id->size == 0) {
/* Ensure bf is always \0 terminated. */
if (bf_size > 0)
bf[0] = '\0';
return 0;
}
for (size_t i = 0; i < build_id->size && offs < bf_size; ++i)
offs += snprintf(bf + offs, bf_size - offs, "%02x", build_id->data[i]);
return offs;
}
int sysfs__snprintf_build_id(const char *root_dir, char *sbuild_id, size_t sbuild_id_size)
{
char notes[PATH_MAX];
struct build_id bid = { .size = 0, };
int ret;
if (!root_dir)
root_dir = "";
scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
ret = sysfs__read_build_id(notes, &bid);
if (ret < 0)
return ret;
return build_id__snprintf(&bid, sbuild_id, sbuild_id_size);
}
int filename__snprintf_build_id(const char *pathname, char *sbuild_id, size_t sbuild_id_size)
{
struct build_id bid = { .size = 0, };
int ret;
ret = filename__read_build_id(pathname, &bid);
if (ret < 0)
return ret;
return build_id__snprintf(&bid, sbuild_id, sbuild_id_size);
}
/* 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;
}
char *build_id_cache__kallsyms_path(const char