| From 12a6d2940b5f02b4b9f71ce098e3bb02bc24a9ea Mon Sep 17 00:00:00 2001 |
| From: Thomas Richter <tmricht@linux.ibm.com> |
| Date: Wed, 24 Jul 2019 14:27:02 +0200 |
| Subject: perf record: Fix module size on s390 |
| |
| From: Thomas Richter <tmricht@linux.ibm.com> |
| |
| commit 12a6d2940b5f02b4b9f71ce098e3bb02bc24a9ea upstream. |
| |
| On s390 the modules loaded in memory have the text segment located after |
| the GOT and Relocation table. This can be seen with this output: |
| |
| [root@m35lp76 perf]# fgrep qeth /proc/modules |
| qeth 151552 1 qeth_l2, Live 0x000003ff800b2000 |
| ... |
| [root@m35lp76 perf]# cat /sys/module/qeth/sections/.text |
| 0x000003ff800b3990 |
| [root@m35lp76 perf]# |
| |
| There is an offset of 0x1990 bytes. The size of the qeth module is |
| 151552 bytes (0x25000 in hex). |
| |
| The location of the GOT/relocation table at the beginning of a module is |
| unique to s390. |
| |
| commit 203d8a4aa6ed ("perf s390: Fix 'start' address of module's map") |
| adjusts the start address of a module in the map structures, but does |
| not adjust the size of the modules. This leads to overlapping of module |
| maps as this example shows: |
| |
| [root@m35lp76 perf] # ./perf report -D |
| 0 0 0xfb0 [0xa0]: PERF_RECORD_MMAP -1/0: [0x3ff800b3990(0x25000) |
| @ 0]: x /lib/modules/.../qeth.ko.xz |
| 0 0 0x1050 [0xb0]: PERF_RECORD_MMAP -1/0: [0x3ff800d85a0(0x8000) |
| @ 0]: x /lib/modules/.../ip6_tables.ko.xz |
| |
| The module qeth.ko has an adjusted start address modified to b3990, but |
| its size is unchanged and the module ends at 0x3ff800d8990. This end |
| address overlaps with the next modules start address of 0x3ff800d85a0. |
| |
| When the size of the leading GOT/Relocation table stored in the |
| beginning of the text segment (0x1990 bytes) is subtracted from module |
| qeth end address, there are no overlaps anymore: |
| |
| 0x3ff800d8990 - 0x1990 = 0x0x3ff800d7000 |
| |
| which is the same as |
| |
| 0x3ff800b2000 + 0x25000 = 0x0x3ff800d7000. |
| |
| To fix this issue, also adjust the modules size in function |
| arch__fix_module_text_start(). Add another function parameter named size |
| and reduce the size of the module when the text segment start address is |
| changed. |
| |
| Output after: |
| 0 0 0xfb0 [0xa0]: PERF_RECORD_MMAP -1/0: [0x3ff800b3990(0x23670) |
| @ 0]: x /lib/modules/.../qeth.ko.xz |
| 0 0 0x1050 [0xb0]: PERF_RECORD_MMAP -1/0: [0x3ff800d85a0(0x7a60) |
| @ 0]: x /lib/modules/.../ip6_tables.ko.xz |
| |
| Reported-by: Stefan Liebler <stli@linux.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 |
| Fixes: 203d8a4aa6ed ("perf s390: Fix 'start' address of module's map") |
| Link: http://lkml.kernel.org/r/20190724122703.3996-1-tmricht@linux.ibm.com |
| Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| tools/perf/arch/s390/util/machine.c | 14 +++++++++++++- |
| tools/perf/util/machine.c | 3 ++- |
| tools/perf/util/machine.h | 2 +- |
| 3 files changed, 16 insertions(+), 3 deletions(-) |
| |
| --- a/tools/perf/arch/s390/util/machine.c |
| +++ b/tools/perf/arch/s390/util/machine.c |
| @@ -8,7 +8,7 @@ |
| #include "debug.h" |
| #include "symbol.h" |
| |
| -int arch__fix_module_text_start(u64 *start, const char *name) |
| +int arch__fix_module_text_start(u64 *start, u64 *size, const char *name) |
| { |
| u64 m_start = *start; |
| char path[PATH_MAX]; |
| @@ -18,6 +18,18 @@ int arch__fix_module_text_start(u64 *sta |
| 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; |
| --- a/tools/perf/util/machine.c |
| +++ b/tools/perf/util/machine.c |
| @@ -1233,6 +1233,7 @@ static int machine__set_modules_path(str |
| return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0); |
| } |
| int __weak arch__fix_module_text_start(u64 *start __maybe_unused, |
| + u64 *size __maybe_unused, |
| const char *name __maybe_unused) |
| { |
| return 0; |
| @@ -1244,7 +1245,7 @@ static int machine__create_module(void * |
| struct machine *machine = arg; |
| struct map *map; |
| |
| - if (arch__fix_module_text_start(&start, name) < 0) |
| + if (arch__fix_module_text_start(&start, &size, name) < 0) |
| return -1; |
| |
| map = machine__findnew_module_map(machine, start, name); |
| --- a/tools/perf/util/machine.h |
| +++ b/tools/perf/util/machine.h |
| @@ -213,7 +213,7 @@ struct symbol *machine__find_kernel_func |
| |
| struct map *machine__findnew_module_map(struct machine *machine, u64 start, |
| const char *filename); |
| -int arch__fix_module_text_start(u64 *start, const char *name); |
| +int arch__fix_module_text_start(u64 *start, u64 *size, const char *name); |
| |
| int __machine__load_kallsyms(struct machine *machine, const char *filename, |
| enum map_type type, bool no_kcore); |