hi,
adding the support to have buildid stored in mmap2 event,
so we can bypass the final perf record hunt on build ids.
This patchset allows perf to record build ID in mmap2 event,
and adds perf tooling to store/download binaries to .debug
cache based on these build IDs.
Note that the build id retrieval code is stolen from bpf
code, where it's been used (together with file offsets)
to replace IPs in user space stack traces. It's now added
under lib directory.
v2 changes:
- add size arg to build_id_parse instead of extra function [Alexei]
- shift build_id_size and build_id [Peter]
- document new config options [Namhyung]
- fallback to maj/min/ino* in case build id parse fails [Namhyung]
- fixed debuginfo retrieval for kernel and modules in buildid-cache
- keeping the post processing disabled for --buildid-mmap
because the buildid parsing seems reliable, failing only for vdso,
vsyscall and annon mappings, which is expected:
people.redhat.com/~jolsa/buildids.txt
On recording server:
- on the recording server we can run record with --buildid-mmap
option to store build ids in mmap2 events:
# perf record --buildid-mmap
^C[ perf record: Woken up 2 times to write data ]
[ perf record: Captured and wrote 0.836 MB perf.data ]
- it stores nothing to ~/.debug cache:
# find ~/.debug
find: ‘/root/.debug’: No such file or directory
- and still reports properly:
# perf report --stdio
...
99.82% swapper [kernel.kallsyms] [k] native_safe_halt
0.03% swapper [kernel.kallsyms] [k] finish_task_switch
0.02% swapper [kernel.kallsyms] [k] __softirqentry_text_start
0.01% kcompactd0 [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore
0.01% ksoftirqd/6 [kernel.kallsyms] [k] slab_free_freelist_hook
0.01% kworker/17:1H-x [kernel.kallsyms] [k] slab_free_freelist_hook
- display used/hit build ids:
# perf buildid-list | head -5
5dcec522abf136fcfd3128f47e131f2365834dd7 /proc/kcore
589e403a34f55486bcac848a45e00bcdeedd1ca8 /usr/lib64/libcrypto.so.1.1.1g
94569566d4eac7e9c87ba029d43d4e2158f9527e /usr/lib64/libpthread-2.30.so
559b9702bebe31c6d132c8dc5cc887673d65d5b5 /usr/lib64/libc-2.30.so
40da7abe89f631f60538a17686a7d65c6a02ed31 /usr/lib64/ld-2.30.so
- store build id binaries into build id cache:
# perf buildid-cache -a perf.data
OK 5dcec522abf136fcfd3128f47e131f2365834dd7 /proc/kcore
OK 589e403a34f55486bcac848a45e00bcdeedd1ca8 /usr/lib64/libcrypto.so.1.1.1g
OK 94569566d4eac7e9c87ba029d43d4e2158f9527e /usr/lib64/libpthread-2.30.so
OK 559b9702bebe31c6d132c8dc5cc887673d65d5b5 /usr/lib64/libc-2.30.so
OK 40da7abe89f631f60538a17686a7d65c6a02ed31 /usr/lib64/ld-2.30.so
OK a674f7a47c78e35a088104647b9640710277b489 /usr/sbin/sshd
OK e5cb4ca25f46485bdbc691c3a92e7e111dac3ef2 /usr/bin/bash
OK 9bc8589108223c944b452f0819298a0c3cba6215 /usr/bin/find
# find ~/.debug | head -5
/root/.debug
/root/.debug/proc
/root/.debug/proc/kcore
/root/.debug/proc/kcore/5dcec522abf136fcfd3128f47e131f2365834dd7
/root/.debug/proc/kcore/5dcec522abf136fcfd3128f47e131f2365834dd7/kallsyms
- run debuginfod daemon to provide binaries to another server (below)
(the initialization could take some time)
# debuginfod -F /
On another server:
- copy perf.data from 'record' server and run:
$ find ~/.debug/
find: ‘/home/jolsa/.debug/’: No such file or directory
$ perf buildid-list | head -5
No kallsyms or vmlinux with build-id 5dcec522abf136fcfd3128f47e131f2365834dd7 was found
5dcec522abf136fcfd3128f47e131f2365834dd7 [kernel.kallsyms]
5784f813b727a50cfd3363234aef9fcbab685cc4 /lib/modules/5.10.0-rc2speed+/kernel/fs/xfs/xfs.ko
589e403a34f55486bcac848a45e00bcdeedd1ca8 /usr/lib64/libcrypto.so.1.1.1g
94569566d4eac7e9c87ba029d43d4e2158f9527e /usr/lib64/libpthread-2.30.so
559b9702bebe31c6d132c8dc5cc887673d65d5b5 /usr/lib64/libc-2.30.so
- report does not show anything (kernel build id does not match):
$ perf report --stdio
...
76.73% swapper [kernel.kallsyms] [k] 0xffffffff81aa8ebe
1.89% find [kernel.kallsyms] [k] 0xffffffff810f2167
0.93% sshd [kernel.kallsyms] [k] 0xffffffff8153380c
0.83% swapper [kernel.kallsyms] [k] 0xffffffff81104b0b
0.71% kworker/u40:2-e [kernel.kallsyms] [k] 0xffffffff810f3850
0.70% kworker/u40:0-e [kernel.kallsyms] [k] 0xffffffff810f3850
0.64% find [kernel.kallsyms] [k] 0xffffffff81a9ba0a
0.63% find [kernel.kallsyms] [k] 0xffffffff81aa93b0
- add build ids does not work, because existing binaries (on another server)
have different build ids:
$ perf buildid-cache -a perf.data
No kallsyms or vmlinux with build-id 5dcec522abf136fcfd3128f47e131f2365834dd7 was found
FAIL 5dcec522abf136fcfd3128f47e131f2365834dd7 [kernel.kallsyms]
FAIL 5784f813b727a50cfd3363234aef9fcbab685cc4 /lib/modules/5.10.0-rc2speed+/kernel/fs/xfs/xfs.ko
FAIL 589e403a34f55486bcac848a45e00bcdeedd1ca8 /usr/lib64/libcrypto.so.1.1.1g
FAIL 94569566d4eac7e9c87ba029d43d4e2158f9527e /usr/lib64/libpthread-2.30.so
FAIL 559b9702bebe31c6d132c8dc5cc887673d65d5b5 /usr/lib64/libc-2.30.so
FAIL 40da7abe89f631f60538a17686a7d65c6a02ed31 /usr/lib64/ld-2.30.so
FAIL a674f7a47c78e35a088104647b9640710277b489 /usr/sbin/sshd
FAIL e5cb4ca25f46485bdbc691c3a92e7e111dac3ef2 /usr/bin/bash
FAIL 9bc8589108223c944b452f0819298a0c3cba6215 /usr/bin/find
- add build ids with debuginfod setup pointing to record server:
$ perf buildid-cache -a perf.data --debuginfod http://192.168.122.174:8002
No kallsyms or vmlinux with build-id 5dcec522abf136fcfd3128f47e131f2365834dd7 was found
OK 5dcec522abf136fcfd3128f47e131f2365834dd7 [kernel.kallsyms]
OK 5784f813b727a50cfd3363234aef9fcbab685cc4 /lib/modules/5.10.0-rc2speed+/kernel/fs/xfs/xfs.ko
OK 589e403a34f55486bcac848a45e00bcdeedd1ca8 /usr/lib64/libcrypto.so.1.1.1g
OK 94569566d4eac7e9c87ba029d43d4e2158f9527e /usr/lib64/libpthread-2.30.so
OK 559b9702bebe31c6d132c8dc5cc887673d65d5b5 /usr/lib64/libc-2.30.so
OK 40da7abe89f631f60538a17686a7d65c6a02ed31 /usr/lib64/ld-2.30.so
OK a674f7a47c78e35a088104647b9640710277b489 /usr/sbin/sshd
OK e5cb4ca25f46485bdbc691c3a92e7e111dac3ef2 /usr/bin/bash
OK 9bc8589108223c944b452f0819298a0c3cba6215 /usr/bin/find
- and report works:
$ perf report --stdio
...
76.73% swapper [kernel.kallsyms] [k] native_safe_halt
1.91% find [kernel.kallsyms] [k] queue_work_on
0.93% sshd [kernel.kallsyms] [k] iowrite16
0.83% swapper [kernel.kallsyms] [k] finish_task_switch
0.72% kworker/u40:2-e [kernel.kallsyms] [k] process_one_work
0.70% kworker/u40:0-e [kernel.kallsyms] [k] process_one_work
0.64% find [kernel.kallsyms] [k] syscall_enter_from_user_mode
0.63% find [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore
- because we have the data in build id cache:
$ find ~/.debug | head -10
.../.debug
.../.debug/home
.../.debug/home/jolsa
.../.debug/home/jolsa/.cache
.../.debug/home/jolsa/.cache/debuginfod_client
.../.debug/home/jolsa/.cache/debuginfod_client/5dcec522abf136fcfd3128f47e131f2365834dd7
.../.debug/home/jolsa/.cache/debuginfod_client/5dcec522abf136fcfd3128f47e131f2365834dd7/executable
.../.debug/home/jolsa/.cache/debuginfod_client/5dcec522abf136fcfd3128f47e131f2365834dd7/executable/5dcec522abf136fcfd3128f47e131f2365834dd7
.../.debug/home/jolsa/.cache/debuginfod_client/5dcec522abf136fcfd3128f47e131f2365834dd7/executable/5dcec522abf136fcfd3128f47e131f2365834dd7/elf
.../.debug/home/jolsa/.cache/debuginfod_client/5dcec522abf136fcfd3128f47e131f2365834dd7/executable/5dcec522abf136fcfd3128f47e131f2365834dd7/debug
Available also in:
git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/build_id
thanks,
jirka
Cc: Frank Ch. Eigler <[email protected]>
Cc: Mark Wielaard <[email protected]>
---
Jiri Olsa (24):
bpf: Move stack_map_get_build_id into lib
bpf: Add size arg to build_id_parse function
perf: Add build id data in mmap2 event
tools headers uapi: Sync tools/include/uapi/linux/perf_event.h
perf tools: Do not swap mmap2 fields in case it contains build id
perf tools: Add build_id__is_defined function
perf tools: Add filename__decompress function
perf tools: Add support to read build id from compressed elf
perf tools: Add check for existing link in buildid dir
perf tools: Use struct extra_kernel_map in machine__process_kernel_mmap_event
perf tools: Try to load vmlinux from buildid database
perf tools: Store build id from mmap2 events
perf tools: Allow mmap2 event to synthesize kernel image
perf tools: Allow mmap2 event to synthesize modules
perf tools: Synthesize build id for kernel/modules/tasks
perf tools: Add support to display build id for mmap2 events
perf tools: Use machine__for_each_dso in perf_session__cache_build_ids
perf tools: Add __perf_session__cache_build_ids function
perf tools: Add is_perf_data function
perf tools: Add build_id_cache__add function
perf buildid-cache: Add support to add build ids from perf data
perf buildid-cache: Add --debuginfod option
perf buildid-list: Add support for mmap2's buildid events
perf record: Add --buildid-mmap option to enable mmap's build id
include/linux/buildid.h | 12 ++++++
include/uapi/linux/perf_event.h | 42 ++++++++++++++++---
kernel/bpf/stackmap.c | 143 ++---------------------------------------------------------------
kernel/events/core.c | 36 +++++++++++++++--
lib/Makefile | 3 +-
lib/buildid.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/include/uapi/linux/perf_event.h | 42 ++++++++++++++++---
tools/lib/perf/include/perf/event.h | 18 +++++++--
tools/perf/Documentation/perf-buildid-cache.txt | 18 ++++++++-
tools/perf/Documentation/perf-config.txt | 10 ++++-
tools/perf/Documentation/perf-record.txt | 3 ++
tools/perf/builtin-buildid-cache.c | 243 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/perf/builtin-buildid-list.c | 3 ++
tools/perf/builtin-record.c | 20 +++++++++
tools/perf/tests/shell/trace+probe_vfs_getname.sh | 2 +-
tools/perf/util/build-id.c | 124 ++++++++++++++++++++++++++++++++++++--------------------
tools/perf/util/build-id.h | 8 ++++
tools/perf/util/data.c | 19 +++++++++
tools/perf/util/data.h | 1 +
tools/perf/util/dso.c | 31 ++++++++------
tools/perf/util/dso.h | 2 +
tools/perf/util/event.c | 41 ++++++++++++++-----
tools/perf/util/evsel.c | 10 +++--
tools/perf/util/machine.c | 80 ++++++++++++++++++++++--------------
tools/perf/util/map.c | 8 +++-
tools/perf/util/map.h | 3 +-
tools/perf/util/perf_api_probe.c | 10 +++++
tools/perf/util/perf_api_probe.h | 1 +
tools/perf/util/perf_event_attr_fprintf.c | 2 +
tools/perf/util/probe-event.c | 6 +--
tools/perf/util/record.h | 1 +
tools/perf/util/session.c | 11 +++--
tools/perf/util/symbol-elf.c | 37 ++++++++++++++++-
tools/perf/util/symbol.c | 16 ++++++++
tools/perf/util/symbol_conf.h | 3 +-
tools/perf/util/synthetic-events.c | 121 +++++++++++++++++++++++++++++++++++++++++--------------
36 files changed, 968 insertions(+), 311 deletions(-)
create mode 100644 include/linux/buildid.h
create mode 100644 lib/buildid.c
It's possible to have other build id types (other than default SHA1).
Currently there's also ld support for MD5 build id.
Adding size argument to build_id_parse function, that returns (if defined)
size of the parsed build id, so we can recognize the build id type.
Cc: Alexei Starovoitov <[email protected]>
Cc: Song Liu <[email protected]>
Signed-off-by: Jiri Olsa <[email protected]>
---
include/linux/buildid.h | 3 ++-
kernel/bpf/stackmap.c | 2 +-
lib/buildid.c | 29 +++++++++++++++++++++--------
3 files changed, 24 insertions(+), 10 deletions(-)
diff --git a/include/linux/buildid.h b/include/linux/buildid.h
index 3be5b49719f1..72639d433873 100644
--- a/include/linux/buildid.h
+++ b/include/linux/buildid.h
@@ -6,6 +6,7 @@
#define BUILD_ID_SIZE 20
-int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id);
+int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id,
+ __u32 *size);
#endif
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 7df08f8af5a1..a05fac2cbb05 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -199,7 +199,7 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
for (i = 0; i < trace_nr; i++) {
vma = find_vma(current->mm, ips[i]);
- if (!vma || build_id_parse(vma, id_offs[i].build_id)) {
+ if (!vma || build_id_parse(vma, id_offs[i].build_id, NULL)) {
/* per entry fall back to ips */
id_offs[i].status = BPF_STACK_BUILD_ID_IP;
id_offs[i].ip = ips[i];
diff --git a/lib/buildid.c b/lib/buildid.c
index e8d5feb7ef20..dbe1b7e247f3 100644
--- a/lib/buildid.c
+++ b/lib/buildid.c
@@ -12,6 +12,7 @@
*/
static inline int parse_build_id(void *page_addr,
unsigned char *build_id,
+ __u32 *size,
void *note_start,
Elf32_Word note_size)
{
@@ -38,6 +39,8 @@ static inline int parse_build_id(void *page_addr,
nhdr->n_descsz);
memset(build_id + nhdr->n_descsz, 0,
BUILD_ID_SIZE - nhdr->n_descsz);
+ if (size)
+ *size = nhdr->n_descsz;
return 0;
}
new_offs = note_offs + sizeof(Elf32_Nhdr) +
@@ -50,7 +53,8 @@ static inline int parse_build_id(void *page_addr,
}
/* Parse build ID from 32-bit ELF */
-static int get_build_id_32(void *page_addr, unsigned char *build_id)
+static int get_build_id_32(void *page_addr, unsigned char *build_id,
+ __u32 *size)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)page_addr;
Elf32_Phdr *phdr;
@@ -65,7 +69,7 @@ static int get_build_id_32(void *page_addr, unsigned char *build_id)
for (i = 0; i < ehdr->e_phnum; ++i) {
if (phdr[i].p_type == PT_NOTE &&
- !parse_build_id(page_addr, build_id,
+ !parse_build_id(page_addr, build_id, size,
page_addr + phdr[i].p_offset,
phdr[i].p_filesz))
return 0;
@@ -74,7 +78,8 @@ static int get_build_id_32(void *page_addr, unsigned char *build_id)
}
/* Parse build ID from 64-bit ELF */
-static int get_build_id_64(void *page_addr, unsigned char *build_id)
+static int get_build_id_64(void *page_addr, unsigned char *build_id,
+ __u32 *size)
{
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)page_addr;
Elf64_Phdr *phdr;
@@ -89,7 +94,7 @@ static int get_build_id_64(void *page_addr, unsigned char *build_id)
for (i = 0; i < ehdr->e_phnum; ++i) {
if (phdr[i].p_type == PT_NOTE &&
- !parse_build_id(page_addr, build_id,
+ !parse_build_id(page_addr, build_id, size,
page_addr + phdr[i].p_offset,
phdr[i].p_filesz))
return 0;
@@ -97,8 +102,16 @@ static int get_build_id_64(void *page_addr, unsigned char *build_id)
return -EINVAL;
}
-/* Parse build ID of ELF file mapped to vma */
-int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id)
+/*
+ * Parse build ID of ELF file mapped to vma
+ * @vma: vma object
+ * @build_id: buffer to store build id, at least BUILD_ID_SIZE long
+ * @size: returns actual build id size in case of success
+ *
+ * Returns 0 on success, otherwise error (< 0).
+ */
+int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id,
+ __u32 *size)
{
Elf32_Ehdr *ehdr;
struct page *page;
@@ -126,9 +139,9 @@ int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id)
goto out;
if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
- ret = get_build_id_32(page_addr, build_id);
+ ret = get_build_id_32(page_addr, build_id, size);
else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
- ret = get_build_id_64(page_addr, build_id);
+ ret = get_build_id_64(page_addr, build_id, size);
out:
kunmap_atomic(page_addr);
put_page(page);
--
2.26.2
Syncing tools's uapi with mmap2 build id data changes.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/include/uapi/linux/perf_event.h | 42 +++++++++++++++++++++++----
1 file changed, 37 insertions(+), 5 deletions(-)
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index b95d3c485d27..45a216bea048 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -384,7 +384,8 @@ struct perf_event_attr {
aux_output : 1, /* generate AUX records instead of events */
cgroup : 1, /* include cgroup events */
text_poke : 1, /* include text poke events */
- __reserved_1 : 30;
+ build_id : 1, /* use build id in mmap2 events */
+ __reserved_1 : 29;
union {
__u32 wakeup_events; /* wakeup every n events */
@@ -657,6 +658,22 @@ struct perf_event_mmap_page {
__u64 aux_size;
};
+/*
+ * The current state of perf_event_header::misc bits usage:
+ * ('|' used bit, '-' unused bit)
+ *
+ * 012 CDEF
+ * |||---------||||
+ *
+ * Where:
+ * 0-2 CPUMODE_MASK
+ *
+ * C PROC_MAP_PARSE_TIMEOUT
+ * D MMAP_DATA / COMM_EXEC / FORK_EXEC / SWITCH_OUT
+ * E MMAP_BUILD_ID / EXACT_IP / SCHED_OUT_PREEMPT
+ * F (reserved)
+ */
+
#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
#define PERF_RECORD_MISC_KERNEL (1 << 0)
@@ -688,6 +705,7 @@ struct perf_event_mmap_page {
*
* PERF_RECORD_MISC_EXACT_IP - PERF_RECORD_SAMPLE of precise events
* PERF_RECORD_MISC_SWITCH_OUT_PREEMPT - PERF_RECORD_SWITCH* events
+ * PERF_RECORD_MISC_MMAP_BUILD_ID - PERF_RECORD_MMAP2 event
*
*
* PERF_RECORD_MISC_EXACT_IP:
@@ -697,9 +715,13 @@ struct perf_event_mmap_page {
*
* PERF_RECORD_MISC_SWITCH_OUT_PREEMPT:
* Indicates that thread was preempted in TASK_RUNNING state.
+ *
+ * PERF_RECORD_MISC_MMAP_BUILD_ID:
+ * Indicates that mmap2 event carries build id data.
*/
#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
#define PERF_RECORD_MISC_SWITCH_OUT_PREEMPT (1 << 14)
+#define PERF_RECORD_MISC_MMAP_BUILD_ID (1 << 14)
/*
* Reserve the last bit to indicate some extended misc field
*/
@@ -911,10 +933,20 @@ enum perf_event_type {
* u64 addr;
* u64 len;
* u64 pgoff;
- * u32 maj;
- * u32 min;
- * u64 ino;
- * u64 ino_generation;
+ * union {
+ * struct {
+ * u32 maj;
+ * u32 min;
+ * u64 ino;
+ * u64 ino_generation;
+ * };
+ * struct {
+ * u8 build_id_size;
+ * u8 __reserved_1;
+ * u16 __reserved_2;
+ * u8 build_id[20];
+ * };
+ * };
* u32 prot, flags;
* char filename[];
* struct sample_id sample_id;
--
2.26.2
Adding build_id__is_defined helper to check build id
is defined and is != zero build id.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/build-id.c | 7 +++++++
tools/perf/util/build-id.h | 1 +
2 files changed, 8 insertions(+)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 6b410c3d52dc..7d9ecc37849c 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -912,3 +912,10 @@ void build_id__init(struct build_id *bid, const u8 *data, size_t size)
memcpy(bid->data, data, size);
bid->size = size;
}
+
+bool build_id__is_defined(const struct build_id *bid)
+{
+ static u8 zero[BUILD_ID_SIZE];
+
+ return bid && bid->size ? memcmp(bid->data, &zero, bid->size) : false;
+}
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index f293f99d5dba..d53415feaf69 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -21,6 +21,7 @@ struct feat_fd;
void build_id__init(struct build_id *bid, const u8 *data, size_t size);
int build_id__sprintf(const struct build_id *build_id, char *bf);
+bool build_id__is_defined(const struct build_id *bid);
int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
--
2.26.2
Adding support to carry build id data in mmap2 event.
The build id data replaces maj/min/ino/ino_generation
fields, which are also used to identify map's binary,
so it's ok to replace them with build id data:
union {
struct {
u32 maj;
u32 min;
u64 ino;
u64 ino_generation;
};
struct {
u8 build_id_size;
u8 __reserved_1;
u16 __reserved_2;
u8 build_id[20];
};
};
Replaced maj/min/ino/ino_generation fields give us size
of 24 bytes. We use 20 bytes for build id data, 1 byte
for size and rest is unused.
There's new misc bit for mmap2 to signal there's build
id data in it:
#define PERF_RECORD_MISC_MMAP_BUILD_ID (1 << 14)
Signed-off-by: Jiri Olsa <[email protected]>
---
include/uapi/linux/perf_event.h | 42 +++++++++++++++++++++++++++++----
kernel/events/core.c | 32 +++++++++++++++++++++----
2 files changed, 65 insertions(+), 9 deletions(-)
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index b95d3c485d27..45a216bea048 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -384,7 +384,8 @@ struct perf_event_attr {
aux_output : 1, /* generate AUX records instead of events */
cgroup : 1, /* include cgroup events */
text_poke : 1, /* include text poke events */
- __reserved_1 : 30;
+ build_id : 1, /* use build id in mmap2 events */
+ __reserved_1 : 29;
union {
__u32 wakeup_events; /* wakeup every n events */
@@ -657,6 +658,22 @@ struct perf_event_mmap_page {
__u64 aux_size;
};
+/*
+ * The current state of perf_event_header::misc bits usage:
+ * ('|' used bit, '-' unused bit)
+ *
+ * 012 CDEF
+ * |||---------||||
+ *
+ * Where:
+ * 0-2 CPUMODE_MASK
+ *
+ * C PROC_MAP_PARSE_TIMEOUT
+ * D MMAP_DATA / COMM_EXEC / FORK_EXEC / SWITCH_OUT
+ * E MMAP_BUILD_ID / EXACT_IP / SCHED_OUT_PREEMPT
+ * F (reserved)
+ */
+
#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
#define PERF_RECORD_MISC_KERNEL (1 << 0)
@@ -688,6 +705,7 @@ struct perf_event_mmap_page {
*
* PERF_RECORD_MISC_EXACT_IP - PERF_RECORD_SAMPLE of precise events
* PERF_RECORD_MISC_SWITCH_OUT_PREEMPT - PERF_RECORD_SWITCH* events
+ * PERF_RECORD_MISC_MMAP_BUILD_ID - PERF_RECORD_MMAP2 event
*
*
* PERF_RECORD_MISC_EXACT_IP:
@@ -697,9 +715,13 @@ struct perf_event_mmap_page {
*
* PERF_RECORD_MISC_SWITCH_OUT_PREEMPT:
* Indicates that thread was preempted in TASK_RUNNING state.
+ *
+ * PERF_RECORD_MISC_MMAP_BUILD_ID:
+ * Indicates that mmap2 event carries build id data.
*/
#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
#define PERF_RECORD_MISC_SWITCH_OUT_PREEMPT (1 << 14)
+#define PERF_RECORD_MISC_MMAP_BUILD_ID (1 << 14)
/*
* Reserve the last bit to indicate some extended misc field
*/
@@ -911,10 +933,20 @@ enum perf_event_type {
* u64 addr;
* u64 len;
* u64 pgoff;
- * u32 maj;
- * u32 min;
- * u64 ino;
- * u64 ino_generation;
+ * union {
+ * struct {
+ * u32 maj;
+ * u32 min;
+ * u64 ino;
+ * u64 ino_generation;
+ * };
+ * struct {
+ * u8 build_id_size;
+ * u8 __reserved_1;
+ * u16 __reserved_2;
+ * u8 build_id[20];
+ * };
+ * };
* u32 prot, flags;
* char filename[];
* struct sample_id sample_id;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index da467e1dd49a..5841b5bca68d 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -51,6 +51,7 @@
#include <linux/proc_ns.h>
#include <linux/mount.h>
#include <linux/min_heap.h>
+#include <linux/buildid.h>
#include "internal.h"
@@ -395,6 +396,7 @@ static atomic_t nr_ksymbol_events __read_mostly;
static atomic_t nr_bpf_events __read_mostly;
static atomic_t nr_cgroup_events __read_mostly;
static atomic_t nr_text_poke_events __read_mostly;
+static atomic_t nr_build_id_events __read_mostly;
static LIST_HEAD(pmus);
static DEFINE_MUTEX(pmus_lock);
@@ -4672,6 +4674,8 @@ static void unaccount_event(struct perf_event *event)
dec = true;
if (event->attr.mmap || event->attr.mmap_data)
atomic_dec(&nr_mmap_events);
+ if (event->attr.build_id)
+ atomic_dec(&nr_build_id_events);
if (event->attr.comm)
atomic_dec(&nr_comm_events);
if (event->attr.namespaces)
@@ -7942,6 +7946,8 @@ struct perf_mmap_event {
u64 ino;
u64 ino_generation;
u32 prot, flags;
+ u8 build_id[BUILD_ID_SIZE];
+ u32 build_id_size;
struct {
struct perf_event_header header;
@@ -7973,6 +7979,7 @@ static void perf_event_mmap_output(struct perf_event *event,
struct perf_sample_data sample;
int size = mmap_event->event_id.header.size;
u32 type = mmap_event->event_id.header.type;
+ bool use_build_id;
int ret;
if (!perf_event_mmap_match(event, data))
@@ -7997,13 +8004,25 @@ static void perf_event_mmap_output(struct perf_event *event,
mmap_event->event_id.pid = perf_event_pid(event, current);
mmap_event->event_id.tid = perf_event_tid(event, current);
+ use_build_id = event->attr.build_id && mmap_event->build_id_size;
+
+ if (event->attr.mmap2 && use_build_id)
+ mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_BUILD_ID;
+
perf_output_put(&handle, mmap_event->event_id);
if (event->attr.mmap2) {
- perf_output_put(&handle, mmap_event->maj);
- perf_output_put(&handle, mmap_event->min);
- perf_output_put(&handle, mmap_event->ino);
- perf_output_put(&handle, mmap_event->ino_generation);
+ if (use_build_id) {
+ u8 size[4] = { (u8) mmap_event->build_id_size, 0, 0, 0 };
+
+ __output_copy(&handle, size, 4);
+ __output_copy(&handle, mmap_event->build_id, BUILD_ID_SIZE);
+ } else {
+ perf_output_put(&handle, mmap_event->maj);
+ perf_output_put(&handle, mmap_event->min);
+ perf_output_put(&handle, mmap_event->ino);
+ perf_output_put(&handle, mmap_event->ino_generation);
+ }
perf_output_put(&handle, mmap_event->prot);
perf_output_put(&handle, mmap_event->flags);
}
@@ -8132,6 +8151,9 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size;
+ if (atomic_read(&nr_build_id_events))
+ build_id_parse(vma, mmap_event->build_id, &mmap_event->build_id_size);
+
perf_iterate_sb(perf_event_mmap_output,
mmap_event,
NULL);
@@ -11069,6 +11091,8 @@ static void account_event(struct perf_event *event)
inc = true;
if (event->attr.mmap || event->attr.mmap_data)
atomic_inc(&nr_mmap_events);
+ if (event->attr.build_id)
+ atomic_inc(&nr_build_id_events);
if (event->attr.comm)
atomic_inc(&nr_comm_events);
if (event->attr.namespaces)
--
2.26.2
If PERF_RECORD_MISC_BUILD_ID misc bit is set, mmap2
event carries build id, placed in following union:
union {
struct {
u32 maj;
u32 min;
u64 ino;
u64 ino_generation;
};
struct {
u8 build_id[20];
u8 build_id_size;
u8 __reserved_1;
u16 __reserved_2;
};
};
In this case we can't swap above fields.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/session.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 098080287c68..da632b8e2b08 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -592,10 +592,13 @@ static void perf_event__mmap2_swap(union perf_event *event,
event->mmap2.start = bswap_64(event->mmap2.start);
event->mmap2.len = bswap_64(event->mmap2.len);
event->mmap2.pgoff = bswap_64(event->mmap2.pgoff);
- event->mmap2.maj = bswap_32(event->mmap2.maj);
- event->mmap2.min = bswap_32(event->mmap2.min);
- event->mmap2.ino = bswap_64(event->mmap2.ino);
- event->mmap2.ino_generation = bswap_64(event->mmap2.ino_generation);
+
+ if (!(event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID)) {
+ event->mmap2.maj = bswap_32(event->mmap2.maj);
+ event->mmap2.min = bswap_32(event->mmap2.min);
+ event->mmap2.ino = bswap_64(event->mmap2.ino);
+ event->mmap2.ino_generation = bswap_64(event->mmap2.ino_generation);
+ }
if (sample_id_all) {
void *data = &event->mmap2.filename;
--
2.26.2
When adding new build id link we fail if the link is already
there. Adding check for existing link and output debug message
that the build id is already linked.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/build-id.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 7d9ecc37849c..ef9a31b54ba2 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -754,8 +754,21 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
tmp = dir_name + strlen(buildid_dir) - 5;
memcpy(tmp, "../..", 5);
- if (symlink(tmp, linkname) == 0)
+ if (symlink(tmp, linkname) == 0) {
err = 0;
+ } else if (errno == EEXIST) {
+ char path[PATH_MAX];
+
+ if (readlink(linkname, path, sizeof(path)) == -1) {
+ pr_err("Cant read link: %s\n", linkname);
+ goto out_free;
+ }
+ if (strcmp(tmp, path)) {
+ pr_debug("build <%s> already linked to %s\n",
+ sbuild_id, linkname);
+ }
+ err = 0;
+ }
/* Update SDT cache : error is just warned */
if (realname &&
--
2.26.2
Currently we don't check on kernel's vmlinux the same way as
we do for normal binaries, but we either look for kallsyms
file in build id database or check on known vmlinux locations
(plus some other optional paths).
This patch adds the check for standard build id binary location,
so we are ready once we start to store it there from debuginfod
in following changes.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/build-id.c | 13 ++++++++++---
tools/perf/util/build-id.h | 2 ++
tools/perf/util/symbol.c | 16 ++++++++++++++++
3 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index ef9a31b54ba2..2755d7b37a44 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -260,10 +260,9 @@ static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso,
"debug" : "elf"));
}
-char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
- bool is_debug)
+char *__dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
+ bool is_debug, bool is_kallsyms)
{
- 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;
@@ -292,6 +291,14 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
return bf;
}
+char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
+ bool is_debug)
+{
+ bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
+
+ return __dso__build_id_filename(dso, bf, size, is_debug, is_kallsyms);
+}
+
#define dsos__for_each_with_build_id(pos, head) \
list_for_each_entry(pos, head, node) \
if (!pos->has_build_id) \
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index d53415feaf69..f1a2f67df6e4 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -29,6 +29,8 @@ char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
bool is_debug);
+char *__dso__build_id_filename(const struct dso *dso, char *bf, size_t size,
+ bool is_debug, bool is_kallsyms);
int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
struct perf_sample *sample, struct evsel *evsel,
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 0d14abdf3d72..64a039cbba1b 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2189,6 +2189,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map)
int err;
const char *kallsyms_filename = NULL;
char *kallsyms_allocated_filename = NULL;
+ char *filename = NULL;
+
/*
* Step 1: if the user specified a kallsyms or vmlinux filename, use
* it and only it, reporting errors to the user if it cannot be used.
@@ -2213,6 +2215,20 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map)
return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false);
}
+ /*
+ * Before checking on common vmlinux locations, check if it's
+ * stored as standard build id binary (not kallsyms) under
+ * .debug cache.
+ */
+ if (!symbol_conf.ignore_vmlinux_buildid)
+ filename = __dso__build_id_filename(dso, NULL, 0, false, false);
+ if (filename != NULL) {
+ err = dso__load_vmlinux(dso, map, filename, true);
+ if (err > 0)
+ return err;
+ free(filename);
+ }
+
if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
err = dso__load_vmlinux_path(dso, map);
if (err > 0)
--
2.26.2
Allow mmap2 event to synthesize kernel modules,
so we can synthesize module's build id data in
following changes.
It's enabled by new symbol_conf.buildid_mmap2
bool, which will be switched in following
changes.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/synthetic-events.c | 49 +++++++++++++++++++-----------
1 file changed, 32 insertions(+), 17 deletions(-)
diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
index 872df6d6dbef..a18ae502d765 100644
--- a/tools/perf/util/synthetic-events.c
+++ b/tools/perf/util/synthetic-events.c
@@ -593,16 +593,17 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t
int rc = 0;
struct map *pos;
struct maps *maps = machine__kernel_maps(machine);
- union perf_event *event = zalloc((sizeof(event->mmap) +
- machine->id_hdr_size));
+ union perf_event *event;
+ size_t size = symbol_conf.buildid_mmap2 ?
+ sizeof(event->mmap2) : sizeof(event->mmap);
+
+ event = zalloc(size + machine->id_hdr_size);
if (event == NULL) {
pr_debug("Not enough memory synthesizing mmap event "
"for kernel modules\n");
return -1;
}
- event->header.type = PERF_RECORD_MMAP;
-
/*
* kernel uses 0 for user space maps, see kernel/perf_event.c
* __perf_event_mmap
@@ -613,23 +614,37 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t
event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
maps__for_each_entry(maps, pos) {
- size_t size;
-
if (!__map__is_kmodule(pos))
continue;
- size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
- event->mmap.header.type = PERF_RECORD_MMAP;
- event->mmap.header.size = (sizeof(event->mmap) -
- (sizeof(event->mmap.filename) - size));
- memset(event->mmap.filename + size, 0, machine->id_hdr_size);
- event->mmap.header.size += machine->id_hdr_size;
- event->mmap.start = pos->start;
- event->mmap.len = pos->end - pos->start;
- event->mmap.pid = machine->pid;
+ if (symbol_conf.buildid_mmap2) {
+ size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
+ event->mmap2.header.type = PERF_RECORD_MMAP2;
+ event->mmap2.header.size = (sizeof(event->mmap2) -
+ (sizeof(event->mmap2.filename) - size));
+ memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
+ event->mmap2.header.size += machine->id_hdr_size;
+ event->mmap2.start = pos->start;
+ event->mmap2.len = pos->end - pos->start;
+ event->mmap2.pid = machine->pid;
+
+ memcpy(event->mmap2.filename, pos->dso->long_name,
+ pos->dso->long_name_len + 1);
+ } else {
+ size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
+ event->mmap.header.type = PERF_RECORD_MMAP;
+ event->mmap.header.size = (sizeof(event->mmap) -
+ (sizeof(event->mmap.filename) - size));
+ memset(event->mmap.filename + size, 0, machine->id_hdr_size);
+ event->mmap.header.size += machine->id_hdr_size;
+ event->mmap.start = pos->start;
+ event->mmap.len = pos->end - pos->start;
+ event->mmap.pid = machine->pid;
+
+ memcpy(event->mmap.filename, pos->dso->long_name,
+ pos->dso->long_name_len + 1);
+ }
- memcpy(event->mmap.filename, pos->dso->long_name,
- pos->dso->long_name_len + 1);
if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
rc = -1;
break;
--
2.26.2
Adding support to display build id in mmap2 events:
$ perf script --show-mmap-events | head -4
swapper ... @ 0xffffffff81000000 <ff1969b3ba5e43911208bb46fa7d5b1eb809e422>]: ---p [kernel.kallsyms]_text
swapper ... @ 0 <5f62adb730272c9417883ae8b8a8ec224df8cddd>]: ---p /lib/modules/5.9.0-rc5buildid+/kernel/drivers/firmware/qemu_fw_cfg.ko
swapper ... @ 0 <c9ac6e1dafc1ebdadb048f967854e810706c8bab>]: ---p /lib/modules/5.9.0-rc5buildid+/kernel/drivers/char/virtio_console.ko
swapper ... @ 0 <86441a4c5b2c2ff5b440682f4c612bd4b426eb5c>]: ---p /lib/modules/5.9.0-rc5buildid+/kernel/lib/libcrc32c.ko
$ perf report -D | grep MMAP2 | head -4
0 0 ... @ 0xffffffff81000000 <ff1969b3ba5e43911208bb46fa7d5b1eb809e422>]: ---p [kernel.kallsyms]_text
0 0 ... @ 0 <5f62adb730272c9417883ae8b8a8ec224df8cddd>]: ---p /lib/modules/5.9.0-rc5buildid+/kernel/drivers/firmware/qemu_fw_cfg.ko
0 0 ... @ 0 <c9ac6e1dafc1ebdadb048f967854e810706c8bab>]: ---p /lib/modules/5.9.0-rc5buildid+/kernel/drivers/char/virtio_console.ko
0 0 ... @ 0 <86441a4c5b2c2ff5b440682f4c612bd4b426eb5c>]: ---p /lib/modules/5.9.0-rc5buildid+/kernel/lib/libcrc32c.ko
Adding build id data into <> brackets.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/event.c | 41 ++++++++++++++++++++++++++++++-----------
1 file changed, 30 insertions(+), 11 deletions(-)
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 05616d4138a9..fbe8578e4c47 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -288,17 +288,36 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
{
- return fprintf(fp, " %d/%d: [%#" PRI_lx64 "(%#" PRI_lx64 ") @ %#" PRI_lx64
- " %02x:%02x %"PRI_lu64" %"PRI_lu64"]: %c%c%c%c %s\n",
- event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
- event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
- event->mmap2.min, event->mmap2.ino,
- event->mmap2.ino_generation,
- (event->mmap2.prot & PROT_READ) ? 'r' : '-',
- (event->mmap2.prot & PROT_WRITE) ? 'w' : '-',
- (event->mmap2.prot & PROT_EXEC) ? 'x' : '-',
- (event->mmap2.flags & MAP_SHARED) ? 's' : 'p',
- event->mmap2.filename);
+ if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
+ char sbuild_id[SBUILD_ID_SIZE];
+ struct build_id bid;
+
+ build_id__init(&bid, event->mmap2.build_id,
+ event->mmap2.build_id_size);
+ build_id__sprintf(&bid, sbuild_id);
+
+ return fprintf(fp, " %d/%d: [%#" PRI_lx64 "(%#" PRI_lx64 ") @ %#" PRI_lx64
+ " <%s>]: %c%c%c%c %s\n",
+ event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
+ event->mmap2.len, event->mmap2.pgoff, sbuild_id,
+ (event->mmap2.prot & PROT_READ) ? 'r' : '-',
+ (event->mmap2.prot & PROT_WRITE) ? 'w' : '-',
+ (event->mmap2.prot & PROT_EXEC) ? 'x' : '-',
+ (event->mmap2.flags & MAP_SHARED) ? 's' : 'p',
+ event->mmap2.filename);
+ } else {
+ return fprintf(fp, " %d/%d: [%#" PRI_lx64 "(%#" PRI_lx64 ") @ %#" PRI_lx64
+ " %02x:%02x %"PRI_lu64" %"PRI_lu64"]: %c%c%c%c %s\n",
+ event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
+ event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
+ event->mmap2.min, event->mmap2.ino,
+ event->mmap2.ino_generation,
+ (event->mmap2.prot & PROT_READ) ? 'r' : '-',
+ (event->mmap2.prot & PROT_WRITE) ? 'w' : '-',
+ (event->mmap2.prot & PROT_EXEC) ? 'x' : '-',
+ (event->mmap2.flags & MAP_SHARED) ? 's' : 'p',
+ event->mmap2.filename);
+ }
}
size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp)
--
2.26.2
Using machine__for_each_dso in perf_session__cache_build_ids,
so we can reuse perf_session__cache_build_ids with different
callback in following changes.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/build-id.c | 41 +++++++++++++++-----------------------
1 file changed, 16 insertions(+), 25 deletions(-)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 2755d7b37a44..9f14d5851bb5 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -854,12 +854,16 @@ int build_id_cache__remove_s(const char *sbuild_id)
return err;
}
-static int dso__cache_build_id(struct dso *dso, struct machine *machine)
+static int dso__cache_build_id(struct dso *dso, struct machine *machine,
+ void *priv __maybe_unused)
{
bool is_kallsyms = dso__is_kallsyms(dso);
bool is_vdso = dso__is_vdso(dso);
const char *name = dso->long_name;
+ if (!dso->has_build_id)
+ return 0;
+
if (dso__is_kcore(dso)) {
is_kallsyms = true;
name = machine->mmap_name;
@@ -868,43 +872,30 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine)
is_kallsyms, is_vdso);
}
-static int __dsos__cache_build_ids(struct list_head *head,
- struct machine *machine)
+static int
+machines__for_each_dso(struct machines *machines, machine__dso_t fn, void *priv)
{
- struct dso *pos;
- int err = 0;
-
- dsos__for_each_with_build_id(pos, head)
- if (dso__cache_build_id(pos, machine))
- err = -1;
+ int ret = machine__for_each_dso(&machines->host, fn, priv);
+ struct rb_node *nd;
- return err;
-}
+ for (nd = rb_first_cached(&machines->guests); nd;
+ nd = rb_next(nd)) {
+ struct machine *pos = rb_entry(nd, struct machine, rb_node);
-static int machine__cache_build_ids(struct machine *machine)
-{
- return __dsos__cache_build_ids(&machine->dsos.head, machine);
+ ret |= machine__for_each_dso(pos, fn, priv);
+ }
+ return ret ? -1 : 0;
}
int perf_session__cache_build_ids(struct perf_session *session)
{
- struct rb_node *nd;
- int ret;
-
if (no_buildid_cache)
return 0;
if (mkdir(buildid_dir, 0755) != 0 && errno != EEXIST)
return -1;
- ret = machine__cache_build_ids(&session->machines.host);
-
- for (nd = rb_first_cached(&session->machines.guests); nd;
- nd = rb_next(nd)) {
- struct machine *pos = rb_entry(nd, struct machine, rb_node);
- ret |= machine__cache_build_ids(pos);
- }
- return ret ? -1 : 0;
+ return machines__for_each_dso(&session->machines, dso__cache_build_id, NULL) ? -1 : 0;
}
static bool machine__read_build_ids(struct machine *machine, bool with_hits)
--
2.26.2
Adding support to decompress file before reading build id.
Adding filename__read_build_id and change its current
versions to read_build_id.
Shutting down stderr output of perf list in the shell test:
82: Check open filename arg using perf trace + vfs_getname : Ok
because with decompression code in the place we the
filename__read_build_id function is more verbose in case
of error and the test did not account for that.
Signed-off-by: Jiri Olsa <[email protected]>
---
.../tests/shell/trace+probe_vfs_getname.sh | 2 +-
tools/perf/util/symbol-elf.c | 37 ++++++++++++++++++-
2 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/tools/perf/tests/shell/trace+probe_vfs_getname.sh b/tools/perf/tests/shell/trace+probe_vfs_getname.sh
index 11cc2af13f2b..3660fcc02fef 100755
--- a/tools/perf/tests/shell/trace+probe_vfs_getname.sh
+++ b/tools/perf/tests/shell/trace+probe_vfs_getname.sh
@@ -20,7 +20,7 @@ skip_if_no_perf_trace || exit 2
file=$(mktemp /tmp/temporary_file.XXXXX)
trace_open_vfs_getname() {
- evts=$(echo $(perf list syscalls:sys_enter_open* 2>&1 | egrep 'open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/') | sed 's/ /,/')
+ evts=$(echo $(perf list syscalls:sys_enter_open* >&1 2>/dev/nul | egrep 'open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/') | sed 's/ /,/')
perf trace -e $evts touch $file 2>&1 | \
egrep " +[0-9]+\.[0-9]+ +\( +[0-9]+\.[0-9]+ ms\): +touch\/[0-9]+ open(at)?\((dfd: +CWD, +)?filename: +${file}, +flags: CREAT\|NOCTTY\|NONBLOCK\|WRONLY, +mode: +IRUGO\|IWUGO\) += +[0-9]+$"
}
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 44dd86a4f25f..f3577f7d72fe 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -534,7 +534,7 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
#ifdef HAVE_LIBBFD_BUILDID_SUPPORT
-int filename__read_build_id(const char *filename, struct build_id *bid)
+static int read_build_id(const char *filename, struct build_id *bid)
{
size_t size = sizeof(bid->data);
int err = -1;
@@ -563,7 +563,7 @@ int filename__read_build_id(const char *filename, struct build_id *bid)
#else // HAVE_LIBBFD_BUILDID_SUPPORT
-int filename__read_build_id(const char *filename, struct build_id *bid)
+static int read_build_id(const char *filename, struct build_id *bid)
{
size_t size = sizeof(bid->data);
int fd, err = -1;
@@ -595,6 +595,39 @@ int filename__read_build_id(const char *filename, struct build_id *bid)
#endif // HAVE_LIBBFD_BUILDID_SUPPORT
+int filename__read_build_id(const char *filename, struct build_id *bid)
+{
+ struct kmod_path m = { .name = NULL, };
+ char path[PATH_MAX];
+ int err;
+
+ if (!filename)
+ return -EFAULT;
+
+ err = kmod_path__parse(&m, filename);
+ if (err)
+ return -1;
+
+ if (m.comp) {
+ int error = 0, fd;
+
+ fd = filename__decompress(filename, path, sizeof(path), m.comp, &error);
+ if (fd < 0) {
+ pr_debug("Failed to decompress (error %d) %s\n",
+ error, filename);
+ return -1;
+ }
+ close(fd);
+ filename = path;
+ }
+
+ err = read_build_id(filename, bid);
+
+ if (m.comp)
+ unlink(filename);
+ return err;
+}
+
int sysfs__read_build_id(const char *filename, struct build_id *bid)
{
size_t size = sizeof(bid->data);
--
2.26.2
Moving stack_map_get_build_id into lib with
declaration in linux/buildid.h header:
int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id);
This function returns build id for given struct vm_area_struct.
There is no functional change to stack_map_get_build_id function.
Cc: Alexei Starovoitov <[email protected]>
Acked-by: Song Liu <[email protected]>
Signed-off-by: Jiri Olsa <[email protected]>
---
include/linux/buildid.h | 11 ++++
kernel/bpf/stackmap.c | 143 ++--------------------------------------
lib/Makefile | 3 +-
lib/buildid.c | 136 ++++++++++++++++++++++++++++++++++++++
4 files changed, 153 insertions(+), 140 deletions(-)
create mode 100644 include/linux/buildid.h
create mode 100644 lib/buildid.c
diff --git a/include/linux/buildid.h b/include/linux/buildid.h
new file mode 100644
index 000000000000..3be5b49719f1
--- /dev/null
+++ b/include/linux/buildid.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_BUILDID_H
+#define _LINUX_BUILDID_H
+
+#include <linux/mm_types.h>
+
+#define BUILD_ID_SIZE 20
+
+int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id);
+
+#endif
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 06065fa27124..7df08f8af5a1 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -7,10 +7,9 @@
#include <linux/kernel.h>
#include <linux/stacktrace.h>
#include <linux/perf_event.h>
-#include <linux/elf.h>
-#include <linux/pagemap.h>
#include <linux/irq_work.h>
#include <linux/btf_ids.h>
+#include <linux/buildid.h>
#include "percpu_freelist.h"
#define STACK_CREATE_FLAG_MASK \
@@ -153,140 +152,6 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr)
return ERR_PTR(err);
}
-#define BPF_BUILD_ID 3
-/*
- * Parse build id from the note segment. This logic can be shared between
- * 32-bit and 64-bit system, because Elf32_Nhdr and Elf64_Nhdr are
- * identical.
- */
-static inline int stack_map_parse_build_id(void *page_addr,
- unsigned char *build_id,
- void *note_start,
- Elf32_Word note_size)
-{
- Elf32_Word note_offs = 0, new_offs;
-
- /* check for overflow */
- if (note_start < page_addr || note_start + note_size < note_start)
- return -EINVAL;
-
- /* only supports note that fits in the first page */
- if (note_start + note_size > page_addr + PAGE_SIZE)
- return -EINVAL;
-
- while (note_offs + sizeof(Elf32_Nhdr) < note_size) {
- Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs);
-
- if (nhdr->n_type == BPF_BUILD_ID &&
- nhdr->n_namesz == sizeof("GNU") &&
- nhdr->n_descsz > 0 &&
- nhdr->n_descsz <= BPF_BUILD_ID_SIZE) {
- memcpy(build_id,
- note_start + note_offs +
- ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr),
- nhdr->n_descsz);
- memset(build_id + nhdr->n_descsz, 0,
- BPF_BUILD_ID_SIZE - nhdr->n_descsz);
- return 0;
- }
- new_offs = note_offs + sizeof(Elf32_Nhdr) +
- ALIGN(nhdr->n_namesz, 4) + ALIGN(nhdr->n_descsz, 4);
- if (new_offs <= note_offs) /* overflow */
- break;
- note_offs = new_offs;
- }
- return -EINVAL;
-}
-
-/* Parse build ID from 32-bit ELF */
-static int stack_map_get_build_id_32(void *page_addr,
- unsigned char *build_id)
-{
- Elf32_Ehdr *ehdr = (Elf32_Ehdr *)page_addr;
- Elf32_Phdr *phdr;
- int i;
-
- /* only supports phdr that fits in one page */
- if (ehdr->e_phnum >
- (PAGE_SIZE - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr))
- return -EINVAL;
-
- phdr = (Elf32_Phdr *)(page_addr + sizeof(Elf32_Ehdr));
-
- for (i = 0; i < ehdr->e_phnum; ++i) {
- if (phdr[i].p_type == PT_NOTE &&
- !stack_map_parse_build_id(page_addr, build_id,
- page_addr + phdr[i].p_offset,
- phdr[i].p_filesz))
- return 0;
- }
- return -EINVAL;
-}
-
-/* Parse build ID from 64-bit ELF */
-static int stack_map_get_build_id_64(void *page_addr,
- unsigned char *build_id)
-{
- Elf64_Ehdr *ehdr = (Elf64_Ehdr *)page_addr;
- Elf64_Phdr *phdr;
- int i;
-
- /* only supports phdr that fits in one page */
- if (ehdr->e_phnum >
- (PAGE_SIZE - sizeof(Elf64_Ehdr)) / sizeof(Elf64_Phdr))
- return -EINVAL;
-
- phdr = (Elf64_Phdr *)(page_addr + sizeof(Elf64_Ehdr));
-
- for (i = 0; i < ehdr->e_phnum; ++i) {
- if (phdr[i].p_type == PT_NOTE &&
- !stack_map_parse_build_id(page_addr, build_id,
- page_addr + phdr[i].p_offset,
- phdr[i].p_filesz))
- return 0;
- }
- return -EINVAL;
-}
-
-/* Parse build ID of ELF file mapped to vma */
-static int stack_map_get_build_id(struct vm_area_struct *vma,
- unsigned char *build_id)
-{
- Elf32_Ehdr *ehdr;
- struct page *page;
- void *page_addr;
- int ret;
-
- /* only works for page backed storage */
- if (!vma->vm_file)
- return -EINVAL;
-
- page = find_get_page(vma->vm_file->f_mapping, 0);
- if (!page)
- return -EFAULT; /* page not mapped */
-
- ret = -EINVAL;
- page_addr = kmap_atomic(page);
- ehdr = (Elf32_Ehdr *)page_addr;
-
- /* compare magic x7f "ELF" */
- if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
- goto out;
-
- /* only support executable file and shared object file */
- if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
- goto out;
-
- if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
- ret = stack_map_get_build_id_32(page_addr, build_id);
- else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
- ret = stack_map_get_build_id_64(page_addr, build_id);
-out:
- kunmap_atomic(page_addr);
- put_page(page);
- return ret;
-}
-
static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
u64 *ips, u32 trace_nr, bool user)
{
@@ -327,18 +192,18 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
for (i = 0; i < trace_nr; i++) {
id_offs[i].status = BPF_STACK_BUILD_ID_IP;
id_offs[i].ip = ips[i];
- memset(id_offs[i].build_id, 0, BPF_BUILD_ID_SIZE);
+ memset(id_offs[i].build_id, 0, BUILD_ID_SIZE);
}
return;
}
for (i = 0; i < trace_nr; i++) {
vma = find_vma(current->mm, ips[i]);
- if (!vma || stack_map_get_build_id(vma, id_offs[i].build_id)) {
+ if (!vma || build_id_parse(vma, id_offs[i].build_id)) {
/* per entry fall back to ips */
id_offs[i].status = BPF_STACK_BUILD_ID_IP;
id_offs[i].ip = ips[i];
- memset(id_offs[i].build_id, 0, BPF_BUILD_ID_SIZE);
+ memset(id_offs[i].build_id, 0, BUILD_ID_SIZE);
continue;
}
id_offs[i].offset = (vma->vm_pgoff << PAGE_SHIFT) + ips[i]
diff --git a/lib/Makefile b/lib/Makefile
index ce45af50983a..f4858f5e9215 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -36,7 +36,8 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
flex_proportions.o ratelimit.o show_mem.o \
is_single_threaded.o plist.o decompress.o kobject_uevent.o \
earlycpio.o seq_buf.o siphash.o dec_and_lock.o \
- nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o
+ nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o \
+ buildid.o
lib-$(CONFIG_PRINTK) += dump_stack.o
lib-$(CONFIG_SMP) += cpumask.o
diff --git a/lib/buildid.c b/lib/buildid.c
new file mode 100644
index 000000000000..e8d5feb7ef20
--- /dev/null
+++ b/lib/buildid.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/buildid.h>
+#include <linux/elf.h>
+#include <linux/pagemap.h>
+
+#define BUILD_ID 3
+/*
+ * Parse build id from the note segment. This logic can be shared between
+ * 32-bit and 64-bit system, because Elf32_Nhdr and Elf64_Nhdr are
+ * identical.
+ */
+static inline int parse_build_id(void *page_addr,
+ unsigned char *build_id,
+ void *note_start,
+ Elf32_Word note_size)
+{
+ Elf32_Word note_offs = 0, new_offs;
+
+ /* check for overflow */
+ if (note_start < page_addr || note_start + note_size < note_start)
+ return -EINVAL;
+
+ /* only supports note that fits in the first page */
+ if (note_start + note_size > page_addr + PAGE_SIZE)
+ return -EINVAL;
+
+ while (note_offs + sizeof(Elf32_Nhdr) < note_size) {
+ Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs);
+
+ if (nhdr->n_type == BUILD_ID &&
+ nhdr->n_namesz == sizeof("GNU") &&
+ nhdr->n_descsz > 0 &&
+ nhdr->n_descsz <= BUILD_ID_SIZE) {
+ memcpy(build_id,
+ note_start + note_offs +
+ ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr),
+ nhdr->n_descsz);
+ memset(build_id + nhdr->n_descsz, 0,
+ BUILD_ID_SIZE - nhdr->n_descsz);
+ return 0;
+ }
+ new_offs = note_offs + sizeof(Elf32_Nhdr) +
+ ALIGN(nhdr->n_namesz, 4) + ALIGN(nhdr->n_descsz, 4);
+ if (new_offs <= note_offs) /* overflow */
+ break;
+ note_offs = new_offs;
+ }
+ return -EINVAL;
+}
+
+/* Parse build ID from 32-bit ELF */
+static int get_build_id_32(void *page_addr, unsigned char *build_id)
+{
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)page_addr;
+ Elf32_Phdr *phdr;
+ int i;
+
+ /* only supports phdr that fits in one page */
+ if (ehdr->e_phnum >
+ (PAGE_SIZE - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr))
+ return -EINVAL;
+
+ phdr = (Elf32_Phdr *)(page_addr + sizeof(Elf32_Ehdr));
+
+ for (i = 0; i < ehdr->e_phnum; ++i) {
+ if (phdr[i].p_type == PT_NOTE &&
+ !parse_build_id(page_addr, build_id,
+ page_addr + phdr[i].p_offset,
+ phdr[i].p_filesz))
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* Parse build ID from 64-bit ELF */
+static int get_build_id_64(void *page_addr, unsigned char *build_id)
+{
+ Elf64_Ehdr *ehdr = (Elf64_Ehdr *)page_addr;
+ Elf64_Phdr *phdr;
+ int i;
+
+ /* only supports phdr that fits in one page */
+ if (ehdr->e_phnum >
+ (PAGE_SIZE - sizeof(Elf64_Ehdr)) / sizeof(Elf64_Phdr))
+ return -EINVAL;
+
+ phdr = (Elf64_Phdr *)(page_addr + sizeof(Elf64_Ehdr));
+
+ for (i = 0; i < ehdr->e_phnum; ++i) {
+ if (phdr[i].p_type == PT_NOTE &&
+ !parse_build_id(page_addr, build_id,
+ page_addr + phdr[i].p_offset,
+ phdr[i].p_filesz))
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* Parse build ID of ELF file mapped to vma */
+int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id)
+{
+ Elf32_Ehdr *ehdr;
+ struct page *page;
+ void *page_addr;
+ int ret;
+
+ /* only works for page backed storage */
+ if (!vma->vm_file)
+ return -EINVAL;
+
+ page = find_get_page(vma->vm_file->f_mapping, 0);
+ if (!page)
+ return -EFAULT; /* page not mapped */
+
+ ret = -EINVAL;
+ page_addr = kmap_atomic(page);
+ ehdr = (Elf32_Ehdr *)page_addr;
+
+ /* compare magic x7f "ELF" */
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
+ goto out;
+
+ /* only support executable file and shared object file */
+ if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
+ goto out;
+
+ if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
+ ret = get_build_id_32(page_addr, build_id);
+ else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
+ ret = get_build_id_64(page_addr, build_id);
+out:
+ kunmap_atomic(page_addr);
+ put_page(page);
+ return ret;
+}
--
2.26.2
Adding build_id_cache__add function as core function
that adds file into build id database. It will be
sed from another callers in following changes.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/build-id.c | 42 ++++++++++++++++++++++++--------------
tools/perf/util/build-id.h | 2 ++
2 files changed, 29 insertions(+), 15 deletions(-)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index dc8f864fe15a..0d9a473c46d0 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -670,24 +670,15 @@ static char *build_id_cache__find_debug(const char *sbuild_id,
return realname;
}
-int build_id_cache__add_s(const char *sbuild_id, const char *name,
- struct nsinfo *nsi, bool is_kallsyms, bool is_vdso)
+int
+build_id_cache__add(const char *sbuild_id, const char *name, const char *realname,
+ struct nsinfo *nsi, bool is_kallsyms, bool is_vdso)
{
const size_t size = PATH_MAX;
- char *realname = NULL, *filename = NULL, *dir_name = NULL,
- *linkname = zalloc(size), *tmp;
+ char *filename = NULL, *dir_name = NULL, *linkname = zalloc(size), *tmp;
char *debugfile = NULL;
int err = -1;
- if (!is_kallsyms) {
- if (!is_vdso)
- realname = nsinfo__realpath(name, nsi);
- else
- realname = realpath(name, NULL);
- if (!realname)
- goto out_free;
- }
-
dir_name = build_id_cache__cachedir(sbuild_id, name, nsi, is_kallsyms,
is_vdso);
if (!dir_name)
@@ -783,8 +774,6 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
pr_debug4("Failed to update/scan SDT cache for %s\n", realname);
out_free:
- if (!is_kallsyms)
- free(realname);
free(filename);
free(debugfile);
free(dir_name);
@@ -792,6 +781,29 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
return err;
}
+int build_id_cache__add_s(const char *sbuild_id, const char *name,
+ struct nsinfo *nsi, bool is_kallsyms, bool is_vdso)
+{
+ char *realname = NULL;
+ int err = -1;
+
+ if (!is_kallsyms) {
+ if (!is_vdso)
+ realname = nsinfo__realpath(name, nsi);
+ else
+ realname = realpath(name, NULL);
+ if (!realname)
+ goto out_free;
+ }
+
+ err = build_id_cache__add(sbuild_id, name, realname, nsi, is_kallsyms, is_vdso);
+
+out_free:
+ if (!is_kallsyms)
+ free(realname);
+ return err;
+}
+
static int build_id_cache__add_b(const struct build_id *bid,
const char *name, struct nsinfo *nsi,
bool is_kallsyms, bool is_vdso)
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index c6f10e3d2152..02613f4b2c29 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -63,6 +63,8 @@ char *build_id_cache__complement(const char *incomplete_sbuild_id);
int build_id_cache__list_build_ids(const char *pathname, struct nsinfo *nsi,
struct strlist **result);
bool build_id_cache__cached(const char *sbuild_id);
+int build_id_cache__add(const char *sbuild_id, const char *name, const char *realname,
+ struct nsinfo *nsi, bool is_kallsyms, bool is_vdso);
int build_id_cache__add_s(const char *sbuild_id,
const char *name, struct nsinfo *nsi,
bool is_kallsyms, bool is_vdso);
--
2.26.2
Factor filename__decompress from decompress_kmodule function.
It can decompress files with compressions supported in perf -
xz and gz, the support needs to be compiled in.
It will to be used in following changes to get build id out of
compressed elf objects.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/dso.c | 31 +++++++++++++++++++------------
tools/perf/util/dso.h | 2 ++
2 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 89b5fd2b5de3..d786cf6b0cfa 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -279,18 +279,12 @@ bool dso__needs_decompress(struct dso *dso)
dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
}
-static int decompress_kmodule(struct dso *dso, const char *name,
- char *pathname, size_t len)
+int filename__decompress(const char *name, char *pathname,
+ size_t len, int comp, int *err)
{
char tmpbuf[] = KMOD_DECOMP_NAME;
int fd = -1;
- if (!dso__needs_decompress(dso))
- return -1;
-
- if (dso->comp == COMP_ID__NONE)
- return -1;
-
/*
* We have proper compression id for DSO and yet the file
* behind the 'name' can still be plain uncompressed object.
@@ -304,17 +298,17 @@ static int decompress_kmodule(struct dso *dso, const char *name,
* To keep this transparent, we detect this and return the file
* descriptor to the uncompressed file.
*/
- if (!compressions[dso->comp].is_compressed(name))
+ if (!compressions[comp].is_compressed(name))
return open(name, O_RDONLY);
fd = mkstemp(tmpbuf);
if (fd < 0) {
- dso->load_errno = errno;
+ *err = errno;
return -1;
}
- if (compressions[dso->comp].decompress(name, fd)) {
- dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
+ if (compressions[comp].decompress(name, fd)) {
+ *err = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
close(fd);
fd = -1;
}
@@ -328,6 +322,19 @@ static int decompress_kmodule(struct dso *dso, const char *name,
return fd;
}
+static int decompress_kmodule(struct dso *dso, const char *name,
+ char *pathname, size_t len)
+{
+ if (!dso__needs_decompress(dso))
+ return -1;
+
+ if (dso->comp == COMP_ID__NONE)
+ return -1;
+
+ return filename__decompress(name, pathname, len, dso->comp,
+ &dso->load_errno);
+}
+
int dso__decompress_kmodule_fd(struct dso *dso, const char *name)
{
return decompress_kmodule(dso, name, NULL, 0);
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index d8cb4f5680a4..cd2fe64a3c5d 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -274,6 +274,8 @@ bool dso__needs_decompress(struct dso *dso);
int dso__decompress_kmodule_fd(struct dso *dso, const char *name);
int dso__decompress_kmodule_path(struct dso *dso, const char *name,
char *pathname, size_t len);
+int filename__decompress(const char *name, char *pathname,
+ size_t len, int comp, int *err);
#define KMOD_DECOMP_NAME "/tmp/perf-kmod-XXXXXX"
#define KMOD_DECOMP_LEN sizeof(KMOD_DECOMP_NAME)
--
2.26.2
Adding support to specify perf data file as -a option file
argument,
If the file is detected to be perf data file, it is processed
and all dso objects with sample hit are stored to the build
id cache.
$ DEBUGINFOD_URLS=http://192.168.122.174:8002 perf buildid-cache -a perf.data
OK 5dcec522abf136fcfd3128f47e131f2365834dd7 /home/jolsa/.debug/.build-id/5d/cec522abf136fcfd3128f47e131f2365834dd7/elf
OK 5784f813b727a50cfd3363234aef9fcbab685cc4 /lib/modules/5.10.0-rc2speed+/kernel/fs/xfs/xfs.ko
By default we store only dso with hits, but it's possible to
specify 'all' to store all dso objects, like:
-a perf.data,all
$ DEBUGINFOD_URLS=http://192.168.122.174:8002 perf buildid-cache -a perf.data,all
OK 5dcec522abf136fcfd3128f47e131f2365834dd7 /home/jolsa/.debug/.build-id/5d/cec522abf136fcfd3128f47e131f2365834dd7/elf
OK 6ce92dc7c31f12fe5b7775a2bb8b14a3546ce2cd /lib/modules/5.10.0-rc2speed+/kernel/drivers/firmware/qemu_fw_cfg.ko
OK bf3f6d32dccc159f841fc3658c241d0e74c61fbb /lib/modules/5.10.0-rc2speed+/kernel/drivers/block/virtio_blk.ko
OK e896b4329cf9f190f1a0fae933f425ff8f71b052 /lib/modules/5.10.0-rc2speed+/kernel/drivers/char/virtio_console.ko
OK 5bedc933cb59e053ecb472f327bd73c548364479 /lib/modules/5.10.0-rc2speed+/kernel/drivers/input/serio/serio_raw.ko
OK cecc506368a8b7a473a5f900d26f0d3d914a9c23 /lib/modules/5.10.0-rc2speed+/kernel/arch/x86/crypto/crc32c-intel.ko
OK 91076fb3646d061a0a42cf7bddb339a665ee4f80 /lib/modules/5.10.0-rc2speed+/kernel/arch/x86/crypto/ghash-clmulni-intel.ko
OK 4e2a304d788bb8e2e950bc82a5944e042afa0bf2 /lib/modules/5.10.0-rc2speed+/kernel/drivers/media/cec/core/cec.ko
OK 31ab0da5ad81e6803280177f507a95f3053d585e /lib/modules/5.10.0-rc2speed+/kernel/lib/libcrc32c.ko
OK f6154bca47c149f48c942fcc3d653041dd285c65 /lib/modules/5.10.0-rc2speed+/kernel/drivers/gpu/drm/ttm/ttm.ko
OK 723f5852de81590d54b23b38c160d3618b41951b /lib/modules/5.10.0-rc2speed+/kernel/arch/x86/crypto/crct10dif-pclmul.ko
OK 06b1eab7f141cbc3e5a5db47909c8ab5cb242e40 /lib/modules/5.10.0-rc2speed+/kernel/drivers/gpu/drm/drm_ttm_helper.ko
OK 38292b862cf3ff87489508fdb4895efa45780813 /lib/modules/5.10.0-rc2speed+/kernel/drivers/gpu/drm/qxl/qxl.ko
OK cdf51e58609bf2ce4837a7b195e0ccae0a930907 /lib/modules/5.10.0-rc2speed+/kernel/arch/x86/crypto/crc32-pclmul.ko
OK 5ca8958388f6688452ecc2cb83d6031394c659ad /lib/modules/5.10.0-rc2speed+/kernel/drivers/gpu/drm/drm.ko
OK 236bc4e4f38bf3559007566cb32b3dcc1bc28d2d /lib/modules/5.10.0-rc2speed+/kernel/drivers/gpu/drm/drm_kms_helper.ko
OK 5784f813b727a50cfd3363234aef9fcbab685cc4 /lib/modules/5.10.0-rc2speed+/kernel/fs/xfs/xfs.ko
OK 66db2be3efaa43bb5a5c481986e9554e1885cc69 /usr/lib/systemd/systemd
OK 7db607d9f2de89860d9639712da64c8bacd31e4b /usr/lib64/libm-2.30.so
OK 55b5f9652e1d17c1dd58f62628d5063428e5db91 /usr/lib64/libudev.so.1.6.15
OK 63b97070bf097130713bb6c89cf7100b5f3c9b17 /usr/lib64/libunistring.so.2.1.0
...
Once perf data is specified, no other file can be specified in
the option, otherwise it causes syntax error.
Signed-off-by: Jiri Olsa <[email protected]>
---
.../perf/Documentation/perf-buildid-cache.txt | 12 +-
tools/perf/builtin-buildid-cache.c | 215 +++++++++++++++++-
tools/perf/util/probe-event.c | 6 +-
3 files changed, 227 insertions(+), 6 deletions(-)
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
index f6de0952ff3c..b77da5138bca 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -23,7 +23,17 @@ OPTIONS
-------
-a::
--add=::
- Add specified file to the cache.
+ Add specified file or perf.data binaries to the cache.
+
+ If the file is detected to be perf data file, it is processed
+ and all dso objects with sample hit are stored to the cache.
+
+ It's possible to specify 'all' to store all dso objects, like:
+ -a perf.data,all
+
+ Once perf data is specified, no other file can be specified in
+ the option, otherwise it causes syntax error.
+
-f::
--force::
Don't complain, do it.
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index a25411926e48..0bfb54ee1e5e 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -29,6 +29,11 @@
#include "util/probe-file.h"
#include <linux/string.h>
#include <linux/err.h>
+#include <linux/zalloc.h>
+#include <sys/stat.h>
+#ifdef HAVE_DEBUGINFOD_SUPPORT
+#include <elfutils/debuginfod.h>
+#endif
static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
{
@@ -348,6 +353,205 @@ static int build_id_cache__show_all(void)
return 0;
}
+#ifdef HAVE_DEBUGINFOD_SUPPORT
+static int call_debuginfod(const char *sbuild_id, char **path, bool debuginfo)
+{
+ debuginfod_client *c;
+ int fd;
+
+ c = debuginfod_begin();
+ if (c == NULL)
+ return -1;
+
+ pr_debug("trying debuginfod for executable <%s> ... ", sbuild_id);
+
+ if (debuginfo) {
+ fd = debuginfod_find_debuginfo(c, (const unsigned char *) sbuild_id,
+ 0, path);
+ } else {
+ fd = debuginfod_find_executable(c, (const unsigned char *) sbuild_id,
+ 0, path);
+ }
+ if (fd >= 0)
+ close(fd); /* retaining reference by realname */
+
+ debuginfod_end(c);
+ pr_debug("%s%s\n", *path ? "OK " : "FAILED", *path ? *path : "");
+ return *path ? 0 : -1;
+}
+#else
+static int call_debuginfod(const char *sbuild_id __maybe_unused,
+ char **path __maybe_unused,
+ bool debuginfo __maybe_unused)
+{
+ return -1;
+}
+#endif
+
+struct dso_store_data {
+ bool hits;
+ bool force_download;
+};
+
+static int dso_store(struct dso *dso, struct machine *machine, void *priv)
+{
+ struct dso_store_data *data = priv;
+ char sbuild_id[SBUILD_ID_SIZE];
+ struct build_id bid;
+ char *path = NULL, *link = NULL;
+ bool is_kallsyms;
+ int err = -1;
+
+ /*
+ * There's no build id in dso, nothing to do..
+ */
+ if (!dso->has_build_id || !build_id__is_defined(&dso->bid))
+ return 0;
+
+ if (data->hits && !dso->hit)
+ return 0;
+
+ /*
+ * The storing process is:
+ * - get build id of the dso
+ * - check if it is already in cache
+ * - check if it matches provided build id from mmap2 event
+ * - if not, try debuginfod to download the binary
+ * - store binary to build id database
+ */
+ is_kallsyms = !strcmp(machine->mmap_name, dso->short_name);
+ build_id__sprintf(&dso->bid, sbuild_id);
+
+ link = build_id_cache__linkname(sbuild_id, NULL, 0);
+ if (!link)
+ return -ENOMEM;
+
+ if (!data->force_download && !access(link, X_OK)) {
+ pr_debug("already in cache - %s <%s>\n", dso->long_name, sbuild_id);
+ err = 0;
+ goto out;
+ }
+
+ path = strdup(dso->long_name);
+ if (!path)
+ goto out;
+
+ if (is_kallsyms) {
+ /*
+ * Find out if we are on the same kernel as perf.data
+ * and store kallsyms in that case.
+ */
+ err = sysfs__read_build_id("/sys/kernel/notes", &bid);
+ if (err < 0)
+ goto out;
+ } else {
+ struct nscookie nsc;
+ struct stat st;
+
+ nsinfo__mountns_enter(dso->nsinfo, &nsc);
+
+ /*
+ * Does the file exists in the first place, if it does,
+ * resolve path and read the build id.
+ */
+ if (stat(dso->long_name, &st)) {
+ nsinfo__mountns_exit(&nsc);
+ zfree(&path);
+ goto try_download;
+ }
+
+ err = filename__read_build_id(dso->long_name, &bid);
+ nsinfo__mountns_exit(&nsc);
+
+ if (err <= 0)
+ goto out;
+ }
+
+ /*
+ * If we match, then what we want in mmap2 event
+ * is what we got in the binary,
+ */
+ if (bid.size != dso->bid.size || memcmp(&bid, &dso->bid, bid.size)) {
+ char sbid[SBUILD_ID_SIZE];
+
+ build_id__sprintf(&bid, sbid);
+ pr_debug("mmap build id <%s> does not match for %s <%s>\n",
+ sbuild_id, path, sbid);
+ zfree(&path);
+ }
+
+try_download:
+ /*
+ * We did not match build id or did not find the
+ * binary - try debuginfod as last resort.
+ */
+ if (!path) {
+ bool debuginfo;
+ char *tmp = NULL;
+
+ /*
+ * The debuginfo retrieval for standard binaries
+ * is handled within build_id_cache__add function.
+ *
+ * For kernel and kernel modules we have to ask
+ * for debuginfo directly, because debuginfod
+ * does not treat them as binaries.
+ */
+ debuginfo = is_kallsyms ||
+ is_kernel_module(dso->long_name, PERF_RECORD_MISC_CPUMODE_UNKNOWN);
+
+ if (call_debuginfod(sbuild_id, &tmp, debuginfo)) {
+ err = -1;
+ goto out;
+ }
+
+ path = tmp;
+
+ /*
+ * The kernel dso is now elf binary, so disable is_kallsyms
+ * so build_id_cache__add can prepare proper file names.
+ */
+ is_kallsyms = false;
+ }
+
+ pr_debug("linking %s %s <%s>\n", dso->short_name, path, sbuild_id);
+
+ err = build_id_cache__add(sbuild_id, path, path,
+ dso->nsinfo, is_kallsyms, false);
+out:
+ free(path);
+ fprintf(stderr, "%s %s %s\n", err ? "FAIL" : "OK ", sbuild_id, dso->long_name);
+ return 0;
+}
+
+static int
+build_id_cache__add_perf_data(const char *path, bool all)
+{
+ struct perf_session *session;
+ struct dso_store_data priv = {
+ .hits = !all,
+ .force_download = false,
+ };
+ struct perf_data data = {
+ .path = path,
+ .mode = PERF_DATA_MODE_READ,
+ };
+ int err;
+
+ session = perf_session__new(&data, false, &build_id__mark_dso_hit_ops);
+ if (IS_ERR(session))
+ return PTR_ERR(session);
+
+ err = perf_session__process_events(session);
+ if (err)
+ goto out;
+
+ err = __perf_session__cache_build_ids(session, dso_store, &priv);
+out:
+ perf_session__delete(session);
+ return err;
+}
+
int cmd_buildid_cache(int argc, const char **argv)
{
struct strlist *list;
@@ -440,7 +644,15 @@ int cmd_buildid_cache(int argc, const char **argv)
list = strlist__new(add_name_list_str, NULL);
if (list) {
strlist__for_each_entry(pos, list)
- if (build_id_cache__add_file(pos->s, nsi)) {
+ if (is_perf_data(pos->s)) {
+ struct str_node *all_pos = strlist__next(pos);
+ bool all = !strcmp("all", all_pos ? all_pos->s : "");
+
+ if (build_id_cache__add_perf_data(pos->s, all))
+ pr_warning("Couldn't add build ids from %s\n", pos->s);
+ if (all)
+ pos = all_pos;
+ } else if (build_id_cache__add_file(pos->s, nsi)) {
if (errno == EEXIST) {
pr_debug("%s already in the cache\n",
pos->s);
@@ -449,7 +661,6 @@ int cmd_buildid_cache(int argc, const char **argv)
pr_warning("Couldn't add %s: %s\n",
pos->s, str_error_r(errno, sbuf, sizeof(sbuf)));
}
-
strlist__delete(list);
}
}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8eae2afff71a..e821bb977c9b 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1616,9 +1616,9 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
return -EINVAL;
}
- pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
- pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
- pp->lazy_line);
+ pr_debug2("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
+ pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
+ pp->lazy_line);
return 0;
}
--
2.26.2
Using struct extra_kernel_map in machine__process_kernel_mmap_event,
to pass mmap details. This way we can used single function for all 3
mmap versions.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/machine.c | 62 +++++++++++++++++++++------------------
1 file changed, 33 insertions(+), 29 deletions(-)
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 15385ea00190..1ae32a81639c 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1581,32 +1581,25 @@ static bool machine__uses_kcore(struct machine *machine)
}
static bool perf_event__is_extra_kernel_mmap(struct machine *machine,
- union perf_event *event)
+ struct extra_kernel_map *xm)
{
return machine__is(machine, "x86_64") &&
- is_entry_trampoline(event->mmap.filename);
+ is_entry_trampoline(xm->name);
}
static int machine__process_extra_kernel_map(struct machine *machine,
- union perf_event *event)
+ struct extra_kernel_map *xm)
{
struct dso *kernel = machine__kernel_dso(machine);
- struct extra_kernel_map xm = {
- .start = event->mmap.start,
- .end = event->mmap.start + event->mmap.len,
- .pgoff = event->mmap.pgoff,
- };
if (kernel == NULL)
return -1;
- strlcpy(xm.name, event->mmap.filename, KMAP_NAME_LEN);
-
- return machine__create_extra_kernel_map(machine, kernel, &xm);
+ return machine__create_extra_kernel_map(machine, kernel, xm);
}
static int machine__process_kernel_mmap_event(struct machine *machine,
- union perf_event *event)
+ struct extra_kernel_map *xm)
{
struct map *map;
enum dso_space_type dso_space;
@@ -1621,20 +1614,18 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
else
dso_space = DSO_SPACE__KERNEL_GUEST;
- is_kernel_mmap = memcmp(event->mmap.filename,
- machine->mmap_name,
+ is_kernel_mmap = memcmp(xm->name, machine->mmap_name,
strlen(machine->mmap_name) - 1) == 0;
- if (event->mmap.filename[0] == '/' ||
- (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
- map = machine__addnew_module_map(machine, event->mmap.start,
- event->mmap.filename);
+ if (xm->name[0] == '/' ||
+ (!is_kernel_mmap && xm->name[0] == '[')) {
+ map = machine__addnew_module_map(machine, xm->start,
+ xm->name);
if (map == NULL)
goto out_problem;
- map->end = map->start + event->mmap.len;
+ map->end = map->start + xm->end - xm->start;
} else if (is_kernel_mmap) {
- const char *symbol_name = (event->mmap.filename +
- strlen(machine->mmap_name));
+ const char *symbol_name = (xm->name + strlen(machine->mmap_name));
/*
* Should be there already, from the build-id table in
* the header.
@@ -1688,18 +1679,17 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
if (strstr(kernel->long_name, "vmlinux"))
dso__set_short_name(kernel, "[kernel.vmlinux]", false);
- machine__update_kernel_mmap(machine, event->mmap.start,
- event->mmap.start + event->mmap.len);
+ machine__update_kernel_mmap(machine, xm->start, xm->end);
/*
* Avoid using a zero address (kptr_restrict) for the ref reloc
* symbol. Effectively having zero here means that at record
* time /proc/sys/kernel/kptr_restrict was non zero.
*/
- if (event->mmap.pgoff != 0) {
+ if (xm->pgoff != 0) {
map__set_kallsyms_ref_reloc_sym(machine->vmlinux_map,
symbol_name,
- event->mmap.pgoff);
+ xm->pgoff);
}
if (machine__is_default_guest(machine)) {
@@ -1708,8 +1698,8 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
*/
dso__load(kernel, machine__kernel_map(machine));
}
- } else if (perf_event__is_extra_kernel_mmap(machine, event)) {
- return machine__process_extra_kernel_map(machine, event);
+ } else if (perf_event__is_extra_kernel_mmap(machine, xm)) {
+ return machine__process_extra_kernel_map(machine, xm);
}
return 0;
out_problem:
@@ -1735,7 +1725,14 @@ int machine__process_mmap2_event(struct machine *machine,
if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
sample->cpumode == PERF_RECORD_MISC_KERNEL) {
- ret = machine__process_kernel_mmap_event(machine, event);
+ struct extra_kernel_map xm = {
+ .start = event->mmap2.start,
+ .end = event->mmap2.start + event->mmap2.len,
+ .pgoff = event->mmap2.pgoff,
+ };
+
+ strlcpy(xm.name, event->mmap2.filename, KMAP_NAME_LEN);
+ ret = machine__process_kernel_mmap_event(machine, &xm);
if (ret < 0)
goto out_problem;
return 0;
@@ -1785,7 +1782,14 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
sample->cpumode == PERF_RECORD_MISC_KERNEL) {
- ret = machine__process_kernel_mmap_event(machine, event);
+ struct extra_kernel_map xm = {
+ .start = event->mmap.start,
+ .end = event->mmap.start + event->mmap.len,
+ .pgoff = event->mmap.pgoff,
+ };
+
+ strlcpy(xm.name, event->mmap.filename, KMAP_NAME_LEN);
+ ret = machine__process_kernel_mmap_event(machine, &xm);
if (ret < 0)
goto out_problem;
return 0;
--
2.26.2
Allow mmap2 event to synthesize kernel image,
so we can synthesize kernel build id data in
following changes.
It's enabled by new symbol_conf.buildid_mmap2
bool, which will be switched in following
changes.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/symbol_conf.h | 3 ++-
tools/perf/util/synthetic-events.c | 40 ++++++++++++++++++++----------
2 files changed, 29 insertions(+), 14 deletions(-)
diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
index b916afb95ec5..b18f9c8dbb75 100644
--- a/tools/perf/util/symbol_conf.h
+++ b/tools/perf/util/symbol_conf.h
@@ -42,7 +42,8 @@ struct symbol_conf {
report_block,
report_individual_block,
inline_name,
- disable_add2line_warn;
+ disable_add2line_warn,
+ buildid_mmap2;
const char *vmlinux_name,
*kallsyms_name,
*source_prefix,
diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
index 8a23391558cf..872df6d6dbef 100644
--- a/tools/perf/util/synthetic-events.c
+++ b/tools/perf/util/synthetic-events.c
@@ -988,11 +988,12 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine)
{
- size_t size;
+ union perf_event *event;
+ size_t size = symbol_conf.buildid_mmap2 ?
+ sizeof(event->mmap2) : sizeof(event->mmap);
struct map *map = machine__kernel_map(machine);
struct kmap *kmap;
int err;
- union perf_event *event;
if (map == NULL)
return -1;
@@ -1006,7 +1007,7 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
* available use this, and after it is use this as a fallback for older
* kernels.
*/
- event = zalloc((sizeof(event->mmap) + machine->id_hdr_size));
+ event = zalloc(size + machine->id_hdr_size);
if (event == NULL) {
pr_debug("Not enough memory synthesizing mmap event "
"for kernel modules\n");
@@ -1023,16 +1024,29 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
}
- size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
- "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
- size = PERF_ALIGN(size, sizeof(u64));
- event->mmap.header.type = PERF_RECORD_MMAP;
- event->mmap.header.size = (sizeof(event->mmap) -
- (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
- event->mmap.pgoff = kmap->ref_reloc_sym->addr;
- event->mmap.start = map->start;
- event->mmap.len = map->end - event->mmap.start;
- event->mmap.pid = machine->pid;
+ if (symbol_conf.buildid_mmap2) {
+ size = snprintf(event->mmap2.filename, sizeof(event->mmap2.filename),
+ "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
+ size = PERF_ALIGN(size, sizeof(u64));
+ event->mmap2.header.type = PERF_RECORD_MMAP2;
+ event->mmap2.header.size = (sizeof(event->mmap2) -
+ (sizeof(event->mmap2.filename) - size) + machine->id_hdr_size);
+ event->mmap2.pgoff = kmap->ref_reloc_sym->addr;
+ event->mmap2.start = map->start;
+ event->mmap2.len = map->end - event->mmap.start;
+ event->mmap2.pid = machine->pid;
+ } else {
+ size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
+ "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
+ size = PERF_ALIGN(size, sizeof(u64));
+ event->mmap.header.type = PERF_RECORD_MMAP;
+ event->mmap.header.size = (sizeof(event->mmap) -
+ (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
+ event->mmap.pgoff = kmap->ref_reloc_sym->addr;
+ event->mmap.start = map->start;
+ event->mmap.len = map->end - event->mmap.start;
+ event->mmap.pid = machine->pid;
+ }
err = perf_tool__process_synth_event(tool, event, machine, process);
free(event);
--
2.26.2
When processing mmap2 event, check on the build id
misc bit: PERF_RECORD_MISC_BUILD_ID and if it's set,
store the build id in mmap's dso object.
Also adding the build id data arts to struct
perf_record_mmap2 event definition.
Signed-off-by: Jiri Olsa <[email protected]>
---
kernel/events/core.c | 4 ++++
tools/lib/perf/include/perf/event.h | 18 ++++++++++++++----
tools/perf/util/machine.c | 24 +++++++++++++++++++-----
tools/perf/util/map.c | 8 ++++++--
tools/perf/util/map.h | 3 ++-
5 files changed, 45 insertions(+), 12 deletions(-)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 5841b5bca68d..fa7f392c6c0c 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -8017,6 +8017,10 @@ static void perf_event_mmap_output(struct perf_event *event,
__output_copy(&handle, size, 4);
__output_copy(&handle, mmap_event->build_id, BUILD_ID_SIZE);
+
+if (mmap_event->build_id_size > 20)
+ trace_printk("build_id_size %u %s\n", mmap_event->build_id_size, mmap_event->file_name);
+
} else {
perf_output_put(&handle, mmap_event->maj);
perf_output_put(&handle, mmap_event->min);
diff --git a/tools/lib/perf/include/perf/event.h b/tools/lib/perf/include/perf/event.h
index 988c539bedb6..d82054225fcc 100644
--- a/tools/lib/perf/include/perf/event.h
+++ b/tools/lib/perf/include/perf/event.h
@@ -23,10 +23,20 @@ struct perf_record_mmap2 {
__u64 start;
__u64 len;
__u64 pgoff;
- __u32 maj;
- __u32 min;
- __u64 ino;
- __u64 ino_generation;
+ union {
+ struct {
+ __u32 maj;
+ __u32 min;
+ __u64 ino;
+ __u64 ino_generation;
+ };
+ struct {
+ __u8 build_id_size;
+ __u8 __reserved_1;
+ __u16 __reserved_2;
+ __u8 build_id[20];
+ };
+ };
__u32 prot;
__u32 flags;
char filename[PATH_MAX];
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 1ae32a81639c..1edb7d10b042 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1599,7 +1599,8 @@ static int machine__process_extra_kernel_map(struct machine *machine,
}
static int machine__process_kernel_mmap_event(struct machine *machine,
- struct extra_kernel_map *xm)
+ struct extra_kernel_map *xm,
+ struct build_id *bid)
{
struct map *map;
enum dso_space_type dso_space;
@@ -1624,6 +1625,10 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
goto out_problem;
map->end = map->start + xm->end - xm->start;
+
+ if (build_id__is_defined(bid))
+ dso__set_build_id(map->dso, bid);
+
} else if (is_kernel_mmap) {
const char *symbol_name = (xm->name + strlen(machine->mmap_name));
/*
@@ -1681,6 +1686,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
machine__update_kernel_mmap(machine, xm->start, xm->end);
+ if (build_id__is_defined(bid))
+ dso__set_build_id(kernel, bid);
+
/*
* Avoid using a zero address (kptr_restrict) for the ref reloc
* symbol. Effectively having zero here means that at record
@@ -1718,11 +1726,17 @@ int machine__process_mmap2_event(struct machine *machine,
.ino = event->mmap2.ino,
.ino_generation = event->mmap2.ino_generation,
};
+ struct build_id __bid, *bid = NULL;
int ret = 0;
if (dump_trace)
perf_event__fprintf_mmap2(event, stdout);
+ if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
+ bid = &__bid;
+ build_id__init(bid, event->mmap2.build_id, event->mmap2.build_id_size);
+ }
+
if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
sample->cpumode == PERF_RECORD_MISC_KERNEL) {
struct extra_kernel_map xm = {
@@ -1732,7 +1746,7 @@ int machine__process_mmap2_event(struct machine *machine,
};
strlcpy(xm.name, event->mmap2.filename, KMAP_NAME_LEN);
- ret = machine__process_kernel_mmap_event(machine, &xm);
+ ret = machine__process_kernel_mmap_event(machine, &xm, bid);
if (ret < 0)
goto out_problem;
return 0;
@@ -1746,7 +1760,7 @@ int machine__process_mmap2_event(struct machine *machine,
map = map__new(machine, event->mmap2.start,
event->mmap2.len, event->mmap2.pgoff,
&dso_id, event->mmap2.prot,
- event->mmap2.flags,
+ event->mmap2.flags, bid,
event->mmap2.filename, thread);
if (map == NULL)
@@ -1789,7 +1803,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
};
strlcpy(xm.name, event->mmap.filename, KMAP_NAME_LEN);
- ret = machine__process_kernel_mmap_event(machine, &xm);
+ ret = machine__process_kernel_mmap_event(machine, &xm, NULL);
if (ret < 0)
goto out_problem;
return 0;
@@ -1805,7 +1819,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
map = map__new(machine, event->mmap.start,
event->mmap.len, event->mmap.pgoff,
- NULL, prot, 0, event->mmap.filename, thread);
+ NULL, prot, 0, NULL, event->mmap.filename, thread);
if (map == NULL)
goto out_problem_map;
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index f44ede437dc7..692e56dc832e 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -130,8 +130,8 @@ void map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso)
struct map *map__new(struct machine *machine, u64 start, u64 len,
u64 pgoff, struct dso_id *id,
- u32 prot, u32 flags, char *filename,
- struct thread *thread)
+ u32 prot, u32 flags, struct build_id *bid,
+ char *filename, struct thread *thread)
{
struct map *map = malloc(sizeof(*map));
struct nsinfo *nsi = NULL;
@@ -194,6 +194,10 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
dso__set_loaded(dso);
}
dso->nsinfo = nsi;
+
+ if (build_id__is_defined(bid))
+ dso__set_build_id(dso, bid);
+
dso__put(dso);
}
return map;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index b1c0686db1b7..9f32825c98d8 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -104,10 +104,11 @@ void map__init(struct map *map,
u64 start, u64 end, u64 pgoff, struct dso *dso);
struct dso_id;
+struct build_id;
struct map *map__new(struct machine *machine, u64 start, u64 len,
u64 pgoff, struct dso_id *id, u32 prot, u32 flags,
- char *filename, struct thread *thread);
+ struct build_id *bid, char *filename, struct thread *thread);
struct map *map__new2(u64 start, struct dso *dso);
void map__delete(struct map *map);
struct map *map__clone(struct map *map);
--
2.26.2
Add buildid-list support for mmap2's build id data, so we can
display build ids for dso objects for data without the build
id cache update.
$ perf buildid-list
1805c738c8f3ec0f47b7ea09080c28f34d18a82b /usr/lib64/ld-2.31.so
d278249792061c6b74d1693ca59513be1def13f2 /usr/lib64/libc-2.31.so
By default only dso objects with hits are shown.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-buildid-list.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index e3ef75583514..87f5b1a4a7fa 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -77,6 +77,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
perf_header__has_feat(&session->header, HEADER_AUXTRACE))
with_hits = false;
+ if (!perf_header__has_feat(&session->header, HEADER_BUILD_ID))
+ with_hits = true;
+
/*
* in pipe-mode, the only way to get the buildids is to parse
* the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
--
2.26.2
Adding --debuginfod option to specify debuginfod url and
support to do that through config file as well.
Use following in ~/.perfconfig file:
[buildid-cache]
debuginfod=http://192.168.122.174:8002
Signed-off-by: Jiri Olsa <[email protected]>
---
.../perf/Documentation/perf-buildid-cache.txt | 6 ++++
tools/perf/Documentation/perf-config.txt | 7 +++++
tools/perf/builtin-buildid-cache.c | 28 +++++++++++++++++--
3 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
index b77da5138bca..75385f4dc11f 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -84,6 +84,12 @@ OPTIONS
used when creating a uprobe for a process that resides in a
different mount namespace from the perf(1) utility.
+--debuginfod=URL::
+ Specify debuginfod URL to be used when retrieving perf.data binaries,
+ it follows the same syntax as the DEBUGINFOD_URLS variable, like:
+
+ buildid-cache.debuginfod=http://192.168.122.174:8002
+
SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-buildid-list[1]
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index 31069d8a5304..15fad32b9885 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -238,6 +238,13 @@ buildid.*::
cache location, or to disable it altogether. If you want to disable it,
set buildid.dir to /dev/null. The default is $HOME/.debug
+buildid-cache.*::
+ buildid-cache.debuginfod=URL
+ Specify debuginfod URL to be used when retrieving perf.data binaries,
+ it follows the same syntax as the DEBUGINFOD_URLS variable, like:
+
+ buildid-cache.debuginfod=http://192.168.122.174:8002
+
annotate.*::
These are in control of addresses, jump function, source code
in lines of assembly code from a specific program.
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 0bfb54ee1e5e..fc03de7d2a28 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -27,6 +27,7 @@
#include "util/time-utils.h"
#include "util/util.h"
#include "util/probe-file.h"
+#include "util/config.h"
#include <linux/string.h>
#include <linux/err.h>
#include <linux/zalloc.h>
@@ -552,12 +553,21 @@ build_id_cache__add_perf_data(const char *path, bool all)
return err;
}
+static int perf_buildid_cache_config(const char *var, const char *value, void *cb)
+{
+ const char **debuginfod = cb;
+
+ if (!strcmp(var, "buildid-cache.debuginfod"))
+ *debuginfod = strdup(value);
+
+ return 0;
+}
+
int cmd_buildid_cache(int argc, const char **argv)
{
struct strlist *list;
struct str_node *pos;
- int ret = 0;
- int ns_id = -1;
+ int ret, ns_id = -1;
bool force = false;
bool list_files = false;
bool opts_flag = false;
@@ -567,7 +577,8 @@ int cmd_buildid_cache(int argc, const char **argv)
*purge_name_list_str = NULL,
*missing_filename = NULL,
*update_name_list_str = NULL,
- *kcore_filename = NULL;
+ *kcore_filename = NULL,
+ *debuginfod = NULL;
char sbuf[STRERR_BUFSIZE];
struct perf_data data = {
@@ -592,6 +603,8 @@ int cmd_buildid_cache(int argc, const char **argv)
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
OPT_STRING('u', "update", &update_name_list_str, "file list",
"file(s) to update"),
+ OPT_STRING(0, "debuginfod", &debuginfod, "debuginfod url",
+ "set debuginfod url"),
OPT_INCR('v', "verbose", &verbose, "be more verbose"),
OPT_INTEGER(0, "target-ns", &ns_id, "target pid for namespace context"),
OPT_END()
@@ -601,6 +614,10 @@ int cmd_buildid_cache(int argc, const char **argv)
NULL
};
+ ret = perf_config(perf_buildid_cache_config, &debuginfod);
+ if (ret)
+ return ret;
+
argc = parse_options(argc, argv, buildid_cache_options,
buildid_cache_usage, 0);
@@ -612,6 +629,11 @@ int cmd_buildid_cache(int argc, const char **argv)
if (argc || !(list_files || opts_flag))
usage_with_options(buildid_cache_usage, buildid_cache_options);
+ if (debuginfod) {
+ pr_debug("DEBUGINFOD_URLS=%s\n", debuginfod);
+ setenv("DEBUGINFOD_URLS", debuginfod, 1);
+ }
+
/* -l is exclusive. It can not be used with other options. */
if (list_files && opts_flag) {
usage_with_options_msg(buildid_cache_usage,
--
2.26.2
Adding build id to synthesized mmap2 events for
everything - kernel/modules/tasks.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/synthetic-events.c | 32 ++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
index a18ae502d765..91b1962d399c 100644
--- a/tools/perf/util/synthetic-events.c
+++ b/tools/perf/util/synthetic-events.c
@@ -347,6 +347,31 @@ static bool read_proc_maps_line(struct io *io, __u64 *start, __u64 *end,
}
}
+static void perf_record_mmap2__read_build_id(struct perf_record_mmap2 *event,
+ bool is_kernel)
+{
+ struct build_id bid;
+ int rc;
+
+ if (is_kernel)
+ rc = sysfs__read_build_id("/sys/kernel/notes", &bid);
+ else
+ rc = filename__read_build_id(event->filename, &bid) > 0 ? 0 : -1;
+
+ if (rc == 0) {
+ memcpy(event->build_id, bid.data, sizeof(bid.data));
+ event->build_id_size = (u8) bid.size;
+ event->header.misc |= PERF_RECORD_MISC_MMAP_BUILD_ID;
+ event->__reserved_1 = 0;
+ event->__reserved_2 = 0;
+ } else {
+ if (event->filename[0] == '/') {
+ pr_debug2("Failed to read build ID for %s\n",
+ event->filename);
+ }
+ }
+}
+
int perf_event__synthesize_mmap_events(struct perf_tool *tool,
union perf_event *event,
pid_t pid, pid_t tgid,
@@ -453,6 +478,9 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
event->mmap2.pid = tgid;
event->mmap2.tid = pid;
+ if (symbol_conf.buildid_mmap2)
+ perf_record_mmap2__read_build_id(&event->mmap2, false);
+
if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
rc = -1;
break;
@@ -630,6 +658,8 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t
memcpy(event->mmap2.filename, pos->dso->long_name,
pos->dso->long_name_len + 1);
+
+ perf_record_mmap2__read_build_id(&event->mmap2, false);
} else {
size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
event->mmap.header.type = PERF_RECORD_MMAP;
@@ -1050,6 +1080,8 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
event->mmap2.start = map->start;
event->mmap2.len = map->end - event->mmap.start;
event->mmap2.pid = machine->pid;
+
+ perf_record_mmap2__read_build_id(&event->mmap2, true);
} else {
size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
"%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
--
2.26.2
Adding --buildid-mmap option to enable build id in mmap2 events.
It will only work if there's kernel support for that and it disables
build id cache (implies --no-buildid).
It's also possible to enable it permanently via config option
in ~.perfconfig file:
[record]
build-id=mmap
Also added build_id bit in the verbose output for perf_event_attr:
# perf record --buildid-mmap -vv
...
perf_event_attr:
type 1
size 120
...
build_id 1
Adding also missing text_poke bit.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/Documentation/perf-config.txt | 3 ++-
tools/perf/Documentation/perf-record.txt | 3 +++
tools/perf/builtin-record.c | 20 ++++++++++++++++++++
tools/perf/util/evsel.c | 10 ++++++----
tools/perf/util/perf_api_probe.c | 10 ++++++++++
tools/perf/util/perf_api_probe.h | 1 +
tools/perf/util/perf_event_attr_fprintf.c | 2 ++
tools/perf/util/record.h | 1 +
8 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index 15fad32b9885..66a697ed9655 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -559,11 +559,12 @@ kmem.*::
record.*::
record.build-id::
- This option can be 'cache', 'no-cache' or 'skip'.
+ This option can be 'cache', 'no-cache', 'skip' or 'mmap'.
'cache' is to post-process data and save/update the binaries into
the build-id cache (in ~/.debug). This is the default.
But if this option is 'no-cache', it will not update the build-id cache.
'skip' skips post-processing and does not update the cache.
+ 'mmap' skips post-processing and reads build-ids from MMAP events.
record.call-graph::
This is identical to 'call-graph.record-mode', except it is
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 768888b9326a..1bcf51e24979 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -482,6 +482,9 @@ Specify vmlinux path which has debuginfo.
--buildid-all::
Record build-id of all DSOs regardless whether it's actually hit or not.
+--buildid-mmap::
+Record build ids in mmap2 events, disables build id cache (implies --no-buildid).
+
--aio[=n]::
Use <n> control blocks in asynchronous (Posix AIO) trace writing mode (default: 1, max: 4).
Asynchronous mode is supported only when linking Perf tool with libc library
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index adf311d15d3d..47bae9d82d43 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -102,6 +102,7 @@ struct record {
bool no_buildid_cache;
bool no_buildid_cache_set;
bool buildid_all;
+ bool buildid_mmap;
bool timestamp_filename;
bool timestamp_boundary;
struct switch_output switch_output;
@@ -2139,6 +2140,8 @@ static int perf_record_config(const char *var, const char *value, void *cb)
rec->no_buildid_cache = true;
else if (!strcmp(value, "skip"))
rec->no_buildid = true;
+ else if (!strcmp(value, "mmap"))
+ rec->buildid_mmap = true;
else
return -1;
return 0;
@@ -2554,6 +2557,8 @@ static struct option __record_options[] = {
"file", "vmlinux pathname"),
OPT_BOOLEAN(0, "buildid-all", &record.buildid_all,
"Record build-id of all DSOs regardless of hits"),
+ OPT_BOOLEAN(0, "buildid-mmap", &record.buildid_mmap,
+ "Record build-id in map events"),
OPT_BOOLEAN(0, "timestamp-filename", &record.timestamp_filename,
"append timestamp to output filename"),
OPT_BOOLEAN(0, "timestamp-boundary", &record.timestamp_boundary,
@@ -2657,6 +2662,21 @@ int cmd_record(int argc, const char **argv)
}
+ if (rec->buildid_mmap) {
+ if (!perf_can_record_build_id()) {
+ pr_err("Failed: no support to record build id in mmap events, update your kernel.\n");
+ err = -EINVAL;
+ goto out_opts;
+ }
+ pr_debug("Enabling build id in mmap2 events.\n");
+ /* Enable mmap build id synthesizing. */
+ symbol_conf.buildid_mmap2 = true;
+ /* Enable perf_event_attr::build_id bit. */
+ rec->opts.build_id = true;
+ /* Disable build id cache. */
+ rec->no_buildid = true;
+ }
+
if (rec->opts.kcore)
rec->data.is_dir = true;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1cad6051d8b0..749d806ee1d1 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1170,10 +1170,12 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts,
if (opts->sample_weight)
evsel__set_sample_bit(evsel, WEIGHT);
- attr->task = track;
- attr->mmap = track;
- attr->mmap2 = track && !perf_missing_features.mmap2;
- attr->comm = track;
+ attr->task = track;
+ attr->mmap = track;
+ attr->mmap2 = track && !perf_missing_features.mmap2;
+ attr->comm = track;
+ attr->build_id = track && opts->build_id;
+
/*
* ksymbol is tracked separately with text poke because it needs to be
* system wide and enabled immediately.
diff --git a/tools/perf/util/perf_api_probe.c b/tools/perf/util/perf_api_probe.c
index 3840d02f0f7b..829af17a0867 100644
--- a/tools/perf/util/perf_api_probe.c
+++ b/tools/perf/util/perf_api_probe.c
@@ -98,6 +98,11 @@ static void perf_probe_text_poke(struct evsel *evsel)
evsel->core.attr.text_poke = 1;
}
+static void perf_probe_build_id(struct evsel *evsel)
+{
+ evsel->core.attr.build_id = 1;
+}
+
bool perf_can_sample_identifier(void)
{
return perf_probe_api(perf_probe_sample_identifier);
@@ -172,3 +177,8 @@ bool perf_can_aux_sample(void)
return true;
}
+
+bool perf_can_record_build_id(void)
+{
+ return perf_probe_api(perf_probe_build_id);
+}
diff --git a/tools/perf/util/perf_api_probe.h b/tools/perf/util/perf_api_probe.h
index d5506a983a94..f12ca55f509a 100644
--- a/tools/perf/util/perf_api_probe.h
+++ b/tools/perf/util/perf_api_probe.h
@@ -11,5 +11,6 @@ bool perf_can_record_cpu_wide(void);
bool perf_can_record_switch_events(void);
bool perf_can_record_text_poke_events(void);
bool perf_can_sample_identifier(void);
+bool perf_can_record_build_id(void);
#endif // __PERF_API_PROBE_H
diff --git a/tools/perf/util/perf_event_attr_fprintf.c b/tools/perf/util/perf_event_attr_fprintf.c
index e67a227c0ce7..656a7fddfc26 100644
--- a/tools/perf/util/perf_event_attr_fprintf.c
+++ b/tools/perf/util/perf_event_attr_fprintf.c
@@ -134,6 +134,8 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr,
PRINT_ATTRf(bpf_event, p_unsigned);
PRINT_ATTRf(aux_output, p_unsigned);
PRINT_ATTRf(cgroup, p_unsigned);
+ PRINT_ATTRf(text_poke, p_unsigned);
+ PRINT_ATTRf(build_id, p_unsigned);
PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned);
PRINT_ATTRf(bp_type, p_unsigned);
diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h
index 266760ac9143..609e706f4282 100644
--- a/tools/perf/util/record.h
+++ b/tools/perf/util/record.h
@@ -49,6 +49,7 @@ struct record_opts {
bool no_bpf_event;
bool kcore;
bool text_poke;
+ bool build_id;
unsigned int freq;
unsigned int mmap_pages;
unsigned int auxtrace_mmap_pages;
--
2.26.2
Adding __perf_session__cache_build_ids function as an
interface for caching sessions build ids with callback
function and its data pointer.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/build-id.c | 10 ++++++++--
tools/perf/util/build-id.h | 3 +++
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 9f14d5851bb5..dc8f864fe15a 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -887,7 +887,8 @@ machines__for_each_dso(struct machines *machines, machine__dso_t fn, void *priv)
return ret ? -1 : 0;
}
-int perf_session__cache_build_ids(struct perf_session *session)
+int __perf_session__cache_build_ids(struct perf_session *session,
+ machine__dso_t fn, void *priv)
{
if (no_buildid_cache)
return 0;
@@ -895,7 +896,12 @@ int perf_session__cache_build_ids(struct perf_session *session)
if (mkdir(buildid_dir, 0755) != 0 && errno != EEXIST)
return -1;
- return machines__for_each_dso(&session->machines, dso__cache_build_id, NULL) ? -1 : 0;
+ return machines__for_each_dso(&session->machines, fn, priv) ? -1 : 0;
+}
+
+int perf_session__cache_build_ids(struct perf_session *session)
+{
+ return __perf_session__cache_build_ids(session, dso__cache_build_id, NULL);
}
static bool machine__read_build_ids(struct machine *machine, bool with_hits)
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index f1a2f67df6e4..c6f10e3d2152 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -5,6 +5,7 @@
#define BUILD_ID_SIZE 20
#define SBUILD_ID_SIZE (BUILD_ID_SIZE * 2 + 1)
+#include "machine.h"
#include "tool.h"
#include <linux/types.h>
@@ -46,6 +47,8 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
int perf_session__write_buildid_table(struct perf_session *session,
struct feat_fd *fd);
int perf_session__cache_build_ids(struct perf_session *session);
+int __perf_session__cache_build_ids(struct perf_session *session,
+ machine__dso_t fn, void *priv);
char *build_id_cache__origname(const char *sbuild_id);
char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
--
2.26.2
Adding is_perf_data function that returns true if
the given path is perf data file. It will be used
in following patches.
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/util/data.c | 19 +++++++++++++++++++
tools/perf/util/data.h | 1 +
2 files changed, 20 insertions(+)
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index c47aa34fdc0a..be049e812f5a 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -457,3 +457,22 @@ char *perf_data__kallsyms_name(struct perf_data *data)
return kallsyms_name;
}
+
+bool is_perf_data(const char *path)
+{
+ bool ret = false;
+ FILE *file;
+ u64 magic;
+
+ file = fopen(path, "r");
+ if (!file)
+ return false;
+
+ if (fread(&magic, 1, 8, file) < 8)
+ goto out;
+
+ ret = is_perf_magic(magic);
+out:
+ fclose(file);
+ return ret;
+}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 75947ef6bc17..0ebb1568ca86 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -89,4 +89,5 @@ int perf_data__update_dir(struct perf_data *data);
unsigned long perf_data__size(struct perf_data *data);
int perf_data__make_kcore_dir(struct perf_data *data, char *buf, size_t buf_sz);
char *perf_data__kallsyms_name(struct perf_data *data);
+bool is_perf_data(const char *path);
#endif /* __PERF_DATA_H */
--
2.26.2
On Tue, Nov 17, 2020 at 12:00:32PM +0100, Jiri Olsa wrote:
> Adding support to carry build id data in mmap2 event.
>
> The build id data replaces maj/min/ino/ino_generation
> fields, which are also used to identify map's binary,
> so it's ok to replace them with build id data:
>
> union {
> struct {
> u32 maj;
> u32 min;
> u64 ino;
> u64 ino_generation;
> };
> struct {
> u8 build_id_size;
> u8 __reserved_1;
> u16 __reserved_2;
> u8 build_id[20];
> };
> };
>
> Replaced maj/min/ino/ino_generation fields give us size
> of 24 bytes. We use 20 bytes for build id data, 1 byte
> for size and rest is unused.
>
> There's new misc bit for mmap2 to signal there's build
> id data in it:
>
> #define PERF_RECORD_MISC_MMAP_BUILD_ID (1 << 14)
>
> Signed-off-by: Jiri Olsa <[email protected]>
Seems sane enough; how do we want to route this?
Acked-by: Peter Zijlstra (Intel) <[email protected]>
Em Tue, Nov 17, 2020 at 12:00:37PM +0100, Jiri Olsa escreveu:
> Adding support to decompress file before reading build id.
>
> Adding filename__read_build_id and change its current
> versions to read_build_id.
>
> Shutting down stderr output of perf list in the shell test:
> 82: Check open filename arg using perf trace + vfs_getname : Ok
>
> because with decompression code in the place we the
> filename__read_build_id function is more verbose in case
> of error and the test did not account for that.
---
because with decompression code in place filename__read_build_id() is
more verbose in case of an error and the test didn't account for that.
---
I'll fix it up when applying :-)
- Arnaldo
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> .../tests/shell/trace+probe_vfs_getname.sh | 2 +-
> tools/perf/util/symbol-elf.c | 37 ++++++++++++++++++-
> 2 files changed, 36 insertions(+), 3 deletions(-)
>
> diff --git a/tools/perf/tests/shell/trace+probe_vfs_getname.sh b/tools/perf/tests/shell/trace+probe_vfs_getname.sh
> index 11cc2af13f2b..3660fcc02fef 100755
> --- a/tools/perf/tests/shell/trace+probe_vfs_getname.sh
> +++ b/tools/perf/tests/shell/trace+probe_vfs_getname.sh
> @@ -20,7 +20,7 @@ skip_if_no_perf_trace || exit 2
> file=$(mktemp /tmp/temporary_file.XXXXX)
>
> trace_open_vfs_getname() {
> - evts=$(echo $(perf list syscalls:sys_enter_open* 2>&1 | egrep 'open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/') | sed 's/ /,/')
> + evts=$(echo $(perf list syscalls:sys_enter_open* >&1 2>/dev/nul | egrep 'open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/') | sed 's/ /,/')
> perf trace -e $evts touch $file 2>&1 | \
> egrep " +[0-9]+\.[0-9]+ +\( +[0-9]+\.[0-9]+ ms\): +touch\/[0-9]+ open(at)?\((dfd: +CWD, +)?filename: +${file}, +flags: CREAT\|NOCTTY\|NONBLOCK\|WRONLY, +mode: +IRUGO\|IWUGO\) += +[0-9]+$"
> }
> diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
> index 44dd86a4f25f..f3577f7d72fe 100644
> --- a/tools/perf/util/symbol-elf.c
> +++ b/tools/perf/util/symbol-elf.c
> @@ -534,7 +534,7 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
>
> #ifdef HAVE_LIBBFD_BUILDID_SUPPORT
>
> -int filename__read_build_id(const char *filename, struct build_id *bid)
> +static int read_build_id(const char *filename, struct build_id *bid)
> {
> size_t size = sizeof(bid->data);
> int err = -1;
> @@ -563,7 +563,7 @@ int filename__read_build_id(const char *filename, struct build_id *bid)
>
> #else // HAVE_LIBBFD_BUILDID_SUPPORT
>
> -int filename__read_build_id(const char *filename, struct build_id *bid)
> +static int read_build_id(const char *filename, struct build_id *bid)
> {
> size_t size = sizeof(bid->data);
> int fd, err = -1;
> @@ -595,6 +595,39 @@ int filename__read_build_id(const char *filename, struct build_id *bid)
>
> #endif // HAVE_LIBBFD_BUILDID_SUPPORT
>
> +int filename__read_build_id(const char *filename, struct build_id *bid)
> +{
> + struct kmod_path m = { .name = NULL, };
> + char path[PATH_MAX];
> + int err;
> +
> + if (!filename)
> + return -EFAULT;
> +
> + err = kmod_path__parse(&m, filename);
> + if (err)
> + return -1;
> +
> + if (m.comp) {
> + int error = 0, fd;
> +
> + fd = filename__decompress(filename, path, sizeof(path), m.comp, &error);
> + if (fd < 0) {
> + pr_debug("Failed to decompress (error %d) %s\n",
> + error, filename);
> + return -1;
> + }
> + close(fd);
> + filename = path;
> + }
> +
> + err = read_build_id(filename, bid);
> +
> + if (m.comp)
> + unlink(filename);
> + return err;
> +}
> +
> int sysfs__read_build_id(const char *filename, struct build_id *bid)
> {
> size_t size = sizeof(bid->data);
> --
> 2.26.2
>
--
- Arnaldo
Em Tue, Nov 17, 2020 at 12:00:41PM +0100, Jiri Olsa escreveu:
> When processing mmap2 event, check on the build id
> misc bit: PERF_RECORD_MISC_BUILD_ID and if it's set,
> store the build id in mmap's dso object.
>
> Also adding the build id data arts to struct
> perf_record_mmap2 event definition.
>
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> kernel/events/core.c | 4 ++++
> tools/lib/perf/include/perf/event.h | 18 ++++++++++++++----
> tools/perf/util/machine.c | 24 +++++++++++++++++++-----
> tools/perf/util/map.c | 8 ++++++--
> tools/perf/util/map.h | 3 ++-
> 5 files changed, 45 insertions(+), 12 deletions(-)
You mixed up kernel changes with tools/ changes, can you please split
this up?
Also there is an indentation problem in the kernel changes, which, I
think, is just debugging cruft that you forgot to excise? :-)
- Arnaldo
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index 5841b5bca68d..fa7f392c6c0c 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -8017,6 +8017,10 @@ static void perf_event_mmap_output(struct perf_event *event,
>
> __output_copy(&handle, size, 4);
> __output_copy(&handle, mmap_event->build_id, BUILD_ID_SIZE);
> +
> +if (mmap_event->build_id_size > 20)
> + trace_printk("build_id_size %u %s\n", mmap_event->build_id_size, mmap_event->file_name);
> +
> } else {
> perf_output_put(&handle, mmap_event->maj);
> perf_output_put(&handle, mmap_event->min);
> diff --git a/tools/lib/perf/include/perf/event.h b/tools/lib/perf/include/perf/event.h
> index 988c539bedb6..d82054225fcc 100644
> --- a/tools/lib/perf/include/perf/event.h
> +++ b/tools/lib/perf/include/perf/event.h
> @@ -23,10 +23,20 @@ struct perf_record_mmap2 {
> __u64 start;
> __u64 len;
> __u64 pgoff;
> - __u32 maj;
> - __u32 min;
> - __u64 ino;
> - __u64 ino_generation;
> + union {
> + struct {
> + __u32 maj;
> + __u32 min;
> + __u64 ino;
> + __u64 ino_generation;
> + };
> + struct {
> + __u8 build_id_size;
> + __u8 __reserved_1;
> + __u16 __reserved_2;
> + __u8 build_id[20];
> + };
> + };
> __u32 prot;
> __u32 flags;
> char filename[PATH_MAX];
> diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
> index 1ae32a81639c..1edb7d10b042 100644
> --- a/tools/perf/util/machine.c
> +++ b/tools/perf/util/machine.c
> @@ -1599,7 +1599,8 @@ static int machine__process_extra_kernel_map(struct machine *machine,
> }
>
> static int machine__process_kernel_mmap_event(struct machine *machine,
> - struct extra_kernel_map *xm)
> + struct extra_kernel_map *xm,
> + struct build_id *bid)
> {
> struct map *map;
> enum dso_space_type dso_space;
> @@ -1624,6 +1625,10 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
> goto out_problem;
>
> map->end = map->start + xm->end - xm->start;
> +
> + if (build_id__is_defined(bid))
> + dso__set_build_id(map->dso, bid);
> +
> } else if (is_kernel_mmap) {
> const char *symbol_name = (xm->name + strlen(machine->mmap_name));
> /*
> @@ -1681,6 +1686,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
>
> machine__update_kernel_mmap(machine, xm->start, xm->end);
>
> + if (build_id__is_defined(bid))
> + dso__set_build_id(kernel, bid);
> +
> /*
> * Avoid using a zero address (kptr_restrict) for the ref reloc
> * symbol. Effectively having zero here means that at record
> @@ -1718,11 +1726,17 @@ int machine__process_mmap2_event(struct machine *machine,
> .ino = event->mmap2.ino,
> .ino_generation = event->mmap2.ino_generation,
> };
> + struct build_id __bid, *bid = NULL;
> int ret = 0;
>
> if (dump_trace)
> perf_event__fprintf_mmap2(event, stdout);
>
> + if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
> + bid = &__bid;
> + build_id__init(bid, event->mmap2.build_id, event->mmap2.build_id_size);
> + }
> +
> if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
> sample->cpumode == PERF_RECORD_MISC_KERNEL) {
> struct extra_kernel_map xm = {
> @@ -1732,7 +1746,7 @@ int machine__process_mmap2_event(struct machine *machine,
> };
>
> strlcpy(xm.name, event->mmap2.filename, KMAP_NAME_LEN);
> - ret = machine__process_kernel_mmap_event(machine, &xm);
> + ret = machine__process_kernel_mmap_event(machine, &xm, bid);
> if (ret < 0)
> goto out_problem;
> return 0;
> @@ -1746,7 +1760,7 @@ int machine__process_mmap2_event(struct machine *machine,
> map = map__new(machine, event->mmap2.start,
> event->mmap2.len, event->mmap2.pgoff,
> &dso_id, event->mmap2.prot,
> - event->mmap2.flags,
> + event->mmap2.flags, bid,
> event->mmap2.filename, thread);
>
> if (map == NULL)
> @@ -1789,7 +1803,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
> };
>
> strlcpy(xm.name, event->mmap.filename, KMAP_NAME_LEN);
> - ret = machine__process_kernel_mmap_event(machine, &xm);
> + ret = machine__process_kernel_mmap_event(machine, &xm, NULL);
> if (ret < 0)
> goto out_problem;
> return 0;
> @@ -1805,7 +1819,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
>
> map = map__new(machine, event->mmap.start,
> event->mmap.len, event->mmap.pgoff,
> - NULL, prot, 0, event->mmap.filename, thread);
> + NULL, prot, 0, NULL, event->mmap.filename, thread);
>
> if (map == NULL)
> goto out_problem_map;
> diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
> index f44ede437dc7..692e56dc832e 100644
> --- a/tools/perf/util/map.c
> +++ b/tools/perf/util/map.c
> @@ -130,8 +130,8 @@ void map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso)
>
> struct map *map__new(struct machine *machine, u64 start, u64 len,
> u64 pgoff, struct dso_id *id,
> - u32 prot, u32 flags, char *filename,
> - struct thread *thread)
> + u32 prot, u32 flags, struct build_id *bid,
> + char *filename, struct thread *thread)
> {
> struct map *map = malloc(sizeof(*map));
> struct nsinfo *nsi = NULL;
> @@ -194,6 +194,10 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
> dso__set_loaded(dso);
> }
> dso->nsinfo = nsi;
> +
> + if (build_id__is_defined(bid))
> + dso__set_build_id(dso, bid);
> +
> dso__put(dso);
> }
> return map;
> diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
> index b1c0686db1b7..9f32825c98d8 100644
> --- a/tools/perf/util/map.h
> +++ b/tools/perf/util/map.h
> @@ -104,10 +104,11 @@ void map__init(struct map *map,
> u64 start, u64 end, u64 pgoff, struct dso *dso);
>
> struct dso_id;
> +struct build_id;
>
> struct map *map__new(struct machine *machine, u64 start, u64 len,
> u64 pgoff, struct dso_id *id, u32 prot, u32 flags,
> - char *filename, struct thread *thread);
> + struct build_id *bid, char *filename, struct thread *thread);
> struct map *map__new2(u64 start, struct dso *dso);
> void map__delete(struct map *map);
> struct map *map__clone(struct map *map);
> --
> 2.26.2
>
--
- Arnaldo
Em Tue, Nov 17, 2020 at 12:00:42PM +0100, Jiri Olsa escreveu:
> Allow mmap2 event to synthesize kernel image,
> so we can synthesize kernel build id data in
> following changes.
>
> It's enabled by new symbol_conf.buildid_mmap2
> bool, which will be switched in following
> changes.
Why make this an option? MMAP2 goes back years:
13d7a2410fa637f45 (Stephane Eranian 2013-08-21 12:10:24 +0200 904) * The MMAP2 records are an augmented version of MMAP, they add
13d7a2410fa637f45 (Stephane Eranian 2013-08-21 12:10:24 +0200 905) * maj, min, ino numbers to be used to uniquely identify each mapping
Also we unconditionally generate MMAP2 events if the kernel supports it,
from evsel__config():
attr->mmap = track;
attr->mmap2 = track && !perf_missing_features.mmap2;
So perhaps we should reuse that logic? I.e. use mmap2 if the kernel
supports it?
- Arnaldo
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> tools/perf/util/symbol_conf.h | 3 ++-
> tools/perf/util/synthetic-events.c | 40 ++++++++++++++++++++----------
> 2 files changed, 29 insertions(+), 14 deletions(-)
>
> diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
> index b916afb95ec5..b18f9c8dbb75 100644
> --- a/tools/perf/util/symbol_conf.h
> +++ b/tools/perf/util/symbol_conf.h
> @@ -42,7 +42,8 @@ struct symbol_conf {
> report_block,
> report_individual_block,
> inline_name,
> - disable_add2line_warn;
> + disable_add2line_warn,
> + buildid_mmap2;
> const char *vmlinux_name,
> *kallsyms_name,
> *source_prefix,
> diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
> index 8a23391558cf..872df6d6dbef 100644
> --- a/tools/perf/util/synthetic-events.c
> +++ b/tools/perf/util/synthetic-events.c
> @@ -988,11 +988,12 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
> perf_event__handler_t process,
> struct machine *machine)
> {
> - size_t size;
> + union perf_event *event;
> + size_t size = symbol_conf.buildid_mmap2 ?
> + sizeof(event->mmap2) : sizeof(event->mmap);
> struct map *map = machine__kernel_map(machine);
> struct kmap *kmap;
> int err;
> - union perf_event *event;
>
> if (map == NULL)
> return -1;
> @@ -1006,7 +1007,7 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
> * available use this, and after it is use this as a fallback for older
> * kernels.
> */
> - event = zalloc((sizeof(event->mmap) + machine->id_hdr_size));
> + event = zalloc(size + machine->id_hdr_size);
> if (event == NULL) {
> pr_debug("Not enough memory synthesizing mmap event "
> "for kernel modules\n");
> @@ -1023,16 +1024,29 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
> event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
> }
>
> - size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
> - "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
> - size = PERF_ALIGN(size, sizeof(u64));
> - event->mmap.header.type = PERF_RECORD_MMAP;
> - event->mmap.header.size = (sizeof(event->mmap) -
> - (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
> - event->mmap.pgoff = kmap->ref_reloc_sym->addr;
> - event->mmap.start = map->start;
> - event->mmap.len = map->end - event->mmap.start;
> - event->mmap.pid = machine->pid;
> + if (symbol_conf.buildid_mmap2) {
> + size = snprintf(event->mmap2.filename, sizeof(event->mmap2.filename),
> + "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
> + size = PERF_ALIGN(size, sizeof(u64));
> + event->mmap2.header.type = PERF_RECORD_MMAP2;
> + event->mmap2.header.size = (sizeof(event->mmap2) -
> + (sizeof(event->mmap2.filename) - size) + machine->id_hdr_size);
> + event->mmap2.pgoff = kmap->ref_reloc_sym->addr;
> + event->mmap2.start = map->start;
> + event->mmap2.len = map->end - event->mmap.start;
> + event->mmap2.pid = machine->pid;
> + } else {
> + size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
> + "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
> + size = PERF_ALIGN(size, sizeof(u64));
> + event->mmap.header.type = PERF_RECORD_MMAP;
> + event->mmap.header.size = (sizeof(event->mmap) -
> + (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
> + event->mmap.pgoff = kmap->ref_reloc_sym->addr;
> + event->mmap.start = map->start;
> + event->mmap.len = map->end - event->mmap.start;
> + event->mmap.pid = machine->pid;
> + }
>
> err = perf_tool__process_synth_event(tool, event, machine, process);
> free(event);
> --
> 2.26.2
>
--
- Arnaldo
Em Tue, Nov 17, 2020 at 12:00:44PM +0100, Jiri Olsa escreveu:
> Adding build id to synthesized mmap2 events for
> everything - kernel/modules/tasks.
>
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> tools/perf/util/synthetic-events.c | 32 ++++++++++++++++++++++++++++++
> 1 file changed, 32 insertions(+)
>
> diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
> index a18ae502d765..91b1962d399c 100644
> --- a/tools/perf/util/synthetic-events.c
> +++ b/tools/perf/util/synthetic-events.c
> @@ -347,6 +347,31 @@ static bool read_proc_maps_line(struct io *io, __u64 *start, __u64 *end,
> }
> }
>
> +static void perf_record_mmap2__read_build_id(struct perf_record_mmap2 *event,
> + bool is_kernel)
> +{
> + struct build_id bid;
> + int rc;
> +
> + if (is_kernel)
> + rc = sysfs__read_build_id("/sys/kernel/notes", &bid);
> + else
> + rc = filename__read_build_id(event->filename, &bid) > 0 ? 0 : -1;
> +
> + if (rc == 0) {
> + memcpy(event->build_id, bid.data, sizeof(bid.data));
> + event->build_id_size = (u8) bid.size;
> + event->header.misc |= PERF_RECORD_MISC_MMAP_BUILD_ID;
> + event->__reserved_1 = 0;
> + event->__reserved_2 = 0;
> + } else {
> + if (event->filename[0] == '/') {
> + pr_debug2("Failed to read build ID for %s\n",
> + event->filename);
> + }
> + }
> +}
> +
> int perf_event__synthesize_mmap_events(struct perf_tool *tool,
> union perf_event *event,
> pid_t pid, pid_t tgid,
> @@ -453,6 +478,9 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
> event->mmap2.pid = tgid;
> event->mmap2.tid = pid;
>
> + if (symbol_conf.buildid_mmap2)
> + perf_record_mmap2__read_build_id(&event->mmap2, false);
Ditto
> if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
> rc = -1;
> break;
> @@ -630,6 +658,8 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t
>
> memcpy(event->mmap2.filename, pos->dso->long_name,
> pos->dso->long_name_len + 1);
> +
> + perf_record_mmap2__read_build_id(&event->mmap2, false);
> } else {
> size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
> event->mmap.header.type = PERF_RECORD_MMAP;
> @@ -1050,6 +1080,8 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
> event->mmap2.start = map->start;
> event->mmap2.len = map->end - event->mmap.start;
> event->mmap2.pid = machine->pid;
> +
> + perf_record_mmap2__read_build_id(&event->mmap2, true);
> } else {
> size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
> "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
> --
> 2.26.2
>
--
- Arnaldo
Em Tue, Nov 17, 2020 at 12:00:50PM +0100, Jiri Olsa escreveu:
> Adding support to specify perf data file as -a option file
> argument,
>
> If the file is detected to be perf data file, it is processed
> and all dso objects with sample hit are stored to the build
> id cache.
>
> $ DEBUGINFOD_URLS=http://192.168.122.174:8002 perf buildid-cache -a perf.data
> OK 5dcec522abf136fcfd3128f47e131f2365834dd7 /home/jolsa/.debug/.build-id/5d/cec522abf136fcfd3128f47e131f2365834dd7/elf
> OK 5784f813b727a50cfd3363234aef9fcbab685cc4 /lib/modules/5.10.0-rc2speed+/kernel/fs/xfs/xfs.ko
>
> By default we store only dso with hits, but it's possible to
> specify 'all' to store all dso objects, like:
> -a perf.data,all
>
> $ DEBUGINFOD_URLS=http://192.168.122.174:8002 perf buildid-cache -a perf.data,all
> OK 5dcec522abf136fcfd3128f47e131f2365834dd7 /home/jolsa/.debug/.build-id/5d/cec522abf136fcfd3128f47e131f2365834dd7/elf
> OK 6ce92dc7c31f12fe5b7775a2bb8b14a3546ce2cd /lib/modules/5.10.0-rc2speed+/kernel/drivers/firmware/qemu_fw_cfg.ko
> OK bf3f6d32dccc159f841fc3658c241d0e74c61fbb /lib/modules/5.10.0-rc2speed+/kernel/drivers/block/virtio_blk.ko
> OK e896b4329cf9f190f1a0fae933f425ff8f71b052 /lib/modules/5.10.0-rc2speed+/kernel/drivers/char/virtio_console.ko
> OK 5bedc933cb59e053ecb472f327bd73c548364479 /lib/modules/5.10.0-rc2speed+/kernel/drivers/input/serio/serio_raw.ko
> OK cecc506368a8b7a473a5f900d26f0d3d914a9c23 /lib/modules/5.10.0-rc2speed+/kernel/arch/x86/crypto/crc32c-intel.ko
> OK 91076fb3646d061a0a42cf7bddb339a665ee4f80 /lib/modules/5.10.0-rc2speed+/kernel/arch/x86/crypto/ghash-clmulni-intel.ko
> OK 4e2a304d788bb8e2e950bc82a5944e042afa0bf2 /lib/modules/5.10.0-rc2speed+/kernel/drivers/media/cec/core/cec.ko
> OK 31ab0da5ad81e6803280177f507a95f3053d585e /lib/modules/5.10.0-rc2speed+/kernel/lib/libcrc32c.ko
> OK f6154bca47c149f48c942fcc3d653041dd285c65 /lib/modules/5.10.0-rc2speed+/kernel/drivers/gpu/drm/ttm/ttm.ko
> OK 723f5852de81590d54b23b38c160d3618b41951b /lib/modules/5.10.0-rc2speed+/kernel/arch/x86/crypto/crct10dif-pclmul.ko
> OK 06b1eab7f141cbc3e5a5db47909c8ab5cb242e40 /lib/modules/5.10.0-rc2speed+/kernel/drivers/gpu/drm/drm_ttm_helper.ko
> OK 38292b862cf3ff87489508fdb4895efa45780813 /lib/modules/5.10.0-rc2speed+/kernel/drivers/gpu/drm/qxl/qxl.ko
> OK cdf51e58609bf2ce4837a7b195e0ccae0a930907 /lib/modules/5.10.0-rc2speed+/kernel/arch/x86/crypto/crc32-pclmul.ko
> OK 5ca8958388f6688452ecc2cb83d6031394c659ad /lib/modules/5.10.0-rc2speed+/kernel/drivers/gpu/drm/drm.ko
> OK 236bc4e4f38bf3559007566cb32b3dcc1bc28d2d /lib/modules/5.10.0-rc2speed+/kernel/drivers/gpu/drm/drm_kms_helper.ko
> OK 5784f813b727a50cfd3363234aef9fcbab685cc4 /lib/modules/5.10.0-rc2speed+/kernel/fs/xfs/xfs.ko
> OK 66db2be3efaa43bb5a5c481986e9554e1885cc69 /usr/lib/systemd/systemd
> OK 7db607d9f2de89860d9639712da64c8bacd31e4b /usr/lib64/libm-2.30.so
> OK 55b5f9652e1d17c1dd58f62628d5063428e5db91 /usr/lib64/libudev.so.1.6.15
> OK 63b97070bf097130713bb6c89cf7100b5f3c9b17 /usr/lib64/libunistring.so.2.1.0
> ...
This is a cool feature! :-)
- Arnaldo
>
> Once perf data is specified, no other file can be specified in
> the option, otherwise it causes syntax error.
>
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> .../perf/Documentation/perf-buildid-cache.txt | 12 +-
> tools/perf/builtin-buildid-cache.c | 215 +++++++++++++++++-
> tools/perf/util/probe-event.c | 6 +-
> 3 files changed, 227 insertions(+), 6 deletions(-)
>
> diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
> index f6de0952ff3c..b77da5138bca 100644
> --- a/tools/perf/Documentation/perf-buildid-cache.txt
> +++ b/tools/perf/Documentation/perf-buildid-cache.txt
> @@ -23,7 +23,17 @@ OPTIONS
> -------
> -a::
> --add=::
> - Add specified file to the cache.
> + Add specified file or perf.data binaries to the cache.
> +
> + If the file is detected to be perf data file, it is processed
> + and all dso objects with sample hit are stored to the cache.
> +
> + It's possible to specify 'all' to store all dso objects, like:
> + -a perf.data,all
> +
> + Once perf data is specified, no other file can be specified in
> + the option, otherwise it causes syntax error.
> +
> -f::
> --force::
> Don't complain, do it.
> diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
> index a25411926e48..0bfb54ee1e5e 100644
> --- a/tools/perf/builtin-buildid-cache.c
> +++ b/tools/perf/builtin-buildid-cache.c
> @@ -29,6 +29,11 @@
> #include "util/probe-file.h"
> #include <linux/string.h>
> #include <linux/err.h>
> +#include <linux/zalloc.h>
> +#include <sys/stat.h>
> +#ifdef HAVE_DEBUGINFOD_SUPPORT
> +#include <elfutils/debuginfod.h>
> +#endif
>
> static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
> {
> @@ -348,6 +353,205 @@ static int build_id_cache__show_all(void)
> return 0;
> }
>
> +#ifdef HAVE_DEBUGINFOD_SUPPORT
> +static int call_debuginfod(const char *sbuild_id, char **path, bool debuginfo)
> +{
> + debuginfod_client *c;
> + int fd;
> +
> + c = debuginfod_begin();
> + if (c == NULL)
> + return -1;
> +
> + pr_debug("trying debuginfod for executable <%s> ... ", sbuild_id);
> +
> + if (debuginfo) {
> + fd = debuginfod_find_debuginfo(c, (const unsigned char *) sbuild_id,
> + 0, path);
> + } else {
> + fd = debuginfod_find_executable(c, (const unsigned char *) sbuild_id,
> + 0, path);
> + }
> + if (fd >= 0)
> + close(fd); /* retaining reference by realname */
> +
> + debuginfod_end(c);
> + pr_debug("%s%s\n", *path ? "OK " : "FAILED", *path ? *path : "");
> + return *path ? 0 : -1;
> +}
> +#else
> +static int call_debuginfod(const char *sbuild_id __maybe_unused,
> + char **path __maybe_unused,
> + bool debuginfo __maybe_unused)
> +{
> + return -1;
> +}
> +#endif
> +
> +struct dso_store_data {
> + bool hits;
> + bool force_download;
> +};
> +
> +static int dso_store(struct dso *dso, struct machine *machine, void *priv)
> +{
> + struct dso_store_data *data = priv;
> + char sbuild_id[SBUILD_ID_SIZE];
> + struct build_id bid;
> + char *path = NULL, *link = NULL;
> + bool is_kallsyms;
> + int err = -1;
> +
> + /*
> + * There's no build id in dso, nothing to do..
> + */
> + if (!dso->has_build_id || !build_id__is_defined(&dso->bid))
> + return 0;
> +
> + if (data->hits && !dso->hit)
> + return 0;
> +
> + /*
> + * The storing process is:
> + * - get build id of the dso
> + * - check if it is already in cache
> + * - check if it matches provided build id from mmap2 event
> + * - if not, try debuginfod to download the binary
> + * - store binary to build id database
> + */
> + is_kallsyms = !strcmp(machine->mmap_name, dso->short_name);
> + build_id__sprintf(&dso->bid, sbuild_id);
> +
> + link = build_id_cache__linkname(sbuild_id, NULL, 0);
> + if (!link)
> + return -ENOMEM;
> +
> + if (!data->force_download && !access(link, X_OK)) {
> + pr_debug("already in cache - %s <%s>\n", dso->long_name, sbuild_id);
> + err = 0;
> + goto out;
> + }
> +
> + path = strdup(dso->long_name);
> + if (!path)
> + goto out;
> +
> + if (is_kallsyms) {
> + /*
> + * Find out if we are on the same kernel as perf.data
> + * and store kallsyms in that case.
> + */
> + err = sysfs__read_build_id("/sys/kernel/notes", &bid);
> + if (err < 0)
> + goto out;
> + } else {
> + struct nscookie nsc;
> + struct stat st;
> +
> + nsinfo__mountns_enter(dso->nsinfo, &nsc);
> +
> + /*
> + * Does the file exists in the first place, if it does,
> + * resolve path and read the build id.
> + */
> + if (stat(dso->long_name, &st)) {
> + nsinfo__mountns_exit(&nsc);
> + zfree(&path);
> + goto try_download;
> + }
> +
> + err = filename__read_build_id(dso->long_name, &bid);
> + nsinfo__mountns_exit(&nsc);
> +
> + if (err <= 0)
> + goto out;
> + }
> +
> + /*
> + * If we match, then what we want in mmap2 event
> + * is what we got in the binary,
> + */
> + if (bid.size != dso->bid.size || memcmp(&bid, &dso->bid, bid.size)) {
> + char sbid[SBUILD_ID_SIZE];
> +
> + build_id__sprintf(&bid, sbid);
> + pr_debug("mmap build id <%s> does not match for %s <%s>\n",
> + sbuild_id, path, sbid);
> + zfree(&path);
> + }
> +
> +try_download:
> + /*
> + * We did not match build id or did not find the
> + * binary - try debuginfod as last resort.
> + */
> + if (!path) {
> + bool debuginfo;
> + char *tmp = NULL;
> +
> + /*
> + * The debuginfo retrieval for standard binaries
> + * is handled within build_id_cache__add function.
> + *
> + * For kernel and kernel modules we have to ask
> + * for debuginfo directly, because debuginfod
> + * does not treat them as binaries.
> + */
> + debuginfo = is_kallsyms ||
> + is_kernel_module(dso->long_name, PERF_RECORD_MISC_CPUMODE_UNKNOWN);
> +
> + if (call_debuginfod(sbuild_id, &tmp, debuginfo)) {
> + err = -1;
> + goto out;
> + }
> +
> + path = tmp;
> +
> + /*
> + * The kernel dso is now elf binary, so disable is_kallsyms
> + * so build_id_cache__add can prepare proper file names.
> + */
> + is_kallsyms = false;
> + }
> +
> + pr_debug("linking %s %s <%s>\n", dso->short_name, path, sbuild_id);
> +
> + err = build_id_cache__add(sbuild_id, path, path,
> + dso->nsinfo, is_kallsyms, false);
> +out:
> + free(path);
> + fprintf(stderr, "%s %s %s\n", err ? "FAIL" : "OK ", sbuild_id, dso->long_name);
> + return 0;
> +}
> +
> +static int
> +build_id_cache__add_perf_data(const char *path, bool all)
> +{
> + struct perf_session *session;
> + struct dso_store_data priv = {
> + .hits = !all,
> + .force_download = false,
> + };
> + struct perf_data data = {
> + .path = path,
> + .mode = PERF_DATA_MODE_READ,
> + };
> + int err;
> +
> + session = perf_session__new(&data, false, &build_id__mark_dso_hit_ops);
> + if (IS_ERR(session))
> + return PTR_ERR(session);
> +
> + err = perf_session__process_events(session);
> + if (err)
> + goto out;
> +
> + err = __perf_session__cache_build_ids(session, dso_store, &priv);
> +out:
> + perf_session__delete(session);
> + return err;
> +}
> +
> int cmd_buildid_cache(int argc, const char **argv)
> {
> struct strlist *list;
> @@ -440,7 +644,15 @@ int cmd_buildid_cache(int argc, const char **argv)
> list = strlist__new(add_name_list_str, NULL);
> if (list) {
> strlist__for_each_entry(pos, list)
> - if (build_id_cache__add_file(pos->s, nsi)) {
> + if (is_perf_data(pos->s)) {
> + struct str_node *all_pos = strlist__next(pos);
> + bool all = !strcmp("all", all_pos ? all_pos->s : "");
> +
> + if (build_id_cache__add_perf_data(pos->s, all))
> + pr_warning("Couldn't add build ids from %s\n", pos->s);
> + if (all)
> + pos = all_pos;
> + } else if (build_id_cache__add_file(pos->s, nsi)) {
> if (errno == EEXIST) {
> pr_debug("%s already in the cache\n",
> pos->s);
> @@ -449,7 +661,6 @@ int cmd_buildid_cache(int argc, const char **argv)
> pr_warning("Couldn't add %s: %s\n",
> pos->s, str_error_r(errno, sbuf, sizeof(sbuf)));
> }
> -
> strlist__delete(list);
> }
> }
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index 8eae2afff71a..e821bb977c9b 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -1616,9 +1616,9 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
> return -EINVAL;
> }
>
> - pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
> - pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
> - pp->lazy_line);
> + pr_debug2("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
> + pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
> + pp->lazy_line);
> return 0;
> }
>
> --
> 2.26.2
>
--
- Arnaldo
Em Tue, Nov 17, 2020 at 12:00:43PM +0100, Jiri Olsa escreveu:
> Allow mmap2 event to synthesize kernel modules,
> so we can synthesize module's build id data in
> following changes.
>
> It's enabled by new symbol_conf.buildid_mmap2
> bool, which will be switched in following
> changes.
Ditto as for the kernel mmap event, don't we do this probing before
generating the synthetic events? If not perhaps we should, to avoid
synthesizing things and then failing on creating the events? If we do it
that way, we can switch from symbol_conf.buildid_mmap2 to
!perf_missing_features.mmap2.
- Arnaldo
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> tools/perf/util/synthetic-events.c | 49 +++++++++++++++++++-----------
> 1 file changed, 32 insertions(+), 17 deletions(-)
>
> diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
> index 872df6d6dbef..a18ae502d765 100644
> --- a/tools/perf/util/synthetic-events.c
> +++ b/tools/perf/util/synthetic-events.c
> @@ -593,16 +593,17 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t
> int rc = 0;
> struct map *pos;
> struct maps *maps = machine__kernel_maps(machine);
> - union perf_event *event = zalloc((sizeof(event->mmap) +
> - machine->id_hdr_size));
> + union perf_event *event;
> + size_t size = symbol_conf.buildid_mmap2 ?
> + sizeof(event->mmap2) : sizeof(event->mmap);
> +
> + event = zalloc(size + machine->id_hdr_size);
> if (event == NULL) {
> pr_debug("Not enough memory synthesizing mmap event "
> "for kernel modules\n");
> return -1;
> }
>
> - event->header.type = PERF_RECORD_MMAP;
> -
> /*
> * kernel uses 0 for user space maps, see kernel/perf_event.c
> * __perf_event_mmap
> @@ -613,23 +614,37 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t
> event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
>
> maps__for_each_entry(maps, pos) {
> - size_t size;
> -
> if (!__map__is_kmodule(pos))
> continue;
>
> - size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
> - event->mmap.header.type = PERF_RECORD_MMAP;
> - event->mmap.header.size = (sizeof(event->mmap) -
> - (sizeof(event->mmap.filename) - size));
> - memset(event->mmap.filename + size, 0, machine->id_hdr_size);
> - event->mmap.header.size += machine->id_hdr_size;
> - event->mmap.start = pos->start;
> - event->mmap.len = pos->end - pos->start;
> - event->mmap.pid = machine->pid;
> + if (symbol_conf.buildid_mmap2) {
> + size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
> + event->mmap2.header.type = PERF_RECORD_MMAP2;
> + event->mmap2.header.size = (sizeof(event->mmap2) -
> + (sizeof(event->mmap2.filename) - size));
> + memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
> + event->mmap2.header.size += machine->id_hdr_size;
> + event->mmap2.start = pos->start;
> + event->mmap2.len = pos->end - pos->start;
> + event->mmap2.pid = machine->pid;
> +
> + memcpy(event->mmap2.filename, pos->dso->long_name,
> + pos->dso->long_name_len + 1);
> + } else {
> + size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
> + event->mmap.header.type = PERF_RECORD_MMAP;
> + event->mmap.header.size = (sizeof(event->mmap) -
> + (sizeof(event->mmap.filename) - size));
> + memset(event->mmap.filename + size, 0, machine->id_hdr_size);
> + event->mmap.header.size += machine->id_hdr_size;
> + event->mmap.start = pos->start;
> + event->mmap.len = pos->end - pos->start;
> + event->mmap.pid = machine->pid;
> +
> + memcpy(event->mmap.filename, pos->dso->long_name,
> + pos->dso->long_name_len + 1);
> + }
>
> - memcpy(event->mmap.filename, pos->dso->long_name,
> - pos->dso->long_name_len + 1);
> if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
> rc = -1;
> break;
> --
> 2.26.2
>
--
- Arnaldo
Em Tue, Nov 17, 2020 at 12:00:51PM +0100, Jiri Olsa escreveu:
> Adding --debuginfod option to specify debuginfod url and
> support to do that through config file as well.
>
> Use following in ~/.perfconfig file:
>
> [buildid-cache]
> debuginfod=http://192.168.122.174:8002
Ditto, its cool this is getting nicely integrated :-)
- Arnaldo
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> .../perf/Documentation/perf-buildid-cache.txt | 6 ++++
> tools/perf/Documentation/perf-config.txt | 7 +++++
> tools/perf/builtin-buildid-cache.c | 28 +++++++++++++++++--
> 3 files changed, 38 insertions(+), 3 deletions(-)
>
> diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
> index b77da5138bca..75385f4dc11f 100644
> --- a/tools/perf/Documentation/perf-buildid-cache.txt
> +++ b/tools/perf/Documentation/perf-buildid-cache.txt
> @@ -84,6 +84,12 @@ OPTIONS
> used when creating a uprobe for a process that resides in a
> different mount namespace from the perf(1) utility.
>
> +--debuginfod=URL::
> + Specify debuginfod URL to be used when retrieving perf.data binaries,
> + it follows the same syntax as the DEBUGINFOD_URLS variable, like:
> +
> + buildid-cache.debuginfod=http://192.168.122.174:8002
> +
> SEE ALSO
> --------
> linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-buildid-list[1]
> diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
> index 31069d8a5304..15fad32b9885 100644
> --- a/tools/perf/Documentation/perf-config.txt
> +++ b/tools/perf/Documentation/perf-config.txt
> @@ -238,6 +238,13 @@ buildid.*::
> cache location, or to disable it altogether. If you want to disable it,
> set buildid.dir to /dev/null. The default is $HOME/.debug
>
> +buildid-cache.*::
> + buildid-cache.debuginfod=URL
> + Specify debuginfod URL to be used when retrieving perf.data binaries,
> + it follows the same syntax as the DEBUGINFOD_URLS variable, like:
> +
> + buildid-cache.debuginfod=http://192.168.122.174:8002
> +
> annotate.*::
> These are in control of addresses, jump function, source code
> in lines of assembly code from a specific program.
> diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
> index 0bfb54ee1e5e..fc03de7d2a28 100644
> --- a/tools/perf/builtin-buildid-cache.c
> +++ b/tools/perf/builtin-buildid-cache.c
> @@ -27,6 +27,7 @@
> #include "util/time-utils.h"
> #include "util/util.h"
> #include "util/probe-file.h"
> +#include "util/config.h"
> #include <linux/string.h>
> #include <linux/err.h>
> #include <linux/zalloc.h>
> @@ -552,12 +553,21 @@ build_id_cache__add_perf_data(const char *path, bool all)
> return err;
> }
>
> +static int perf_buildid_cache_config(const char *var, const char *value, void *cb)
> +{
> + const char **debuginfod = cb;
> +
> + if (!strcmp(var, "buildid-cache.debuginfod"))
> + *debuginfod = strdup(value);
> +
> + return 0;
> +}
> +
> int cmd_buildid_cache(int argc, const char **argv)
> {
> struct strlist *list;
> struct str_node *pos;
> - int ret = 0;
> - int ns_id = -1;
> + int ret, ns_id = -1;
> bool force = false;
> bool list_files = false;
> bool opts_flag = false;
> @@ -567,7 +577,8 @@ int cmd_buildid_cache(int argc, const char **argv)
> *purge_name_list_str = NULL,
> *missing_filename = NULL,
> *update_name_list_str = NULL,
> - *kcore_filename = NULL;
> + *kcore_filename = NULL,
> + *debuginfod = NULL;
> char sbuf[STRERR_BUFSIZE];
>
> struct perf_data data = {
> @@ -592,6 +603,8 @@ int cmd_buildid_cache(int argc, const char **argv)
> OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
> OPT_STRING('u', "update", &update_name_list_str, "file list",
> "file(s) to update"),
> + OPT_STRING(0, "debuginfod", &debuginfod, "debuginfod url",
> + "set debuginfod url"),
> OPT_INCR('v', "verbose", &verbose, "be more verbose"),
> OPT_INTEGER(0, "target-ns", &ns_id, "target pid for namespace context"),
> OPT_END()
> @@ -601,6 +614,10 @@ int cmd_buildid_cache(int argc, const char **argv)
> NULL
> };
>
> + ret = perf_config(perf_buildid_cache_config, &debuginfod);
> + if (ret)
> + return ret;
> +
> argc = parse_options(argc, argv, buildid_cache_options,
> buildid_cache_usage, 0);
>
> @@ -612,6 +629,11 @@ int cmd_buildid_cache(int argc, const char **argv)
> if (argc || !(list_files || opts_flag))
> usage_with_options(buildid_cache_usage, buildid_cache_options);
>
> + if (debuginfod) {
> + pr_debug("DEBUGINFOD_URLS=%s\n", debuginfod);
> + setenv("DEBUGINFOD_URLS", debuginfod, 1);
> + }
> +
> /* -l is exclusive. It can not be used with other options. */
> if (list_files && opts_flag) {
> usage_with_options_msg(buildid_cache_usage,
> --
> 2.26.2
>
--
- Arnaldo
Em Tue, Nov 17, 2020 at 12:00:52PM +0100, Jiri Olsa escreveu:
> Add buildid-list support for mmap2's build id data, so we can
> display build ids for dso objects for data without the build
> id cache update.
> $ perf buildid-list
> 1805c738c8f3ec0f47b7ea09080c28f34d18a82b /usr/lib64/ld-2.31.so
> d278249792061c6b74d1693ca59513be1def13f2 /usr/lib64/libc-2.31.so
>
> By default only dso objects with hits are shown.
Would be interesting to be able to show all the build ids that are
there. a 'perf buildid-list --all' or make this under --force?
- Arnaldo
> Signed-off-by: Jiri Olsa <[email protected]>
> ---
> tools/perf/builtin-buildid-list.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
> index e3ef75583514..87f5b1a4a7fa 100644
> --- a/tools/perf/builtin-buildid-list.c
> +++ b/tools/perf/builtin-buildid-list.c
> @@ -77,6 +77,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
> perf_header__has_feat(&session->header, HEADER_AUXTRACE))
> with_hits = false;
>
> + if (!perf_header__has_feat(&session->header, HEADER_BUILD_ID))
> + with_hits = true;
> +
> /*
> * in pipe-mode, the only way to get the buildids is to parse
> * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
> --
> 2.26.2
>
--
- Arnaldo
On Tue, Nov 17, 2020 at 09:38:05AM -0300, Arnaldo Carvalho de Melo wrote:
> Em Tue, Nov 17, 2020 at 12:00:41PM +0100, Jiri Olsa escreveu:
> > When processing mmap2 event, check on the build id
> > misc bit: PERF_RECORD_MISC_BUILD_ID and if it's set,
> > store the build id in mmap's dso object.
> >
> > Also adding the build id data arts to struct
> > perf_record_mmap2 event definition.
> >
> > Signed-off-by: Jiri Olsa <[email protected]>
> > ---
> > kernel/events/core.c | 4 ++++
> > tools/lib/perf/include/perf/event.h | 18 ++++++++++++++----
> > tools/perf/util/machine.c | 24 +++++++++++++++++++-----
> > tools/perf/util/map.c | 8 ++++++--
> > tools/perf/util/map.h | 3 ++-
> > 5 files changed, 45 insertions(+), 12 deletions(-)
>
> You mixed up kernel changes with tools/ changes, can you please split
> this up?
>
> Also there is an indentation problem in the kernel changes, which, I
> think, is just debugging cruft that you forgot to excise? :-)
mama mia.. sry, that's debug that slipped, there will
be new version for sure ;-)
jirka
>
> - Arnaldo
>
> > diff --git a/kernel/events/core.c b/kernel/events/core.c
> > index 5841b5bca68d..fa7f392c6c0c 100644
> > --- a/kernel/events/core.c
> > +++ b/kernel/events/core.c
> > @@ -8017,6 +8017,10 @@ static void perf_event_mmap_output(struct perf_event *event,
> >
> > __output_copy(&handle, size, 4);
> > __output_copy(&handle, mmap_event->build_id, BUILD_ID_SIZE);
> > +
> > +if (mmap_event->build_id_size > 20)
> > + trace_printk("build_id_size %u %s\n", mmap_event->build_id_size, mmap_event->file_name);
> > +
> > } else {
> > perf_output_put(&handle, mmap_event->maj);
> > perf_output_put(&handle, mmap_event->min);
> > diff --git a/tools/lib/perf/include/perf/event.h b/tools/lib/perf/include/perf/event.h
> > index 988c539bedb6..d82054225fcc 100644
> > --- a/tools/lib/perf/include/perf/event.h
> > +++ b/tools/lib/perf/include/perf/event.h
> > @@ -23,10 +23,20 @@ struct perf_record_mmap2 {
> > __u64 start;
> > __u64 len;
> > __u64 pgoff;
> > - __u32 maj;
> > - __u32 min;
> > - __u64 ino;
> > - __u64 ino_generation;
> > + union {
> > + struct {
> > + __u32 maj;
> > + __u32 min;
> > + __u64 ino;
> > + __u64 ino_generation;
> > + };
> > + struct {
> > + __u8 build_id_size;
> > + __u8 __reserved_1;
> > + __u16 __reserved_2;
> > + __u8 build_id[20];
> > + };
> > + };
> > __u32 prot;
> > __u32 flags;
> > char filename[PATH_MAX];
> > diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
> > index 1ae32a81639c..1edb7d10b042 100644
> > --- a/tools/perf/util/machine.c
> > +++ b/tools/perf/util/machine.c
> > @@ -1599,7 +1599,8 @@ static int machine__process_extra_kernel_map(struct machine *machine,
> > }
> >
> > static int machine__process_kernel_mmap_event(struct machine *machine,
> > - struct extra_kernel_map *xm)
> > + struct extra_kernel_map *xm,
> > + struct build_id *bid)
> > {
> > struct map *map;
> > enum dso_space_type dso_space;
> > @@ -1624,6 +1625,10 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
> > goto out_problem;
> >
> > map->end = map->start + xm->end - xm->start;
> > +
> > + if (build_id__is_defined(bid))
> > + dso__set_build_id(map->dso, bid);
> > +
> > } else if (is_kernel_mmap) {
> > const char *symbol_name = (xm->name + strlen(machine->mmap_name));
> > /*
> > @@ -1681,6 +1686,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
> >
> > machine__update_kernel_mmap(machine, xm->start, xm->end);
> >
> > + if (build_id__is_defined(bid))
> > + dso__set_build_id(kernel, bid);
> > +
> > /*
> > * Avoid using a zero address (kptr_restrict) for the ref reloc
> > * symbol. Effectively having zero here means that at record
> > @@ -1718,11 +1726,17 @@ int machine__process_mmap2_event(struct machine *machine,
> > .ino = event->mmap2.ino,
> > .ino_generation = event->mmap2.ino_generation,
> > };
> > + struct build_id __bid, *bid = NULL;
> > int ret = 0;
> >
> > if (dump_trace)
> > perf_event__fprintf_mmap2(event, stdout);
> >
> > + if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
> > + bid = &__bid;
> > + build_id__init(bid, event->mmap2.build_id, event->mmap2.build_id_size);
> > + }
> > +
> > if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
> > sample->cpumode == PERF_RECORD_MISC_KERNEL) {
> > struct extra_kernel_map xm = {
> > @@ -1732,7 +1746,7 @@ int machine__process_mmap2_event(struct machine *machine,
> > };
> >
> > strlcpy(xm.name, event->mmap2.filename, KMAP_NAME_LEN);
> > - ret = machine__process_kernel_mmap_event(machine, &xm);
> > + ret = machine__process_kernel_mmap_event(machine, &xm, bid);
> > if (ret < 0)
> > goto out_problem;
> > return 0;
> > @@ -1746,7 +1760,7 @@ int machine__process_mmap2_event(struct machine *machine,
> > map = map__new(machine, event->mmap2.start,
> > event->mmap2.len, event->mmap2.pgoff,
> > &dso_id, event->mmap2.prot,
> > - event->mmap2.flags,
> > + event->mmap2.flags, bid,
> > event->mmap2.filename, thread);
> >
> > if (map == NULL)
> > @@ -1789,7 +1803,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
> > };
> >
> > strlcpy(xm.name, event->mmap.filename, KMAP_NAME_LEN);
> > - ret = machine__process_kernel_mmap_event(machine, &xm);
> > + ret = machine__process_kernel_mmap_event(machine, &xm, NULL);
> > if (ret < 0)
> > goto out_problem;
> > return 0;
> > @@ -1805,7 +1819,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
> >
> > map = map__new(machine, event->mmap.start,
> > event->mmap.len, event->mmap.pgoff,
> > - NULL, prot, 0, event->mmap.filename, thread);
> > + NULL, prot, 0, NULL, event->mmap.filename, thread);
> >
> > if (map == NULL)
> > goto out_problem_map;
> > diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
> > index f44ede437dc7..692e56dc832e 100644
> > --- a/tools/perf/util/map.c
> > +++ b/tools/perf/util/map.c
> > @@ -130,8 +130,8 @@ void map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso)
> >
> > struct map *map__new(struct machine *machine, u64 start, u64 len,
> > u64 pgoff, struct dso_id *id,
> > - u32 prot, u32 flags, char *filename,
> > - struct thread *thread)
> > + u32 prot, u32 flags, struct build_id *bid,
> > + char *filename, struct thread *thread)
> > {
> > struct map *map = malloc(sizeof(*map));
> > struct nsinfo *nsi = NULL;
> > @@ -194,6 +194,10 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
> > dso__set_loaded(dso);
> > }
> > dso->nsinfo = nsi;
> > +
> > + if (build_id__is_defined(bid))
> > + dso__set_build_id(dso, bid);
> > +
> > dso__put(dso);
> > }
> > return map;
> > diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
> > index b1c0686db1b7..9f32825c98d8 100644
> > --- a/tools/perf/util/map.h
> > +++ b/tools/perf/util/map.h
> > @@ -104,10 +104,11 @@ void map__init(struct map *map,
> > u64 start, u64 end, u64 pgoff, struct dso *dso);
> >
> > struct dso_id;
> > +struct build_id;
> >
> > struct map *map__new(struct machine *machine, u64 start, u64 len,
> > u64 pgoff, struct dso_id *id, u32 prot, u32 flags,
> > - char *filename, struct thread *thread);
> > + struct build_id *bid, char *filename, struct thread *thread);
> > struct map *map__new2(u64 start, struct dso *dso);
> > void map__delete(struct map *map);
> > struct map *map__clone(struct map *map);
> > --
> > 2.26.2
> >
>
> --
>
> - Arnaldo
>
On Tue, Nov 17, 2020 at 09:44:37AM -0300, Arnaldo Carvalho de Melo wrote:
> Em Tue, Nov 17, 2020 at 12:00:42PM +0100, Jiri Olsa escreveu:
> > Allow mmap2 event to synthesize kernel image,
> > so we can synthesize kernel build id data in
> > following changes.
> >
> > It's enabled by new symbol_conf.buildid_mmap2
> > bool, which will be switched in following
> > changes.
>
> Why make this an option? MMAP2 goes back years:
>
> 13d7a2410fa637f45 (Stephane Eranian 2013-08-21 12:10:24 +0200 904) * The MMAP2 records are an augmented version of MMAP, they add
> 13d7a2410fa637f45 (Stephane Eranian 2013-08-21 12:10:24 +0200 905) * maj, min, ino numbers to be used to uniquely identify each mapping
>
> Also we unconditionally generate MMAP2 events if the kernel supports it,
> from evsel__config():
>
> attr->mmap = track;
> attr->mmap2 = track && !perf_missing_features.mmap2;
>
> So perhaps we should reuse that logic? I.e. use mmap2 if the kernel
> supports it?
mmap2 itself is not a problem, the problem is the new
bit (PERF_RECORD_MISC_MMAP_BUILD_ID) that says there's
build id in mmap2.. older perf tool won't understand
that and report will crash
jirka
On Tue, Nov 17, 2020 at 09:50:40AM -0300, Arnaldo Carvalho de Melo wrote:
> Em Tue, Nov 17, 2020 at 12:00:52PM +0100, Jiri Olsa escreveu:
> > Add buildid-list support for mmap2's build id data, so we can
> > display build ids for dso objects for data without the build
> > id cache update.
>
> > $ perf buildid-list
> > 1805c738c8f3ec0f47b7ea09080c28f34d18a82b /usr/lib64/ld-2.31.so
> > d278249792061c6b74d1693ca59513be1def13f2 /usr/lib64/libc-2.31.so
> >
> > By default only dso objects with hits are shown.
>
> Would be interesting to be able to show all the build ids that are
> there. a 'perf buildid-list --all' or make this under --force?
ok, will check.. one other tool I think would be handy is
to show which debuginfo is not available, because it can
change the report a lot - missing symbols are not getting
accounted, and their hits are accounted only as separated
addresses
jirka
>
> - Arnaldo
>
> > Signed-off-by: Jiri Olsa <[email protected]>
> > ---
> > tools/perf/builtin-buildid-list.c | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
> > index e3ef75583514..87f5b1a4a7fa 100644
> > --- a/tools/perf/builtin-buildid-list.c
> > +++ b/tools/perf/builtin-buildid-list.c
> > @@ -77,6 +77,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
> > perf_header__has_feat(&session->header, HEADER_AUXTRACE))
> > with_hits = false;
> >
> > + if (!perf_header__has_feat(&session->header, HEADER_BUILD_ID))
> > + with_hits = true;
> > +
> > /*
> > * in pipe-mode, the only way to get the buildids is to parse
> > * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
> > --
> > 2.26.2
> >
>
> --
>
> - Arnaldo
>
Em Tue, Nov 17, 2020 at 04:16:51PM +0100, Jiri Olsa escreveu:
> On Tue, Nov 17, 2020 at 09:44:37AM -0300, Arnaldo Carvalho de Melo wrote:
> > Em Tue, Nov 17, 2020 at 12:00:42PM +0100, Jiri Olsa escreveu:
> > > Allow mmap2 event to synthesize kernel image,
> > > so we can synthesize kernel build id data in
> > > following changes.
> > >
> > > It's enabled by new symbol_conf.buildid_mmap2
> > > bool, which will be switched in following
> > > changes.
> >
> > Why make this an option? MMAP2 goes back years:
> >
> > 13d7a2410fa637f45 (Stephane Eranian 2013-08-21 12:10:24 +0200 904) * The MMAP2 records are an augmented version of MMAP, they add
> > 13d7a2410fa637f45 (Stephane Eranian 2013-08-21 12:10:24 +0200 905) * maj, min, ino numbers to be used to uniquely identify each mapping
> >
> > Also we unconditionally generate MMAP2 events if the kernel supports it,
> > from evsel__config():
> >
> > attr->mmap = track;
> > attr->mmap2 = track && !perf_missing_features.mmap2;
> >
> > So perhaps we should reuse that logic? I.e. use mmap2 if the kernel
> > supports it?
>
> mmap2 itself is not a problem, the problem is the new
> bit (PERF_RECORD_MISC_MMAP_BUILD_ID) that says there's
> build id in mmap2.. older perf tool won't understand
> that and report will crash
Is this theoretical or have you experienced it?
Would be good to tweak the perf.data reader code to not crash on unknown
bits like that :-\
But by looking at machine__process_mmap2_event() I couldn't imagine how
that would crash.
It would get bogus maj, min, ino, ino_generation, but probably that
wouldn't make it crash.
- Arnaldo
int machine__process_mmap2_event(struct machine *machine,
union perf_event *event,
struct perf_sample *sample)
{
struct thread *thread;
struct map *map;
struct dso_id dso_id = {
.maj = event->mmap2.maj,
.min = event->mmap2.min,
.ino = event->mmap2.ino,
.ino_generation = event->mmap2.ino_generation,
};
int ret = 0;
if (dump_trace)
perf_event__fprintf_mmap2(event, stdout);
if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
sample->cpumode == PERF_RECORD_MISC_KERNEL) {
ret = machine__process_kernel_mmap_event(machine, event);
if (ret < 0)
goto out_problem;
return 0;
}
thread = machine__findnew_thread(machine, event->mmap2.pid,
event->mmap2.tid);
if (thread == NULL)
goto out_problem;
map = map__new(machine, event->mmap2.start,
event->mmap2.len, event->mmap2.pgoff,
&dso_id, event->mmap2.prot,
event->mmap2.flags,
event->mmap2.filename, thread);
if (map == NULL)
goto out_problem_map;
ret = thread__insert_map(thread, map);
if (ret)
goto out_problem_insert;
thread__put(thread);
map__put(map);
return 0;
out_problem_insert:
map__put(map);
out_problem_map:
thread__put(thread);
out_problem:
dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n");
return 0;
}
Em Tue, Nov 17, 2020 at 04:21:40PM +0100, Jiri Olsa escreveu:
> On Tue, Nov 17, 2020 at 09:50:40AM -0300, Arnaldo Carvalho de Melo wrote:
> > Em Tue, Nov 17, 2020 at 12:00:52PM +0100, Jiri Olsa escreveu:
> > > Add buildid-list support for mmap2's build id data, so we can
> > > display build ids for dso objects for data without the build
> > > id cache update.
> >
> > > $ perf buildid-list
> > > 1805c738c8f3ec0f47b7ea09080c28f34d18a82b /usr/lib64/ld-2.31.so
> > > d278249792061c6b74d1693ca59513be1def13f2 /usr/lib64/libc-2.31.so
> > >
> > > By default only dso objects with hits are shown.
> >
> > Would be interesting to be able to show all the build ids that are
> > there. a 'perf buildid-list --all' or make this under --force?
>
> ok, will check.. one other tool I think would be handy is
> to show which debuginfo is not available, because it can
> change the report a lot - missing symbols are not getting
> accounted, and their hits are accounted only as separated
> addresses
Right, as below.
So you suggest something like:
# perf buildid-cache --fetch-missing-debuginfo
?
- Arnaldo
[root@quaco ~]# rpm -qf `which stress-ng`
stress-ng-0.11.21-1.fc32.x86_64
[root@quaco ~]# rpm -q stress-ng-debuginfo
stress-ng-debuginfo-0.07.29-10.fc31.x86_64
[root@quaco ~]# perf record stress-ng -t 1 -c 1
stress-ng: info: [656926] dispatching hogs: 1 cpu
stress-ng: info: [656926] successful run completed in 1.02s
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.204 MB perf.data (4082 samples) ]
[root@quaco ~]# perf report | head -20
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 4K of event 'cycles'
# Event count (approx.): 3997318603
#
# Overhead Command Shared Object Symbol
# ........ ............. ................ ..............................
#
7.91% stress-ng-cpu stress-ng [.] 0x0000000000035ed9
7.15% stress-ng-cpu stress-ng [.] 0x0000000000035ecc
6.54% stress-ng-cpu stress-ng [.] 0x000000000003bbf6
4.39% stress-ng-cpu stress-ng [.] 0x000000000003a083
4.15% stress-ng-cpu stress-ng [.] 0x0000000000065ed8
3.67% stress-ng-cpu stress-ng [.] 0x0000000000065ecf
3.41% stress-ng-cpu stress-ng [.] 0x0000000000065ee1
3.11% stress-ng-cpu stress-ng [.] 0x000000000003bbf2
2.65% stress-ng-cpu stress-ng [.] 0x000000000003a07b
[root@quaco ~]#
So the above is with a stress-ng-debuginfo package that doesn't matches
the binary installed, so build-id checkign fails, resolving symbols
fail, then:
[root@quaco ~]# rpm -q stress-ng-debuginfo
stress-ng-debuginfo-0.11.21-1.fc32.x86_64
[root@quaco ~]# rpm -q stress-ng
stress-ng-0.11.21-1.fc32.x86_64
[root@quaco ~]#
[root@quaco ~]# rpm -q stress-ng-debuginfo
stress-ng-debuginfo-0.11.21-1.fc32.x86_64
[root@quaco ~]# rpm -q stress-ng
stress-ng-0.11.21-1.fc32.x86_64
[root@quaco ~]# perf report | head -20
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 4K of event 'cycles'
# Event count (approx.): 3997318603
#
# Overhead Command Shared Object Symbol
# ........ ............. ............. .........................................
#
21.48% stress-ng-cpu stress-ng [.] is_prime
16.02% stress-ng-cpu stress-ng [.] stress_cpu_sieve
12.61% stress-ng-cpu stress-ng [.] stress_cpu_cpuid.sse2.2
11.94% stress-ng-cpu stress-ng [.] ackermann
8.24% stress-ng-cpu stress-ng [.] stress_cpu_correlate
3.82% stress-ng-cpu stress-ng [.] queens_try
2.63% stress-ng-cpu stress-ng [.] stress_cpu_nsqrt.sse2.2
2.46% stress-ng-cpu stress-ng [.] ccitt_crc16
2.25% stress-ng-cpu stress-ng [.] stress_cpu_complex_long_double.sse2.2
[root@quaco ~]#
[root@quaco ~]# perf report -v | head -20
build id event received for vmlinux: f72ec65d81949c5ba63ccaa16b59c79d1696bc4d [20]
build id event received for /usr/bin/stress-ng: 82b81bd823dcac393292faaaf40997723ce358a8 [20]
build id event received for [vdso]: a1f89b9b9d2093ae926c550a7de060d435277fbf [20]
build id event received for /usr/lib64/libm-2.31.so: fdf1f1d0761b7392e419d5d72e43d3fd3db6e184 [20]
build id event received for /usr/lib64/libc-2.31.so: d278249792061c6b74d1693ca59513be1def13f2 [20]
Looking at the vmlinux_path (8 entries long)
symsrc__init: build id mismatch for vmlinux.
Using /usr/lib/debug/lib/modules/5.8.14-200.fc32.x86_64/vmlinux for symbols
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 4K of event 'cycles'
# Event count (approx.): 3997318603
#
# Overhead Command Shared Object Symbol
# ........ ............. .................. ....................................................
#
21.48% stress-ng-cpu /usr/bin/stress-ng 0x35e80 l [.] is_prime
16.02% stress-ng-cpu /usr/bin/stress-ng 0x3bbf6 l [.] stress_cpu_sieve
12.61% stress-ng-cpu /usr/bin/stress-ng 0x65ec6 l [.] stress_cpu_cpuid.sse2.2
11.94% stress-ng-cpu /usr/bin/stress-ng 0x3c66b l [.] ackermann
8.24% stress-ng-cpu /usr/bin/stress-ng 0x39fd8 l [.] stress_cpu_correlate
3.82% stress-ng-cpu /usr/bin/stress-ng 0x64742 l [.] queens_try
2.63% stress-ng-cpu /usr/bin/stress-ng 0x7a0a8 l [.] stress_cpu_nsqrt.sse2.2
2.46% stress-ng-cpu /usr/bin/stress-ng 0x3400e l [.] ccitt_crc16
2.25% stress-ng-cpu /usr/bin/stress-ng 0x71761 l [.] stress_cpu_complex_long_double.sse2.2
[root@quaco ~]#
>
> jirka
>
> >
> > - Arnaldo
> >
> > > Signed-off-by: Jiri Olsa <[email protected]>
> > > ---
> > > tools/perf/builtin-buildid-list.c | 3 +++
> > > 1 file changed, 3 insertions(+)
> > >
> > > diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
> > > index e3ef75583514..87f5b1a4a7fa 100644
> > > --- a/tools/perf/builtin-buildid-list.c
> > > +++ b/tools/perf/builtin-buildid-list.c
> > > @@ -77,6 +77,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
> > > perf_header__has_feat(&session->header, HEADER_AUXTRACE))
> > > with_hits = false;
> > >
> > > + if (!perf_header__has_feat(&session->header, HEADER_BUILD_ID))
> > > + with_hits = true;
> > > +
> > > /*
> > > * in pipe-mode, the only way to get the buildids is to parse
> > > * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
> > > --
> > > 2.26.2
> > >
> >
> > --
> >
> > - Arnaldo
> >
>
--
- Arnaldo
On Tue, Nov 17, 2020 at 02:43:33PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Tue, Nov 17, 2020 at 04:16:51PM +0100, Jiri Olsa escreveu:
> > On Tue, Nov 17, 2020 at 09:44:37AM -0300, Arnaldo Carvalho de Melo wrote:
> > > Em Tue, Nov 17, 2020 at 12:00:42PM +0100, Jiri Olsa escreveu:
> > > > Allow mmap2 event to synthesize kernel image,
> > > > so we can synthesize kernel build id data in
> > > > following changes.
> > > >
> > > > It's enabled by new symbol_conf.buildid_mmap2
> > > > bool, which will be switched in following
> > > > changes.
> > >
> > > Why make this an option? MMAP2 goes back years:
> > >
> > > 13d7a2410fa637f45 (Stephane Eranian 2013-08-21 12:10:24 +0200 904) * The MMAP2 records are an augmented version of MMAP, they add
> > > 13d7a2410fa637f45 (Stephane Eranian 2013-08-21 12:10:24 +0200 905) * maj, min, ino numbers to be used to uniquely identify each mapping
> > >
> > > Also we unconditionally generate MMAP2 events if the kernel supports it,
> > > from evsel__config():
> > >
> > > attr->mmap = track;
> > > attr->mmap2 = track && !perf_missing_features.mmap2;
> > >
> > > So perhaps we should reuse that logic? I.e. use mmap2 if the kernel
> > > supports it?
> >
> > mmap2 itself is not a problem, the problem is the new
> > bit (PERF_RECORD_MISC_MMAP_BUILD_ID) that says there's
> > build id in mmap2.. older perf tool won't understand
> > that and report will crash
>
> Is this theoretical or have you experienced it?
>
> Would be good to tweak the perf.data reader code to not crash on unknown
> bits like that :-\
>
> But by looking at machine__process_mmap2_event() I couldn't imagine how
> that would crash.
>
> It would get bogus maj, min, ino, ino_generation, but probably that
> wouldn't make it crash.
right, I shouldn't said crash, sry ;-) but bogus values are worse
than that anyway
jirka
On Tue, Nov 17, 2020 at 02:54:00PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Tue, Nov 17, 2020 at 04:21:40PM +0100, Jiri Olsa escreveu:
> > On Tue, Nov 17, 2020 at 09:50:40AM -0300, Arnaldo Carvalho de Melo wrote:
> > > Em Tue, Nov 17, 2020 at 12:00:52PM +0100, Jiri Olsa escreveu:
> > > > Add buildid-list support for mmap2's build id data, so we can
> > > > display build ids for dso objects for data without the build
> > > > id cache update.
> > >
> > > > $ perf buildid-list
> > > > 1805c738c8f3ec0f47b7ea09080c28f34d18a82b /usr/lib64/ld-2.31.so
> > > > d278249792061c6b74d1693ca59513be1def13f2 /usr/lib64/libc-2.31.so
> > > >
> > > > By default only dso objects with hits are shown.
> > >
> > > Would be interesting to be able to show all the build ids that are
> > > there. a 'perf buildid-list --all' or make this under --force?
> >
> > ok, will check.. one other tool I think would be handy is
> > to show which debuginfo is not available, because it can
> > change the report a lot - missing symbols are not getting
> > accounted, and their hits are accounted only as separated
> > addresses
>
> Right, as below.
>
> So you suggest something like:
>
> # perf buildid-cache --fetch-missing-debuginfo
haven't thought about interface yet, just noticed it's something
that's not so easy to find out while we can present it to user quite
easily
the interface needs to have perf.data in it, because buildid-cache
does not work on top of perf.data, perhaps something like:
# perf report --show-missing-debuginfo
or on top of current interface:
# perf buildid-cache -a perf.data --show-missing-debuginfo
jirka
On Tue, Nov 17, 2020 at 11:00:37AM -0800, Ian Rogers wrote:
> On Tue, Nov 17, 2020 at 3:01 AM Jiri Olsa <[email protected]> wrote:
>
> > Adding build_id__is_defined helper to check build id
> > is defined and is != zero build id.
> >
> > Signed-off-by: Jiri Olsa <[email protected]>
> > ---
> > tools/perf/util/build-id.c | 7 +++++++
> > tools/perf/util/build-id.h | 1 +
> > 2 files changed, 8 insertions(+)
> >
> > diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> > index 6b410c3d52dc..7d9ecc37849c 100644
> > --- a/tools/perf/util/build-id.c
> > +++ b/tools/perf/util/build-id.c
> > @@ -912,3 +912,10 @@ void build_id__init(struct build_id *bid, const u8
> > *data, size_t size)
> > memcpy(bid->data, data, size);
> > bid->size = size;
> > }
> > +
> > +bool build_id__is_defined(const struct build_id *bid)
> > +{
> > + static u8 zero[BUILD_ID_SIZE];
> > +
> > + return bid && bid->size ? memcmp(bid->data, &zero, bid->size) :
> > false;
> >
>
> Fwiw, I find this method to test for zero a little hard to parse - I'm
heh, it's controversial one, Namhyung commented
on this one in previous version, so I changed it ;-)
https://lore.kernel.org/lkml/CAM9d7cjjGjTN8sDgLZ1PoQZ-sUXWjnVaNdyOVE1yHxq46PrPkw@mail.gmail.com/
> failing as a C programmer :-) Nit, should zero be const?
right, should be const, will change
thanks,
jirka
Em Tue, Nov 17, 2020 at 09:53:59PM +0100, Jiri Olsa escreveu:
> On Tue, Nov 17, 2020 at 11:00:37AM -0800, Ian Rogers wrote:
> > On Tue, Nov 17, 2020 at 3:01 AM Jiri Olsa <[email protected]> wrote:
> >
> > > Adding build_id__is_defined helper to check build id
> > > is defined and is != zero build id.
> > >
> > > Signed-off-by: Jiri Olsa <[email protected]>
> > > ---
> > > tools/perf/util/build-id.c | 7 +++++++
> > > tools/perf/util/build-id.h | 1 +
> > > 2 files changed, 8 insertions(+)
> > >
> > > diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> > > index 6b410c3d52dc..7d9ecc37849c 100644
> > > --- a/tools/perf/util/build-id.c
> > > +++ b/tools/perf/util/build-id.c
> > > @@ -912,3 +912,10 @@ void build_id__init(struct build_id *bid, const u8
> > > *data, size_t size)
> > > memcpy(bid->data, data, size);
> > > bid->size = size;
> > > }
> > > +
> > > +bool build_id__is_defined(const struct build_id *bid)
> > > +{
> > > + static u8 zero[BUILD_ID_SIZE];
> > > +
> > > + return bid && bid->size ? memcmp(bid->data, &zero, bid->size) :
> > > false;
> > Fwiw, I find this method to test for zero a little hard to parse - I'm
>
> heh, it's controversial one, Namhyung commented
> on this one in previous version, so I changed it ;-)
> https://lore.kernel.org/lkml/CAM9d7cjjGjTN8sDgLZ1PoQZ-sUXWjnVaNdyOVE1yHxq46PrPkw@mail.gmail.com/
So, the kernel has an idiom for this in lib/string.c:
/**
* memchr_inv - Find an unmatching character in an area of memory.
* @start: The memory area
* @c: Find a character other than c
* @bytes: The size of the area.
*
* returns the address of the first character other than @c, or %NULL
* if the whole buffer contains just @c.
*/
void *memchr_inv(const void *start, int c, size_t bytes)
No need for any array of some particular size :-)
Its been there for a while:
commit 798248206b59acc6e1238c778281419c041891a7
Author: Akinobu Mita <[email protected]>
Date: Mon Oct 31 17:08:07 2011 -0700
lib/string.c: introduce memchr_inv()
memchr_inv() is mainly used to check whether the whole buffer is filled
with just a specified byte.
- Arnaldo
>
> > failing as a C programmer :-) Nit, should zero be const?
>
> right, should be const, will change
On Tue, Nov 17, 2020 at 01:23:09PM -0800, Ian Rogers wrote:
> On Tue, Nov 17, 2020 at 3:01 AM Jiri Olsa <[email protected]> wrote:
>
> > When adding new build id link we fail if the link is already
> > there. Adding check for existing link and output debug message
> > that the build id is already linked.
> >
> > Signed-off-by: Jiri Olsa <[email protected]>
> > ---
> > tools/perf/util/build-id.c | 15 ++++++++++++++-
> > 1 file changed, 14 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> > index 7d9ecc37849c..ef9a31b54ba2 100644
> > --- a/tools/perf/util/build-id.c
> > +++ b/tools/perf/util/build-id.c
> > @@ -754,8 +754,21 @@ int build_id_cache__add_s(const char *sbuild_id,
> > const char *name,
> > tmp = dir_name + strlen(buildid_dir) - 5;
> > memcpy(tmp, "../..", 5);
> >
> > - if (symlink(tmp, linkname) == 0)
> > + if (symlink(tmp, linkname) == 0) {
> > err = 0;
> > + } else if (errno == EEXIST) {
> > + char path[PATH_MAX];
> > +
> > + if (readlink(linkname, path, sizeof(path)) == -1) {
> > + pr_err("Cant read link: %s\n", linkname);
> > + goto out_free;
> > + }
> >
>
> readlink needs null termination, such as:
> https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/perf/util/build-id.c?h=perf/core#n212
will fix, thanks
jirka
>
> Thanks,
> Ian
>
> + if (strcmp(tmp, path)) {
> > + pr_debug("build <%s> already linked to %s\n",
> > + sbuild_id, linkname);
> > + }
> > + err = 0;
> > + }
> >
> > /* Update SDT cache : error is just warned */
> > if (realname &&
> > --
> > 2.26.2
> >
> >
On Tue, Nov 17, 2020 at 08:33:13PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Tue, Nov 17, 2020 at 09:53:59PM +0100, Jiri Olsa escreveu:
> > On Tue, Nov 17, 2020 at 11:00:37AM -0800, Ian Rogers wrote:
> > > On Tue, Nov 17, 2020 at 3:01 AM Jiri Olsa <[email protected]> wrote:
> > >
> > > > Adding build_id__is_defined helper to check build id
> > > > is defined and is != zero build id.
> > > >
> > > > Signed-off-by: Jiri Olsa <[email protected]>
> > > > ---
> > > > tools/perf/util/build-id.c | 7 +++++++
> > > > tools/perf/util/build-id.h | 1 +
> > > > 2 files changed, 8 insertions(+)
> > > >
> > > > diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> > > > index 6b410c3d52dc..7d9ecc37849c 100644
> > > > --- a/tools/perf/util/build-id.c
> > > > +++ b/tools/perf/util/build-id.c
> > > > @@ -912,3 +912,10 @@ void build_id__init(struct build_id *bid, const u8
> > > > *data, size_t size)
> > > > memcpy(bid->data, data, size);
> > > > bid->size = size;
> > > > }
> > > > +
> > > > +bool build_id__is_defined(const struct build_id *bid)
> > > > +{
> > > > + static u8 zero[BUILD_ID_SIZE];
> > > > +
> > > > + return bid && bid->size ? memcmp(bid->data, &zero, bid->size) :
> > > > false;
>
> > > Fwiw, I find this method to test for zero a little hard to parse - I'm
> >
> > heh, it's controversial one, Namhyung commented
> > on this one in previous version, so I changed it ;-)
> > https://lore.kernel.org/lkml/CAM9d7cjjGjTN8sDgLZ1PoQZ-sUXWjnVaNdyOVE1yHxq46PrPkw@mail.gmail.com/
>
> So, the kernel has an idiom for this in lib/string.c:
>
> /**
> * memchr_inv - Find an unmatching character in an area of memory.
> * @start: The memory area
> * @c: Find a character other than c
> * @bytes: The size of the area.
> *
> * returns the address of the first character other than @c, or %NULL
> * if the whole buffer contains just @c.
> */
> void *memchr_inv(const void *start, int c, size_t bytes)
>
> No need for any array of some particular size :-)
ok, will check
thanks,
jirka
On Thu, Nov 19, 2020 at 12:23:53PM -0800, Ian Rogers wrote:
> On Mon, Nov 9, 2020 at 1:55 PM Jiri Olsa <[email protected]> wrote:
>
> > Adding --debuginfod option to specify debuginfod url and
> > support to do that through config file as well.
> >
> > Use following in ~/.perfconfig file:
> >
> > [buildid-cache]
> > debuginfod=http://192.168.122.174:8002
> >
> > Signed-off-by: Jiri Olsa <[email protected]>
> > ---
> > .../perf/Documentation/perf-buildid-cache.txt | 4 +++
> > tools/perf/builtin-buildid-cache.c | 28 +++++++++++++++++--
> > 2 files changed, 29 insertions(+), 3 deletions(-)
> >
> > diff --git a/tools/perf/Documentation/perf-buildid-cache.txt
> > b/tools/perf/Documentation/perf-buildid-cache.txt
> > index b77da5138bca..0152d8b5cfbe 100644
> > --- a/tools/perf/Documentation/perf-buildid-cache.txt
> > +++ b/tools/perf/Documentation/perf-buildid-cache.txt
> > @@ -84,6 +84,10 @@ OPTIONS
> > used when creating a uprobe for a process that resides in a
> > different mount namespace from the perf(1) utility.
> >
> > +--debuginfod=URL::
> > + Specify debuginfod URL to be used when retrieving perf.data
> > binaries,
> > + it follows the same syntax as the DEBUGINFOD_URLS variable.
> > +
> >
>
> Acked-by: Ian Rogers <[email protected]>
>
> Nit: the environment variable name hints at this being a list, perhaps
> change URL:: above to URLs:: to keep this clear.
true, will change that
thanks,
jirka
On Tue, Nov 17, 2020 at 12:13:34PM +0100, Peter Zijlstra wrote:
> On Tue, Nov 17, 2020 at 12:00:32PM +0100, Jiri Olsa wrote:
> > Adding support to carry build id data in mmap2 event.
> >
> > The build id data replaces maj/min/ino/ino_generation
> > fields, which are also used to identify map's binary,
> > so it's ok to replace them with build id data:
> >
> > union {
> > struct {
> > u32 maj;
> > u32 min;
> > u64 ino;
> > u64 ino_generation;
> > };
> > struct {
> > u8 build_id_size;
> > u8 __reserved_1;
> > u16 __reserved_2;
> > u8 build_id[20];
> > };
> > };
> >
> > Replaced maj/min/ino/ino_generation fields give us size
> > of 24 bytes. We use 20 bytes for build id data, 1 byte
> > for size and rest is unused.
> >
> > There's new misc bit for mmap2 to signal there's build
> > id data in it:
> >
> > #define PERF_RECORD_MISC_MMAP_BUILD_ID (1 << 14)
> >
> > Signed-off-by: Jiri Olsa <[email protected]>
>
> Seems sane enough; how do we want to route this?
>
> Acked-by: Peter Zijlstra (Intel) <[email protected]>
>
I still need review from bpf folks, but then I guess
Arnaldo's tree would be the best, because it's mostly
tools changes.. I'm sending new version
jirka