During execution of command 'perf top' the error message:
Not enough memory for annotating '__irf_end' symbol!)
is emitted from this call sequence:
__cmd_top
perf_top__mmap_read
perf_top__mmap_read_idx
perf_event__process_sample
hist_entry_iter__add
hist_iter__top_callback
perf_top__record_precise_ip
hist_entry__inc_addr_samples
symbol__inc_addr_samples
symbol__get_annotation
symbol__alloc_hist
In this function the size of symbol __irf_end is calculated. The size of
a symbol is the difference between its start and end address.
When the symbol was read the first time, its start and end was set to:
symbol__new: __irf_end 0xe954d0-0xe954d0
which is correct and maps with /proc/kallsyms:
root@s8360046:~/linux-4.15.0/tools/perf# fgrep _irf_end /proc/kallsyms
0000000000e954d0 t __irf_end
root@s8360046:~/linux-4.15.0/tools/perf#
In function symbol__alloc_hist() the end of symbol __irf_end is
symbol__alloc_hist sym:__irf_end start:0xe954d0 end:0x3ff80045a8
which is identical with the first module entry in /proc/kallsyms
This results in a symbol size of __irf_req for histogram analyses of
70334140059072 bytes and a malloc() for this requested size fails.
The root cause of this is function
__dso__load_kallsyms()
+-> symbols__fixup_end()
Function symbols__fixup_end() enlarges the last symbol in the kallsyms
map:
# fgrep __irf_end /proc/kallsyms
0000000000e954d0 t __irf_end
#
to the start address of the first module:
# cat /proc/kallsyms | sort | egrep ' [tT] '
....
0000000000e952d0 T __security_initcall_end
0000000000e954d0 T __initramfs_size
0000000000e954d0 t __irf_end
000003ff800045a8 T fc_get_event_number [scsi_transport_fc]
000003ff800045d0 t store_fc_vport_disable [scsi_transport_fc]
000003ff800046a8 T scsi_is_fc_rport [scsi_transport_fc]
000003ff800046d0 t fc_target_setup [scsi_transport_fc]
On s390 the kernel is located around memory address 0x200, 0x10000 or
0x100000, depending on linux version. Modules however start some- where
around 0x3ff xxxx xxxx.
This is different than x86 and produces a large gap for which histogram
allocation fails.
Fix this by detecting the kernel's last symbol and do no adjustment for
it. Introduce a weak function and handle s390 specifics.
Reported-by: Klaus Theurich <klaus.theurich@de.ibm.com>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Hendrik Brueckner <brueckner@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/20190724122703.3996-2-tmricht@linux.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
53 lines
1.7 KiB
C
53 lines
1.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "util.h"
|
|
#include "machine.h"
|
|
#include "api/fs/fs.h"
|
|
#include "debug.h"
|
|
#include "symbol.h"
|
|
|
|
int arch__fix_module_text_start(u64 *start, u64 *size, const char *name)
|
|
{
|
|
u64 m_start = *start;
|
|
char path[PATH_MAX];
|
|
|
|
snprintf(path, PATH_MAX, "module/%.*s/sections/.text",
|
|
(int)strlen(name) - 2, name + 1);
|
|
if (sysfs__read_ull(path, (unsigned long long *)start) < 0) {
|
|
pr_debug2("Using module %s start:%#lx\n", path, m_start);
|
|
*start = m_start;
|
|
} else {
|
|
/* Successful read of the modules segment text start address.
|
|
* Calculate difference between module start address
|
|
* in memory and module text segment start address.
|
|
* For example module load address is 0x3ff8011b000
|
|
* (from /proc/modules) and module text segment start
|
|
* address is 0x3ff8011b870 (from file above).
|
|
*
|
|
* Adjust the module size and subtract the GOT table
|
|
* size located at the beginning of the module.
|
|
*/
|
|
*size -= (*start - m_start);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* On s390 kernel text segment start is located at very low memory addresses,
|
|
* for example 0x10000. Modules are located at very high memory addresses,
|
|
* for example 0x3ff xxxx xxxx. The gap between end of kernel text segment
|
|
* and beginning of first module's text segment is very big.
|
|
* Therefore do not fill this gap and do not assign it to the kernel dso map.
|
|
*/
|
|
void arch__symbols__fixup_end(struct symbol *p, struct symbol *c)
|
|
{
|
|
if (strchr(p->name, '[') == NULL && strchr(c->name, '['))
|
|
/* Last kernel symbol mapped to end of page */
|
|
p->end = roundup(p->end, page_size);
|
|
else
|
|
p->end = c->start;
|
|
pr_debug4("%s sym:%s end:%#lx\n", __func__, p->name, p->end);
|
|
}
|