aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2014-02-14 14:11:18 -0500
committerH. Peter Anvin <hpa@linux.intel.com>2014-02-14 14:11:18 -0500
commit31fce91e7afc25c666276f65f019bc13fd27e216 (patch)
tree24f9673614a98a06fd8f4254c63b306dddd5aac6
parent4640c7ee9b8953237d05a61ea3ea93981d1bc961 (diff)
parent09503379dc99535b1bbfa51aa1aeef340f5d82ec (diff)
Merge remote-tracking branch 'efi/urgent' into x86/urgent
There have been reports of EFI crashes since -rc1. The following two commits fix known issues. * Fix boot failure on 32-bit EFI due to the recent EFI memmap changes merged during the merge window - Borislav Petkov * Avoid a crash during efi_bgrt_init() by detecting invalid BGRT headers based on the 'status' field. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--Makefile2
-rw-r--r--arch/x86/include/asm/efi.h2
-rw-r--r--arch/x86/platform/efi/efi-bgrt.c2
-rw-r--r--arch/x86/platform/efi/efi.c5
-rw-r--r--arch/x86/platform/efi/efi_32.c6
-rw-r--r--arch/x86/platform/efi/efi_64.c9
-rw-r--r--drivers/char/virtio_console.c9
-rw-r--r--fs/btrfs/compression.c2
-rw-r--r--fs/btrfs/extent-tree.c1
-rw-r--r--fs/btrfs/ioctl.c6
-rw-r--r--fs/btrfs/send.c8
-rw-r--r--fs/cifs/file.c4
-rw-r--r--fs/ext4/file.c2
-rw-r--r--fs/ntfs/file.c2
-rw-r--r--fs/sync.c17
-rw-r--r--fs/xfs/xfs_file.c2
-rw-r--r--include/linux/fs.h8
-rw-r--r--mm/filemap.c4
-rw-r--r--security/selinux/nlmsgtab.c2
-rw-r--r--security/selinux/ss/services.c4
-rw-r--r--tools/perf/builtin-buildid-cache.c33
-rw-r--r--tools/perf/builtin-record.c10
-rw-r--r--tools/perf/design.txt1
-rw-r--r--tools/perf/perf.h4
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c10
-rw-r--r--tools/perf/util/event.c36
-rw-r--r--tools/perf/util/event.h6
-rw-r--r--tools/perf/util/include/asm/hash.h6
-rw-r--r--tools/perf/util/machine.c42
-rw-r--r--tools/perf/util/machine.h2
-rw-r--r--tools/perf/util/map.c5
-rw-r--r--tools/perf/util/map.h1
-rw-r--r--tools/perf/util/symbol-elf.c4
-rw-r--r--tools/perf/util/symbol.c65
34 files changed, 215 insertions, 107 deletions
diff --git a/Makefile b/Makefile
index 606ef7c4a544..933e1def6baf 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
1VERSION = 3 1VERSION = 3
2PATCHLEVEL = 14 2PATCHLEVEL = 14
3SUBLEVEL = 0 3SUBLEVEL = 0
4EXTRAVERSION = -rc1 4EXTRAVERSION = -rc2
5NAME = Shuffling Zombie Juror 5NAME = Shuffling Zombie Juror
6 6
7# *DOCUMENTATION* 7# *DOCUMENTATION*
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 3b978c472d08..3d6b9f81cc68 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -132,6 +132,8 @@ extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
132extern void efi_sync_low_kernel_mappings(void); 132extern void efi_sync_low_kernel_mappings(void);
133extern void efi_setup_page_tables(void); 133extern void efi_setup_page_tables(void);
134extern void __init old_map_region(efi_memory_desc_t *md); 134extern void __init old_map_region(efi_memory_desc_t *md);
135extern void __init runtime_code_page_mkexec(void);
136extern void __init efi_runtime_mkexec(void);
135 137
136struct efi_setup_data { 138struct efi_setup_data {
137 u64 fw_vendor; 139 u64 fw_vendor;
diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c
index 4df9591eadad..f15103dff4b4 100644
--- a/arch/x86/platform/efi/efi-bgrt.c
+++ b/arch/x86/platform/efi/efi-bgrt.c
@@ -42,7 +42,7 @@ void __init efi_bgrt_init(void)
42 42
43 if (bgrt_tab->header.length < sizeof(*bgrt_tab)) 43 if (bgrt_tab->header.length < sizeof(*bgrt_tab))
44 return; 44 return;
45 if (bgrt_tab->version != 1) 45 if (bgrt_tab->version != 1 || bgrt_tab->status != 1)
46 return; 46 return;
47 if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address) 47 if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address)
48 return; 48 return;
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index d62ec87a2b26..1a201ac7cef8 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -792,7 +792,7 @@ void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
792 set_memory_nx(addr, npages); 792 set_memory_nx(addr, npages);
793} 793}
794 794
795static void __init runtime_code_page_mkexec(void) 795void __init runtime_code_page_mkexec(void)
796{ 796{
797 efi_memory_desc_t *md; 797 efi_memory_desc_t *md;
798 void *p; 798 void *p;
@@ -1069,8 +1069,7 @@ void __init efi_enter_virtual_mode(void)
1069 efi.update_capsule = virt_efi_update_capsule; 1069 efi.update_capsule = virt_efi_update_capsule;
1070 efi.query_capsule_caps = virt_efi_query_capsule_caps; 1070 efi.query_capsule_caps = virt_efi_query_capsule_caps;
1071 1071
1072 if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX)) 1072 efi_runtime_mkexec();
1073 runtime_code_page_mkexec();
1074 1073
1075 kfree(new_memmap); 1074 kfree(new_memmap);
1076 1075
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c
index 249b183cf417..0b74cdf7f816 100644
--- a/arch/x86/platform/efi/efi_32.c
+++ b/arch/x86/platform/efi/efi_32.c
@@ -77,3 +77,9 @@ void efi_call_phys_epilog(void)
77 77
78 local_irq_restore(efi_rt_eflags); 78 local_irq_restore(efi_rt_eflags);
79} 79}
80
81void __init efi_runtime_mkexec(void)
82{
83 if (__supported_pte_mask & _PAGE_NX)
84 runtime_code_page_mkexec();
85}
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index 6284f158a47d..0c2a234fef1e 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -233,3 +233,12 @@ void __init parse_efi_setup(u64 phys_addr, u32 data_len)
233{ 233{
234 efi_setup = phys_addr + sizeof(struct setup_data); 234 efi_setup = phys_addr + sizeof(struct setup_data);
235} 235}
236
237void __init efi_runtime_mkexec(void)
238{
239 if (!efi_enabled(EFI_OLD_MEMMAP))
240 return;
241
242 if (__supported_pte_mask & _PAGE_NX)
243 runtime_code_page_mkexec();
244}
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index feea87cc6b8f..6928d094451d 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -890,12 +890,10 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
890 } else { 890 } else {
891 /* Failback to copying a page */ 891 /* Failback to copying a page */
892 struct page *page = alloc_page(GFP_KERNEL); 892 struct page *page = alloc_page(GFP_KERNEL);
893 char *src = buf->ops->map(pipe, buf, 1); 893 char *src;
894 char *dst;
895 894
896 if (!page) 895 if (!page)
897 return -ENOMEM; 896 return -ENOMEM;
898 dst = kmap(page);
899 897
900 offset = sd->pos & ~PAGE_MASK; 898 offset = sd->pos & ~PAGE_MASK;
901 899
@@ -903,9 +901,8 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
903 if (len + offset > PAGE_SIZE) 901 if (len + offset > PAGE_SIZE)
904 len = PAGE_SIZE - offset; 902 len = PAGE_SIZE - offset;
905 903
906 memcpy(dst + offset, src + buf->offset, len); 904 src = buf->ops->map(pipe, buf, 1);
907 905 memcpy(page_address(page) + offset, src + buf->offset, len);
908 kunmap(page);
909 buf->ops->unmap(pipe, buf, src); 906 buf->ops->unmap(pipe, buf, src);
910 907
911 sg_set_page(&(sgl->sg[sgl->n]), page, len, offset); 908 sg_set_page(&(sgl->sg[sgl->n]), page, len, offset);
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index e2600cdb6c25..b01fb6c527e3 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -1010,6 +1010,8 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
1010 bytes = min(bytes, working_bytes); 1010 bytes = min(bytes, working_bytes);
1011 kaddr = kmap_atomic(page_out); 1011 kaddr = kmap_atomic(page_out);
1012 memcpy(kaddr + *pg_offset, buf + buf_offset, bytes); 1012 memcpy(kaddr + *pg_offset, buf + buf_offset, bytes);
1013 if (*pg_index == (vcnt - 1) && *pg_offset == 0)
1014 memset(kaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1013 kunmap_atomic(kaddr); 1015 kunmap_atomic(kaddr);
1014 flush_dcache_page(page_out); 1016 flush_dcache_page(page_out);
1015 1017
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 9c9ecc93ae2c..32312e09f0f5 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2385,6 +2385,7 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
2385 spin_unlock(&delayed_refs->lock); 2385 spin_unlock(&delayed_refs->lock);
2386 locked_ref = NULL; 2386 locked_ref = NULL;
2387 cond_resched(); 2387 cond_resched();
2388 count++;
2388 continue; 2389 continue;
2389 } 2390 }
2390 2391
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index b0134892dc70..383ab455bfa7 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -4525,7 +4525,7 @@ static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg)
4525 spin_lock(&root->fs_info->super_lock); 4525 spin_lock(&root->fs_info->super_lock);
4526 strcpy(super_block->label, label); 4526 strcpy(super_block->label, label);
4527 spin_unlock(&root->fs_info->super_lock); 4527 spin_unlock(&root->fs_info->super_lock);
4528 ret = btrfs_end_transaction(trans, root); 4528 ret = btrfs_commit_transaction(trans, root);
4529 4529
4530out_unlock: 4530out_unlock:
4531 mnt_drop_write_file(file); 4531 mnt_drop_write_file(file);
@@ -4668,7 +4668,7 @@ static int btrfs_ioctl_set_features(struct file *file, void __user *arg)
4668 if (ret) 4668 if (ret)
4669 return ret; 4669 return ret;
4670 4670
4671 trans = btrfs_start_transaction(root, 1); 4671 trans = btrfs_start_transaction(root, 0);
4672 if (IS_ERR(trans)) 4672 if (IS_ERR(trans))
4673 return PTR_ERR(trans); 4673 return PTR_ERR(trans);
4674 4674
@@ -4689,7 +4689,7 @@ static int btrfs_ioctl_set_features(struct file *file, void __user *arg)
4689 btrfs_set_super_incompat_flags(super_block, newflags); 4689 btrfs_set_super_incompat_flags(super_block, newflags);
4690 spin_unlock(&root->fs_info->super_lock); 4690 spin_unlock(&root->fs_info->super_lock);
4691 4691
4692 return btrfs_end_transaction(trans, root); 4692 return btrfs_commit_transaction(trans, root);
4693} 4693}
4694 4694
4695long btrfs_ioctl(struct file *file, unsigned int 4695long btrfs_ioctl(struct file *file, unsigned int
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index cf9107a64204..9c8d1a3fdc3a 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -2774,8 +2774,6 @@ static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino)
2774 return 0; 2774 return 0;
2775} 2775}
2776 2776
2777#ifdef CONFIG_BTRFS_ASSERT
2778
2779static int del_waiting_dir_move(struct send_ctx *sctx, u64 ino) 2777static int del_waiting_dir_move(struct send_ctx *sctx, u64 ino)
2780{ 2778{
2781 struct rb_node *n = sctx->waiting_dir_moves.rb_node; 2779 struct rb_node *n = sctx->waiting_dir_moves.rb_node;
@@ -2796,8 +2794,6 @@ static int del_waiting_dir_move(struct send_ctx *sctx, u64 ino)
2796 return -ENOENT; 2794 return -ENOENT;
2797} 2795}
2798 2796
2799#endif
2800
2801static int add_pending_dir_move(struct send_ctx *sctx, u64 parent_ino) 2797static int add_pending_dir_move(struct send_ctx *sctx, u64 parent_ino)
2802{ 2798{
2803 struct rb_node **p = &sctx->pending_dir_moves.rb_node; 2799 struct rb_node **p = &sctx->pending_dir_moves.rb_node;
@@ -2902,7 +2898,9 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
2902 } 2898 }
2903 2899
2904 sctx->send_progress = sctx->cur_ino + 1; 2900 sctx->send_progress = sctx->cur_ino + 1;
2905 ASSERT(del_waiting_dir_move(sctx, pm->ino) == 0); 2901 ret = del_waiting_dir_move(sctx, pm->ino);
2902 ASSERT(ret == 0);
2903
2906 ret = get_cur_path(sctx, pm->ino, pm->gen, to_path); 2904 ret = get_cur_path(sctx, pm->ino, pm->gen, to_path);
2907 if (ret < 0) 2905 if (ret < 0)
2908 goto out; 2906 goto out;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 853d6d1cc822..a7eda8ebfacc 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2559,8 +2559,8 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov,
2559 if (rc > 0) { 2559 if (rc > 0) {
2560 ssize_t err; 2560 ssize_t err;
2561 2561
2562 err = generic_write_sync(file, pos, rc); 2562 err = generic_write_sync(file, iocb->ki_pos - rc, rc);
2563 if (err < 0 && rc > 0) 2563 if (err < 0)
2564 rc = err; 2564 rc = err;
2565 } 2565 }
2566 2566
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 43e64f6022eb..1a5073959f32 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -152,7 +152,7 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov,
152 if (ret > 0) { 152 if (ret > 0) {
153 ssize_t err; 153 ssize_t err;
154 154
155 err = generic_write_sync(file, pos, ret); 155 err = generic_write_sync(file, iocb->ki_pos - ret, ret);
156 if (err < 0 && ret > 0) 156 if (err < 0 && ret > 0)
157 ret = err; 157 ret = err;
158 } 158 }
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index ea4ba9daeb47..db9bd8a31725 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -2134,7 +2134,7 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
2134 ret = ntfs_file_aio_write_nolock(iocb, iov, nr_segs, &iocb->ki_pos); 2134 ret = ntfs_file_aio_write_nolock(iocb, iov, nr_segs, &iocb->ki_pos);
2135 mutex_unlock(&inode->i_mutex); 2135 mutex_unlock(&inode->i_mutex);
2136 if (ret > 0) { 2136 if (ret > 0) {
2137 int err = generic_write_sync(file, pos, ret); 2137 int err = generic_write_sync(file, iocb->ki_pos - ret, ret);
2138 if (err < 0) 2138 if (err < 0)
2139 ret = err; 2139 ret = err;
2140 } 2140 }
diff --git a/fs/sync.c b/fs/sync.c
index f15537452231..e8ba024a055b 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -222,23 +222,6 @@ SYSCALL_DEFINE1(fdatasync, unsigned int, fd)
222 return do_fsync(fd, 1); 222 return do_fsync(fd, 1);
223} 223}
224 224
225/**
226 * generic_write_sync - perform syncing after a write if file / inode is sync
227 * @file: file to which the write happened
228 * @pos: offset where the write started
229 * @count: length of the write
230 *
231 * This is just a simple wrapper about our general syncing function.
232 */
233int generic_write_sync(struct file *file, loff_t pos, loff_t count)
234{
235 if (!(file->f_flags & O_DSYNC) && !IS_SYNC(file->f_mapping->host))
236 return 0;
237 return vfs_fsync_range(file, pos, pos + count - 1,
238 (file->f_flags & __O_SYNC) ? 0 : 1);
239}
240EXPORT_SYMBOL(generic_write_sync);
241
242/* 225/*
243 * sys_sync_file_range() permits finely controlled syncing over a segment of 226 * sys_sync_file_range() permits finely controlled syncing over a segment of
244 * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is 227 * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 2e7989e3a2d6..64b48eade91d 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -799,7 +799,7 @@ xfs_file_aio_write(
799 XFS_STATS_ADD(xs_write_bytes, ret); 799 XFS_STATS_ADD(xs_write_bytes, ret);
800 800
801 /* Handle various SYNC-type writes */ 801 /* Handle various SYNC-type writes */
802 err = generic_write_sync(file, pos, ret); 802 err = generic_write_sync(file, iocb->ki_pos - ret, ret);
803 if (err < 0) 803 if (err < 0)
804 ret = err; 804 ret = err;
805 } 805 }
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d79678c188ad..60829565e552 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2274,7 +2274,13 @@ extern int filemap_fdatawrite_range(struct address_space *mapping,
2274extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end, 2274extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end,
2275 int datasync); 2275 int datasync);
2276extern int vfs_fsync(struct file *file, int datasync); 2276extern int vfs_fsync(struct file *file, int datasync);
2277extern int generic_write_sync(struct file *file, loff_t pos, loff_t count); 2277static inline int generic_write_sync(struct file *file, loff_t pos, loff_t count)
2278{
2279 if (!(file->f_flags & O_DSYNC) && !IS_SYNC(file->f_mapping->host))
2280 return 0;
2281 return vfs_fsync_range(file, pos, pos + count - 1,
2282 (file->f_flags & __O_SYNC) ? 0 : 1);
2283}
2278extern void emergency_sync(void); 2284extern void emergency_sync(void);
2279extern void emergency_remount(void); 2285extern void emergency_remount(void);
2280#ifdef CONFIG_BLOCK 2286#ifdef CONFIG_BLOCK
diff --git a/mm/filemap.c b/mm/filemap.c
index d56d3c145b9f..7a13f6ac5421 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2553,8 +2553,8 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
2553 if (ret > 0) { 2553 if (ret > 0) {
2554 ssize_t err; 2554 ssize_t err;
2555 2555
2556 err = generic_write_sync(file, pos, ret); 2556 err = generic_write_sync(file, iocb->ki_pos - ret, ret);
2557 if (err < 0 && ret > 0) 2557 if (err < 0)
2558 ret = err; 2558 ret = err;
2559 } 2559 }
2560 return ret; 2560 return ret;
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 332ac8a80cf5..2df7b900e259 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -17,6 +17,7 @@
17#include <linux/inet_diag.h> 17#include <linux/inet_diag.h>
18#include <linux/xfrm.h> 18#include <linux/xfrm.h>
19#include <linux/audit.h> 19#include <linux/audit.h>
20#include <linux/sock_diag.h>
20 21
21#include "flask.h" 22#include "flask.h"
22#include "av_permissions.h" 23#include "av_permissions.h"
@@ -78,6 +79,7 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
78{ 79{
79 { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, 80 { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
80 { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, 81 { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
82 { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
81}; 83};
82 84
83static struct nlmsg_perm nlmsg_xfrm_perms[] = 85static struct nlmsg_perm nlmsg_xfrm_perms[] =
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index c93c21127f0c..5d0144ee8ed6 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1232,6 +1232,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
1232 struct context context; 1232 struct context context;
1233 int rc = 0; 1233 int rc = 0;
1234 1234
1235 /* An empty security context is never valid. */
1236 if (!scontext_len)
1237 return -EINVAL;
1238
1235 if (!ss_initialized) { 1239 if (!ss_initialized) {
1236 int i; 1240 int i;
1237 1241
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index cfede86161d8..b22dbb16f877 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -63,11 +63,35 @@ static int build_id_cache__kcore_dir(char *dir, size_t sz)
63 return 0; 63 return 0;
64} 64}
65 65
66static bool same_kallsyms_reloc(const char *from_dir, char *to_dir)
67{
68 char from[PATH_MAX];
69 char to[PATH_MAX];
70 const char *name;
71 u64 addr1 = 0, addr2 = 0;
72 int i;
73
74 scnprintf(from, sizeof(from), "%s/kallsyms", from_dir);
75 scnprintf(to, sizeof(to), "%s/kallsyms", to_dir);
76
77 for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
78 addr1 = kallsyms__get_function_start(from, name);
79 if (addr1)
80 break;
81 }
82
83 if (name)
84 addr2 = kallsyms__get_function_start(to, name);
85
86 return addr1 == addr2;
87}
88
66static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir, 89static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
67 size_t to_dir_sz) 90 size_t to_dir_sz)
68{ 91{
69 char from[PATH_MAX]; 92 char from[PATH_MAX];
70 char to[PATH_MAX]; 93 char to[PATH_MAX];
94 char to_subdir[PATH_MAX];
71 struct dirent *dent; 95 struct dirent *dent;
72 int ret = -1; 96 int ret = -1;
73 DIR *d; 97 DIR *d;
@@ -86,10 +110,11 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
86 continue; 110 continue;
87 scnprintf(to, sizeof(to), "%s/%s/modules", to_dir, 111 scnprintf(to, sizeof(to), "%s/%s/modules", to_dir,
88 dent->d_name); 112 dent->d_name);
89 if (!compare_proc_modules(from, to)) { 113 scnprintf(to_subdir, sizeof(to_subdir), "%s/%s",
90 scnprintf(to, sizeof(to), "%s/%s", to_dir, 114 to_dir, dent->d_name);
91 dent->d_name); 115 if (!compare_proc_modules(from, to) &&
92 strlcpy(to_dir, to, to_dir_sz); 116 same_kallsyms_reloc(from_dir, to_subdir)) {
117 strlcpy(to_dir, to_subdir, to_dir_sz);
93 ret = 0; 118 ret = 0;
94 break; 119 break;
95 } 120 }
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 3c394bf16fa8..af47531b82ec 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -287,10 +287,7 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
287 * have no _text sometimes. 287 * have no _text sometimes.
288 */ 288 */
289 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 289 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
290 machine, "_text"); 290 machine);
291 if (err < 0)
292 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
293 machine, "_stext");
294 if (err < 0) 291 if (err < 0)
295 pr_err("Couldn't record guest kernel [%d]'s reference" 292 pr_err("Couldn't record guest kernel [%d]'s reference"
296 " relocation symbol.\n", machine->pid); 293 " relocation symbol.\n", machine->pid);
@@ -457,10 +454,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
457 } 454 }
458 455
459 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 456 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
460 machine, "_text"); 457 machine);
461 if (err < 0)
462 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
463 machine, "_stext");
464 if (err < 0) 458 if (err < 0)
465 pr_err("Couldn't record kernel reference relocation symbol\n" 459 pr_err("Couldn't record kernel reference relocation symbol\n"
466 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 460 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index 67e5d0cace85..63a0e6f04a01 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -454,7 +454,6 @@ So to start with, in order to add HAVE_PERF_EVENTS to your Kconfig, you
454will need at least this: 454will need at least this:
455 - asm/perf_event.h - a basic stub will suffice at first 455 - asm/perf_event.h - a basic stub will suffice at first
456 - support for atomic64 types (and associated helper functions) 456 - support for atomic64 types (and associated helper functions)
457 - set_perf_event_pending() implemented
458 457
459If your architecture does have hardware capabilities, you can override the 458If your architecture does have hardware capabilities, you can override the
460weak stub hw_perf_event_init() to register hardware counters. 459weak stub hw_perf_event_init() to register hardware counters.
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 7daa806d9050..e84fa26bc1be 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -100,8 +100,8 @@
100 100
101#ifdef __aarch64__ 101#ifdef __aarch64__
102#define mb() asm volatile("dmb ish" ::: "memory") 102#define mb() asm volatile("dmb ish" ::: "memory")
103#define wmb() asm volatile("dmb ishld" ::: "memory") 103#define wmb() asm volatile("dmb ishst" ::: "memory")
104#define rmb() asm volatile("dmb ishst" ::: "memory") 104#define rmb() asm volatile("dmb ishld" ::: "memory")
105#define cpu_relax() asm volatile("yield" ::: "memory") 105#define cpu_relax() asm volatile("yield" ::: "memory")
106#endif 106#endif
107 107
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 2bd13edcbc17..3d9088003a5b 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -26,7 +26,6 @@ int test__vmlinux_matches_kallsyms(void)
26 struct map *kallsyms_map, *vmlinux_map; 26 struct map *kallsyms_map, *vmlinux_map;
27 struct machine kallsyms, vmlinux; 27 struct machine kallsyms, vmlinux;
28 enum map_type type = MAP__FUNCTION; 28 enum map_type type = MAP__FUNCTION;
29 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
30 u64 mem_start, mem_end; 29 u64 mem_start, mem_end;
31 30
32 /* 31 /*
@@ -70,14 +69,6 @@ int test__vmlinux_matches_kallsyms(void)
70 */ 69 */
71 kallsyms_map = machine__kernel_map(&kallsyms, type); 70 kallsyms_map = machine__kernel_map(&kallsyms, type);
72 71
73 sym = map__find_symbol_by_name(kallsyms_map, ref_reloc_sym.name, NULL);
74 if (sym == NULL) {
75 pr_debug("dso__find_symbol_by_name ");
76 goto out;
77 }
78
79 ref_reloc_sym.addr = UM(sym->start);
80
81 /* 72 /*
82 * Step 5: 73 * Step 5:
83 * 74 *
@@ -89,7 +80,6 @@ int test__vmlinux_matches_kallsyms(void)
89 } 80 }
90 81
91 vmlinux_map = machine__kernel_map(&vmlinux, type); 82 vmlinux_map = machine__kernel_map(&vmlinux, type);
92 map__kmap(vmlinux_map)->ref_reloc_sym = &ref_reloc_sym;
93 83
94 /* 84 /*
95 * Step 6: 85 * Step 6:
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 1fc1c2f04772..b0f3ca850e9e 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -470,23 +470,32 @@ static int find_symbol_cb(void *arg, const char *name, char type,
470 return 1; 470 return 1;
471} 471}
472 472
473u64 kallsyms__get_function_start(const char *kallsyms_filename,
474 const char *symbol_name)
475{
476 struct process_symbol_args args = { .name = symbol_name, };
477
478 if (kallsyms__parse(kallsyms_filename, &args, find_symbol_cb) <= 0)
479 return 0;
480
481 return args.start;
482}
483
473int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 484int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
474 perf_event__handler_t process, 485 perf_event__handler_t process,
475 struct machine *machine, 486 struct machine *machine)
476 const char *symbol_name)
477{ 487{
478 size_t size; 488 size_t size;
479 const char *filename, *mmap_name; 489 const char *mmap_name;
480 char path[PATH_MAX];
481 char name_buff[PATH_MAX]; 490 char name_buff[PATH_MAX];
482 struct map *map; 491 struct map *map;
492 struct kmap *kmap;
483 int err; 493 int err;
484 /* 494 /*
485 * We should get this from /sys/kernel/sections/.text, but till that is 495 * We should get this from /sys/kernel/sections/.text, but till that is
486 * available use this, and after it is use this as a fallback for older 496 * available use this, and after it is use this as a fallback for older
487 * kernels. 497 * kernels.
488 */ 498 */
489 struct process_symbol_args args = { .name = symbol_name, };
490 union perf_event *event = zalloc((sizeof(event->mmap) + 499 union perf_event *event = zalloc((sizeof(event->mmap) +
491 machine->id_hdr_size)); 500 machine->id_hdr_size));
492 if (event == NULL) { 501 if (event == NULL) {
@@ -502,30 +511,19 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
502 * see kernel/perf_event.c __perf_event_mmap 511 * see kernel/perf_event.c __perf_event_mmap
503 */ 512 */
504 event->header.misc = PERF_RECORD_MISC_KERNEL; 513 event->header.misc = PERF_RECORD_MISC_KERNEL;
505 filename = "/proc/kallsyms";
506 } else { 514 } else {
507 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 515 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
508 if (machine__is_default_guest(machine))
509 filename = (char *) symbol_conf.default_guest_kallsyms;
510 else {
511 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
512 filename = path;
513 }
514 }
515
516 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) {
517 free(event);
518 return -ENOENT;
519 } 516 }
520 517
521 map = machine->vmlinux_maps[MAP__FUNCTION]; 518 map = machine->vmlinux_maps[MAP__FUNCTION];
519 kmap = map__kmap(map);
522 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 520 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
523 "%s%s", mmap_name, symbol_name) + 1; 521 "%s%s", mmap_name, kmap->ref_reloc_sym->name) + 1;
524 size = PERF_ALIGN(size, sizeof(u64)); 522 size = PERF_ALIGN(size, sizeof(u64));
525 event->mmap.header.type = PERF_RECORD_MMAP; 523 event->mmap.header.type = PERF_RECORD_MMAP;
526 event->mmap.header.size = (sizeof(event->mmap) - 524 event->mmap.header.size = (sizeof(event->mmap) -
527 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 525 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
528 event->mmap.pgoff = args.start; 526 event->mmap.pgoff = kmap->ref_reloc_sym->addr;
529 event->mmap.start = map->start; 527 event->mmap.start = map->start;
530 event->mmap.len = map->end - event->mmap.start; 528 event->mmap.len = map->end - event->mmap.start;
531 event->mmap.pid = machine->pid; 529 event->mmap.pid = machine->pid;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index faf6e219be21..851fa06f4a42 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -214,8 +214,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
214 struct machine *machine, bool mmap_data); 214 struct machine *machine, bool mmap_data);
215int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 215int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
216 perf_event__handler_t process, 216 perf_event__handler_t process,
217 struct machine *machine, 217 struct machine *machine);
218 const char *symbol_name);
219 218
220int perf_event__synthesize_modules(struct perf_tool *tool, 219int perf_event__synthesize_modules(struct perf_tool *tool,
221 perf_event__handler_t process, 220 perf_event__handler_t process,
@@ -279,4 +278,7 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
279size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); 278size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
280size_t perf_event__fprintf(union perf_event *event, FILE *fp); 279size_t perf_event__fprintf(union perf_event *event, FILE *fp);
281 280
281u64 kallsyms__get_function_start(const char *kallsyms_filename,
282 const char *symbol_name);
283
282#endif /* __PERF_RECORD_H */ 284#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/include/asm/hash.h b/tools/perf/util/include/asm/hash.h
new file mode 100644
index 000000000000..d82b170bb216
--- /dev/null
+++ b/tools/perf/util/include/asm/hash.h
@@ -0,0 +1,6 @@
1#ifndef __ASM_GENERIC_HASH_H
2#define __ASM_GENERIC_HASH_H
3
4/* Stub */
5
6#endif /* __ASM_GENERIC_HASH_H */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index ded74590b92f..c872991e0f65 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -496,19 +496,22 @@ static int symbol__in_kernel(void *arg, const char *name,
496 return 1; 496 return 1;
497} 497}
498 498
499static void machine__get_kallsyms_filename(struct machine *machine, char *buf,
500 size_t bufsz)
501{
502 if (machine__is_default_guest(machine))
503 scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms);
504 else
505 scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir);
506}
507
499/* Figure out the start address of kernel map from /proc/kallsyms */ 508/* Figure out the start address of kernel map from /proc/kallsyms */
500static u64 machine__get_kernel_start_addr(struct machine *machine) 509static u64 machine__get_kernel_start_addr(struct machine *machine)
501{ 510{
502 const char *filename; 511 char filename[PATH_MAX];
503 char path[PATH_MAX];
504 struct process_args args; 512 struct process_args args;
505 513
506 if (machine__is_default_guest(machine)) 514 machine__get_kallsyms_filename(machine, filename, PATH_MAX);
507 filename = (char *)symbol_conf.default_guest_kallsyms;
508 else {
509 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
510 filename = path;
511 }
512 515
513 if (symbol__restricted_filename(filename, "/proc/kallsyms")) 516 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
514 return 0; 517 return 0;
@@ -829,9 +832,25 @@ static int machine__create_modules(struct machine *machine)
829 return 0; 832 return 0;
830} 833}
831 834
835const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
836
832int machine__create_kernel_maps(struct machine *machine) 837int machine__create_kernel_maps(struct machine *machine)
833{ 838{
834 struct dso *kernel = machine__get_kernel(machine); 839 struct dso *kernel = machine__get_kernel(machine);
840 char filename[PATH_MAX];
841 const char *name;
842 u64 addr = 0;
843 int i;
844
845 machine__get_kallsyms_filename(machine, filename, PATH_MAX);
846
847 for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
848 addr = kallsyms__get_function_start(filename, name);
849 if (addr)
850 break;
851 }
852 if (!addr)
853 return -1;
835 854
836 if (kernel == NULL || 855 if (kernel == NULL ||
837 __machine__create_kernel_maps(machine, kernel) < 0) 856 __machine__create_kernel_maps(machine, kernel) < 0)
@@ -850,6 +869,13 @@ int machine__create_kernel_maps(struct machine *machine)
850 * Now that we have all the maps created, just set the ->end of them: 869 * Now that we have all the maps created, just set the ->end of them:
851 */ 870 */
852 map_groups__fixup_end(&machine->kmaps); 871 map_groups__fixup_end(&machine->kmaps);
872
873 if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name,
874 addr)) {
875 machine__destroy_kernel_maps(machine);
876 return -1;
877 }
878
853 return 0; 879 return 0;
854} 880}
855 881
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 477133015440..f77e91e483dc 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -18,6 +18,8 @@ union perf_event;
18#define HOST_KERNEL_ID (-1) 18#define HOST_KERNEL_ID (-1)
19#define DEFAULT_GUEST_KERNEL_ID (0) 19#define DEFAULT_GUEST_KERNEL_ID (0)
20 20
21extern const char *ref_reloc_sym_names[];
22
21struct machine { 23struct machine {
22 struct rb_node rb_node; 24 struct rb_node rb_node;
23 pid_t pid; 25 pid_t pid;
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 3b97513f0e77..39cd2d0faff6 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -39,6 +39,7 @@ void map__init(struct map *map, enum map_type type,
39 map->start = start; 39 map->start = start;
40 map->end = end; 40 map->end = end;
41 map->pgoff = pgoff; 41 map->pgoff = pgoff;
42 map->reloc = 0;
42 map->dso = dso; 43 map->dso = dso;
43 map->map_ip = map__map_ip; 44 map->map_ip = map__map_ip;
44 map->unmap_ip = map__unmap_ip; 45 map->unmap_ip = map__unmap_ip;
@@ -288,7 +289,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip)
288 if (map->dso->rel) 289 if (map->dso->rel)
289 return rip - map->pgoff; 290 return rip - map->pgoff;
290 291
291 return map->unmap_ip(map, rip); 292 return map->unmap_ip(map, rip) - map->reloc;
292} 293}
293 294
294/** 295/**
@@ -311,7 +312,7 @@ u64 map__objdump_2mem(struct map *map, u64 ip)
311 if (map->dso->rel) 312 if (map->dso->rel)
312 return map->unmap_ip(map, ip + map->pgoff); 313 return map->unmap_ip(map, ip + map->pgoff);
313 314
314 return ip; 315 return ip + map->reloc;
315} 316}
316 317
317void map_groups__init(struct map_groups *mg) 318void map_groups__init(struct map_groups *mg)
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 18068c6b71c1..257e513205ce 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -36,6 +36,7 @@ struct map {
36 bool erange_warned; 36 bool erange_warned;
37 u32 priv; 37 u32 priv;
38 u64 pgoff; 38 u64 pgoff;
39 u64 reloc;
39 u32 maj, min; /* only valid for MMAP2 record */ 40 u32 maj, min; /* only valid for MMAP2 record */
40 u64 ino; /* only valid for MMAP2 record */ 41 u64 ino; /* only valid for MMAP2 record */
41 u64 ino_generation;/* only valid for MMAP2 record */ 42 u64 ino_generation;/* only valid for MMAP2 record */
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 759456728703..3e9f336740fa 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -751,6 +751,8 @@ int dso__load_sym(struct dso *dso, struct map *map,
751 if (strcmp(elf_name, kmap->ref_reloc_sym->name)) 751 if (strcmp(elf_name, kmap->ref_reloc_sym->name))
752 continue; 752 continue;
753 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 753 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
754 map->reloc = kmap->ref_reloc_sym->addr -
755 kmap->ref_reloc_sym->unrelocated_addr;
754 break; 756 break;
755 } 757 }
756 } 758 }
@@ -922,6 +924,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
922 (u64)shdr.sh_offset); 924 (u64)shdr.sh_offset);
923 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 925 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
924 } 926 }
927new_symbol:
925 /* 928 /*
926 * We need to figure out if the object was created from C++ sources 929 * We need to figure out if the object was created from C++ sources
927 * DWARF DW_compile_unit has this, but we don't always have access 930 * DWARF DW_compile_unit has this, but we don't always have access
@@ -933,7 +936,6 @@ int dso__load_sym(struct dso *dso, struct map *map,
933 if (demangled != NULL) 936 if (demangled != NULL)
934 elf_name = demangled; 937 elf_name = demangled;
935 } 938 }
936new_symbol:
937 f = symbol__new(sym.st_value, sym.st_size, 939 f = symbol__new(sym.st_value, sym.st_size,
938 GELF_ST_BIND(sym.st_info), elf_name); 940 GELF_ST_BIND(sym.st_info), elf_name);
939 free(demangled); 941 free(demangled);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 39ce9adbaaf0..a9d758a3b371 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -627,7 +627,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
627 * kernel range is broken in several maps, named [kernel].N, as we don't have 627 * kernel range is broken in several maps, named [kernel].N, as we don't have
628 * the original ELF section names vmlinux have. 628 * the original ELF section names vmlinux have.
629 */ 629 */
630static int dso__split_kallsyms(struct dso *dso, struct map *map, 630static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
631 symbol_filter_t filter) 631 symbol_filter_t filter)
632{ 632{
633 struct map_groups *kmaps = map__kmap(map)->kmaps; 633 struct map_groups *kmaps = map__kmap(map)->kmaps;
@@ -692,6 +692,12 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map,
692 char dso_name[PATH_MAX]; 692 char dso_name[PATH_MAX];
693 struct dso *ndso; 693 struct dso *ndso;
694 694
695 if (delta) {
696 /* Kernel was relocated at boot time */
697 pos->start -= delta;
698 pos->end -= delta;
699 }
700
695 if (count == 0) { 701 if (count == 0) {
696 curr_map = map; 702 curr_map = map;
697 goto filter_symbol; 703 goto filter_symbol;
@@ -721,6 +727,10 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map,
721 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 727 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
722 map_groups__insert(kmaps, curr_map); 728 map_groups__insert(kmaps, curr_map);
723 ++kernel_range; 729 ++kernel_range;
730 } else if (delta) {
731 /* Kernel was relocated at boot time */
732 pos->start -= delta;
733 pos->end -= delta;
724 } 734 }
725filter_symbol: 735filter_symbol:
726 if (filter && filter(curr_map, pos)) { 736 if (filter && filter(curr_map, pos)) {
@@ -976,6 +986,23 @@ static int validate_kcore_modules(const char *kallsyms_filename,
976 return 0; 986 return 0;
977} 987}
978 988
989static int validate_kcore_addresses(const char *kallsyms_filename,
990 struct map *map)
991{
992 struct kmap *kmap = map__kmap(map);
993
994 if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
995 u64 start;
996
997 start = kallsyms__get_function_start(kallsyms_filename,
998 kmap->ref_reloc_sym->name);
999 if (start != kmap->ref_reloc_sym->addr)
1000 return -EINVAL;
1001 }
1002
1003 return validate_kcore_modules(kallsyms_filename, map);
1004}
1005
979struct kcore_mapfn_data { 1006struct kcore_mapfn_data {
980 struct dso *dso; 1007 struct dso *dso;
981 enum map_type type; 1008 enum map_type type;
@@ -1019,8 +1046,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
1019 kallsyms_filename)) 1046 kallsyms_filename))
1020 return -EINVAL; 1047 return -EINVAL;
1021 1048
1022 /* All modules must be present at their original addresses */ 1049 /* Modules and kernel must be present at their original addresses */
1023 if (validate_kcore_modules(kallsyms_filename, map)) 1050 if (validate_kcore_addresses(kallsyms_filename, map))
1024 return -EINVAL; 1051 return -EINVAL;
1025 1052
1026 md.dso = dso; 1053 md.dso = dso;
@@ -1113,15 +1140,41 @@ out_err:
1113 return -EINVAL; 1140 return -EINVAL;
1114} 1141}
1115 1142
1143/*
1144 * If the kernel is relocated at boot time, kallsyms won't match. Compute the
1145 * delta based on the relocation reference symbol.
1146 */
1147static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
1148{
1149 struct kmap *kmap = map__kmap(map);
1150 u64 addr;
1151
1152 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
1153 return 0;
1154
1155 addr = kallsyms__get_function_start(filename,
1156 kmap->ref_reloc_sym->name);
1157 if (!addr)
1158 return -1;
1159
1160 *delta = addr - kmap->ref_reloc_sym->addr;
1161 return 0;
1162}
1163
1116int dso__load_kallsyms(struct dso *dso, const char *filename, 1164int dso__load_kallsyms(struct dso *dso, const char *filename,
1117 struct map *map, symbol_filter_t filter) 1165 struct map *map, symbol_filter_t filter)
1118{ 1166{
1167 u64 delta = 0;
1168
1119 if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1169 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1120 return -1; 1170 return -1;
1121 1171
1122 if (dso__load_all_kallsyms(dso, filename, map) < 0) 1172 if (dso__load_all_kallsyms(dso, filename, map) < 0)
1123 return -1; 1173 return -1;
1124 1174
1175 if (kallsyms__delta(map, filename, &delta))
1176 return -1;
1177
1125 symbols__fixup_duplicate(&dso->symbols[map->type]); 1178 symbols__fixup_duplicate(&dso->symbols[map->type]);
1126 symbols__fixup_end(&dso->symbols[map->type]); 1179 symbols__fixup_end(&dso->symbols[map->type]);
1127 1180
@@ -1133,7 +1186,7 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
1133 if (!dso__load_kcore(dso, map, filename)) 1186 if (!dso__load_kcore(dso, map, filename))
1134 return dso__split_kallsyms_for_kcore(dso, map, filter); 1187 return dso__split_kallsyms_for_kcore(dso, map, filter);
1135 else 1188 else
1136 return dso__split_kallsyms(dso, map, filter); 1189 return dso__split_kallsyms(dso, map, delta, filter);
1137} 1190}
1138 1191
1139static int dso__load_perf_map(struct dso *dso, struct map *map, 1192static int dso__load_perf_map(struct dso *dso, struct map *map,
@@ -1424,7 +1477,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
1424 continue; 1477 continue;
1425 scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 1478 scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
1426 "%s/%s/kallsyms", dir, dent->d_name); 1479 "%s/%s/kallsyms", dir, dent->d_name);
1427 if (!validate_kcore_modules(kallsyms_filename, map)) { 1480 if (!validate_kcore_addresses(kallsyms_filename, map)) {
1428 strlcpy(dir, kallsyms_filename, dir_sz); 1481 strlcpy(dir, kallsyms_filename, dir_sz);
1429 ret = 0; 1482 ret = 0;
1430 break; 1483 break;
@@ -1479,7 +1532,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1479 if (fd != -1) { 1532 if (fd != -1) {
1480 close(fd); 1533 close(fd);
1481 /* If module maps match go with /proc/kallsyms */ 1534 /* If module maps match go with /proc/kallsyms */
1482 if (!validate_kcore_modules("/proc/kallsyms", map)) 1535 if (!validate_kcore_addresses("/proc/kallsyms", map))
1483 goto proc_kallsyms; 1536 goto proc_kallsyms;
1484 } 1537 }
1485 1538