• T
    perf record: Fix wrong size in perf_record_mmap for last kernel module · 9ad4652b
    Thomas Richter 提交于
    During work on perf report for s390 I ran into the following issue:
    
    0 0x318 [0x78]: PERF_RECORD_MMAP -1/0:
            [0x3ff804d6990(0xfffffc007fb2966f) @ 0]:
            x /lib/modules/4.12.0perf1+/kernel/drivers/s390/net/qeth_l2.ko
    
    This is a PERF_RECORD_MMAP entry of the perf.data file with an invalid
    module size for qeth_l2.ko (the s390 ethernet device driver).
    
    Even a mainframe does not have 0xfffffc007fb2966f bytes of main memory.
    
    It turned out that this wrong size is created by the perf record
    command.  What happens is this function call sequence from
    __cmd_record():
    
      perf_session__new():
        perf_session__create_kernel_maps():
          machine__create_kernel_maps():
            machine__create_modules():   Creates map for all loaded kernel modules.
              modules__parse():   Reads /proc/modules and extracts module name and
                                  load address (1st and last column)
                machine__create_module():   Called for every module found in /proc/modules.
                                  Creates a new map for every module found and enters
                                  module name and start address into the map. Since the
                                  module end address is unknown it is set to zero.
    
    This ends up with a kernel module map list sorted by module start
    addresses.  All module end addresses are zero.
    
    Last machine__create_kernel_maps() calls function map_groups__fixup_end().
    This function iterates through the maps and assigns each map entry's
    end address the successor map entry start address. The last entry of the
    map group has no successor, so ~0 is used as end to consume the remaining
    memory.
    
    Later __cmd_record calls function record__synthesize() which in turn calls
    perf_event__synthesize_kernel_mmap() and perf_event__synthesize_modules()
    to create PERF_REPORT_MMAP entries into the perf.data file.
    
    On s390 this results in the last module qeth_l2.ko
    (which has highest start address, see module table:
            [root@s8360047 perf]# cat /proc/modules
            qeth_l2 86016 1 - Live 0x000003ff804d6000
            qeth 266240 1 qeth_l2, Live 0x000003ff80296000
            ccwgroup 24576 1 qeth, Live 0x000003ff80218000
            vmur 36864 0 - Live 0x000003ff80182000
            qdio 143360 2 qeth_l2,qeth, Live 0x000003ff80002000
            [root@s8360047 perf]# )
    to be the last entry and its map has an end address of ~0.
    
    When the PERF_RECORD_MMAP entry is created for kernel module qeth_l2.ko
    its start address and length is written. The length is calculated in line:
        event->mmap.len   = pos->end - pos->start;
    and results in 0xffffffffffffffff - 0x3ff804d6990(*) = 0xfffffc007fb2966f
    
    (*) On s390 the module start address is actually determined by a __weak function
    named arch__fix_module_text_start() in machine__create_module().
    
    I think this improvable. We can use the module size (2nd column of /proc/modules)
    to get each loaded kernel module size and calculate its end address.
    Only for map entries which do not have a valid end address (end is still zero)
    we can use the heuristic we have now, that is use successor start address or ~0.
    Signed-off-by: NThomas-Mich Richter <tmricht@linux.vnet.ibm.com>
    Reviewed-by: NArnaldo Carvalho de Melo <acme@redhat.com>
    Cc: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
    Cc: Thomas-Mich Richter <tmricht@linux.vnet.ibm.com>
    Cc: Zvonko Kosic <zvonko.kosic@de.ibm.com>
    LPU-Reference: 20170803134902.47207-2-tmricht@linux.vnet.ibm.com
    Link: http://lkml.kernel.org/n/tip-nmoqij5b5vxx7rq2ckwu8iaj@git.kernel.orgSigned-off-by: NArnaldo Carvalho de Melo <acme@redhat.com>
    9ad4652b
symbol-elf.c 46.8 KB