perf tools and x86 PTI entry trampolines
Subsystems (4)
v4 cover perf tools and x86 PTI entry trampolines
Hi
Here is V4 of patches to support x86 PTI entry trampolines in perf tools.
Patches also here:
http://git.infradead.org/users/ahunter/linux-perf.git/shortlog/refs/heads/perf-tools-kpti-v4
git://git.infradead.org/users/ahunter/linux-perf.git perf-tools-kpti-v4
V3 patches also here:
http://git.infradead.org/users/ahunter/linux-perf.git/shortlog/refs/heads/perf-tools-kpti-v3
git://git.infradead.org/users/ahunter/linux-perf.git perf-tools-kpti-v3
V2 patches also here:
http://git.infradead.org/users/ahunter/linux-perf.git/shortlog/refs/heads/perf-tools-kpti-v2
git://git.infradead.org/users/ahunter/linux-perf.git perf-tools-kpti-v2
V1 patches also here:
http://git.infradead.org/users/ahunter/linux-perf.git/shortlog/refs/heads/perf-tools-kpti-v1
git://git.infradead.org/users/ahunter/linux-perf.git perf-tools-kpti-v1
Changes Since V3:
kallsyms: Simplify update_iter_mod()
Added comment
Added Andi's Ack
kallsyms, x86: Export addresses of PTI entry trampolines
Expanded commit message
Used for_each_possible_cpu()
Added Andi's Ack even though logic changed slightly
x86: Add entry trampolines to kcore
Re-based
Added Andi's Ack
perf tools: Add machine__nr_cpus_avail()
perf tools: Workaround missing maps for x86 PTI entry trampolines perf tools: Fix map_groups__split_kallsyms() for entry trampoline symbols perf tools: Allow for extra kernel maps
perf tools: Create maps for x86 PTI entry trampolines
perf tools: Synthesize and process mmap events for x86 PTI entry trampolines perf buildid-cache: kcore_copy: Keep phdr data in a list
perf buildid-cache: kcore_copy: Keep a count of phdrs
perf buildid-cache: kcore_copy: Calculate offset from phnum
perf buildid-cache: kcore_copy: Layout sections
perf buildid-cache: kcore_copy: Iterate phdrs
perf buildid-cache: kcore_copy: Get rid of kernel_map
perf buildid-cache: kcore_copy: Copy x86 PTI entry trampoline sections perf buildid-cache: kcore_copy: Amend the offset of sections that remap kernel text
Dropped because they have been applied
Changes Since V2:
x86: Add entry trampolines to kcore
x86: kcore: Give entry trampolines all the same offset in kcore
Combined into a single patch
Added comment
Expand commit message
perf tools: Add machine__is() to identify machine arch
Dropped because it has been applied
perf tools: Fix kernel_start for PTI on x86
Dropped because it has been applied
Changes Since V1:
perf tools: Use the _stest symbol to identify the kernel map when loading kcore
Dropped because it has been applied
perf tools: Add machine__is() to identify machine arch
New patch
perf tools: Fix kernel_start for PTI on x86
Moved definition of machine__is() to a separate patch
perf tools: Add machine__nr_cpus_avail()
New patch
perf tools: Workaround missing maps for x86 PTI entry trampolines
Use machine__nr_cpus_avail()
perf tools: Create maps for x86 PTI entry trampolines
Re-based
Changes Since RFC:
Change description 'x86_64 KPTI' to 'x86 PTI'
Rename 'special' kernel map to 'extra' kernel map etc
kallsyms: Simplify update_iter_mod()
Expand commit message
perf tools: Fix kernel_start for PTI on x86
Amend machine__is() to check if machine is NULL
perf tools: Workaround missing maps for x86 PTI entry trampolines
Simplify find_entry_trampoline()
Add comment before struct extra_kernel_map /* Kernel-space maps for symbols that are outside the main kernel map and module maps */
perf tools: Create maps for x86 PTI entry trampolines
Move code presently only used by x86_64 into arch
perf tools: Synthesize and process mmap events for x86 PTI entry trampolines
Fix spelling 'kernal' -> 'kernel'
Rename 'special' kernel map to 'extra' kernel map etc Move code presently only used by x86_64 into arch
perf buildid-cache: kcore_copy: Keep phdr data in a list
Expand commit message
Rename 'list' -> 'node'
perf buildid-cache: kcore_copy: Get rid of kernel_map
Expand commit message
Add phdr_data__new()
Rename 'kcore_copy__new_phdr' -> 'kcore_copy_info__addnew'
Original Cover email:
Perf tools do not know about x86 PTI entry trampolines - see example below. These patches add a workaround, namely "perf tools: Workaround missing maps for x86 PTI entry trampolines", which has the limitation that it hard codes the addresses. Note that the workaround will work for old kernels and old perf.data files, but not for future kernels if the trampoline addresses are ever changed.
At present, perf tools uses /proc/kallsyms to construct a memory map for the kernel. Recording such a map in the perf.data file is necessary to deal with kernel relocation and KASLR.
While it is reasonable on its own terms, to add symbols for the trampolines to /proc/kallsyms, the motivation here is to have perf tools use them to create memory maps in the same fashion as is done for the kernel text.
So the first 2 patches add symbols to /proc/kallsyms for the trampolines:
kallsyms: Simplify update_iter_mod() kallsyms, x86: Export addresses of syscall trampolines
perf tools have the ability to use /proc/kcore (in conjunction with /proc/kallsyms) as the kernel image. So the next 2 patches add program headers for the trampolines to the kcore ELF:
x86: Add entry trampolines to kcore
x86: kcore: Give entry trampolines all the same offset in kcore
It is worth noting that, with the kcore changes alone, perf tools require no changes to recognise the trampolines when using /proc/kcore.
Similarly, if perf tools are used with a matching kallsyms only (by denying access to /proc/kcore or a vmlinux image), then the kallsyms patches are sufficient to recognise the trampolines with no changes needed to the tools.
However, in the general case, when using vmlinux or dealing with relocations, perf tools needs memory maps for the trampolines. Because the kernel text map is constructed as a special case, using the same approach for the trampolines means treating them as a special case also, which requires a number of changes to perf tools, and the remaining patches deal with that.
Example: make a program that does lots of small syscalls e.g.
$ cat uname_x_n.c
#include <sys/utsname.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
long n = argc > 1 ? strtol(argv[1], NULL, 0) : 0;
struct utsname u;
while (n--)
uname(&u);
return 0;
}and then:
sudo perf record uname_x_n 100000 sudo perf report --stdio
Before the changes, there are unknown symbols:
# Overhead Command Shared Object Symbol
# ........ ......... ................ ..................................
#
41.91% uname_x_n [kernel.vmlinux] [k] syscall_return_via_sysret
19.22% uname_x_n [kernel.vmlinux] [k] copy_user_enhanced_fast_string
18.70% uname_x_n [unknown] [k] 0xfffffe00000e201b
4.09% uname_x_n libc-2.19.so [.] __GI___uname
3.08% uname_x_n [kernel.vmlinux] [k] do_syscall_64
3.02% uname_x_n [unknown] [k] 0xfffffe00000e2025
2.32% uname_x_n [kernel.vmlinux] [k] down_read
2.27% uname_x_n ld-2.19.so [.] _dl_start
1.97% uname_x_n [unknown] [k] 0xfffffe00000e201e
1.25% uname_x_n [kernel.vmlinux] [k] up_read
1.02% uname_x_n [unknown] [k] 0xfffffe00000e200c
0.99% uname_x_n [kernel.vmlinux] [k] entry_SYSCALL_64
0.16% uname_x_n [kernel.vmlinux] [k] flush_signal_handlers
0.01% perf [kernel.vmlinux] [k] native_sched_clock
0.00% perf [kernel.vmlinux] [k] native_write_msrAfter the changes there are not:
# Overhead Command Shared Object Symbol
# ........ ......... ................ ..................................
#
41.91% uname_x_n [kernel.vmlinux] [k] syscall_return_via_sysret
24.70% uname_x_n [kernel.vmlinux] [k] entry_SYSCALL_64_trampoline
19.22% uname_x_n [kernel.vmlinux] [k] copy_user_enhanced_fast_string
4.09% uname_x_n libc-2.19.so [.] __GI___uname
3.08% uname_x_n [kernel.vmlinux] [k] do_syscall_64
2.32% uname_x_n [kernel.vmlinux] [k] down_read
2.27% uname_x_n ld-2.19.so [.] _dl_start
1.25% uname_x_n [kernel.vmlinux] [k] up_read
0.99% uname_x_n [kernel.vmlinux] [k] entry_SYSCALL_64
0.16% uname_x_n [kernel.vmlinux] [k] flush_signal_handlers
0.01% perf [kernel.vmlinux] [k] native_sched_clock
0.00% perf [kernel.vmlinux] [k] native_write_msrAdrian Hunter (2):
kallsyms: Simplify update_iter_mod()
x86: Add entry trampolines to kcore
Alexander Shishkin (1):
kallsyms, x86: Export addresses of PTI entry trampolines
arch/x86/mm/cpu_entry_area.c | 33 ++++++++++++++++++++++++++++ fs/proc/kcore.c | 7 ++++-- include/linux/kcore.h | 13 +++++++++++ kernel/kallsyms.c | 51 ++++++++++++++++++++++++++++++++------------ 4 files changed, 88 insertions(+), 16 deletions(-)
Regards
Adrian
PATCH v4 1/3 kallsyms: Simplify update_iter_mod()
The logic in update_iter_mod() is overcomplicated and gets worse every time another get_ksymbol_* function is added.
In preparation for adding another get_ksymbol_* function, simplify logic in update_iter_mod().
--- kernel/kallsyms.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-)
kernel/kallsyms.c +11 -14
@@ -506,27 +506,24 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) } } +/* +* The end position (last + 1) of each additional kallsyms section is recorded +* in iter->pos_..._end as each section is added, and so can be used to +* determine which get_ksymbol_...() function to call next. +*/ static int update_iter_mod (struct kallsym_iter *iter,loff_t pos) { iter->pos = pos; -if (iter->pos_ftrace_mod_end >0 && - iter->pos_ftrace_mod_end < iter->pos) -return get_ksymbol_bpf (iter); - -if (iter->pos_mod_end >0 && - iter->pos_mod_end < iter->pos) { -if (!get_ksymbol_ftrace_mod (iter)) -return get_ksymbol_bpf (iter); +if ((!iter->pos_mod_end || iter->pos_mod_end > pos) && +get_ksymbol_mod (iter))return 1 ; - } -if (!get_ksymbol_mod (iter)) { -if (!get_ksymbol_ftrace_mod (iter)) -return get_ksymbol_bpf (iter); - } +if ((!iter->pos_ftrace_mod_end || iter->pos_ftrace_mod_end > pos) && +get_ksymbol_ftrace_mod (iter)) +return 1 ; -return 1 ; +return get_ksymbol_bpf (iter); }/* Returns false if pos at or past end of file. */
Signature · 1 line
1.9.1
Re: [PATCH V4 1/3] kallsyms: Simplify update_iter_mod()
Quoted 8 lines · Adrian Hunter
The logic in
update_iter_mod()is overcomplicated and gets worse every time another get_ksymbol_* function is added.In preparation for adding another get_ksymbol_* function, simplify logic in
update_iter_mod().Signed-off-by Adrian Hunter <[email protected]>Acked-by Andi Kleen <[email protected]>
Both Daniel and Steven touched this function last year, let's also Cc them.
Quoted 50 lines
--- kernel/kallsyms.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-)kernel/kallsyms.c +11
-14@@ -506,27 +506,24 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) } } +/* +* The end position (last + 1) of each additional kallsyms section is recorded +* in iter->pos_..._end as each section is added, and so can be used to +* determine which get_ksymbol_...() function to call next. +*/ static int update_iter_mod (struct kallsym_iter *iter,loff_t pos) { iter->pos = pos; -if (iter->pos_ftrace_mod_end >0 && - iter->pos_ftrace_mod_end < iter->pos) -return get_ksymbol_bpf (iter); - -if (iter->pos_mod_end >0 && - iter->pos_mod_end < iter->pos) { -if (!get_ksymbol_ftrace_mod (iter)) -return get_ksymbol_bpf (iter); +if ((!iter->pos_mod_end || iter->pos_mod_end > pos) && +get_ksymbol_mod (iter))return 1 ; - } -if (!get_ksymbol_mod (iter)) { -if (!get_ksymbol_ftrace_mod (iter)) -return get_ksymbol_bpf (iter); - } +if ((!iter->pos_ftrace_mod_end || iter->pos_ftrace_mod_end > pos) && +get_ksymbol_ftrace_mod (iter)) +return 1 ; -return 1 ; +return get_ksymbol_bpf (iter); }/* Returns false if pos at or past end of file. */ Signature · 1 line
1.9.1
Steven Rostedt
Acked-byRe: [PATCH V4 1/3] kallsyms: Simplify update_iter_mod()
Quoted 4 lines · On Wed, 6 Jun 2018 15:13:02 +0200 Peter Zijlstra <[email protected]> wrote:
Quoted 3 lines · Adrian Hunter
The logic in
update_iter_mod()is overcomplicated and gets worse every time another get_ksymbol_* function is added.
Quoted 8 lines
Quoted 5 lines
In preparation for adding another get_ksymbol_* function, simplify logic in
update_iter_mod().Signed-off-by Adrian Hunter <[email protected]>Acked-by Andi Kleen <[email protected]>Both Daniel and Steven touched this function last year, let's also Cc them.
Thanks for Ccing me. I tested the patch to make sure my changes still work and they do:
-- Steve
Quoted 2 lines
Re: [PATCH V4 1/3] kallsyms: Simplify update_iter_mod()
Em Wed, Jun 06, 2018 at 02:37:27PM -0400, Steven Rostedt escreveu:
Quoted 13 lines
Quoted 10 lines · On Wed, 6 Jun 2018 15:13:02 +0200 Peter Zijlstra <[email protected]> wrote:
Quoted 8 lines · Adrian Hunter
The logic in
update_iter_mod()is overcomplicated and gets worse every time another get_ksymbol_* function is added.In preparation for adding another get_ksymbol_* function, simplify logic in
update_iter_mod().Signed-off-by Adrian Hunter <[email protected]>Acked-by Andi Kleen <[email protected]>
Quoted 7 lines
Quoted 2 lines
Both Daniel and Steven touched this function last year, let's also Cc them.
Thanks for Ccing me. I tested the patch to make sure my changes still work and they do:
Since you said you tested the patch, may I replace the Acked-by with the stronger Tested-by?
Thanks,
- Arnaldo
Steven Rostedt
Tested-byRe: [PATCH V4 1/3] kallsyms: Simplify update_iter_mod()
Quoted 17 lines · On Wed, 6 Jun 2018 15:59:14 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Wed, Jun 06, 2018 at 02:37:27PM -0400, Steven Rostedt escreveu:
Quoted 16 lines
Quoted 12 lines · On Wed, 6 Jun 2018 15:13:02 +0200 Peter Zijlstra <[email protected]> wrote:
Quoted 8 lines · Adrian Hunter
The logic in
update_iter_mod()is overcomplicated and gets worse every time another get_ksymbol_* function is added.In preparation for adding another get_ksymbol_* function, simplify logic in
update_iter_mod().Signed-off-by Adrian Hunter <[email protected]>Acked-by Andi Kleen <[email protected]>Both Daniel and Steven touched this function last year, let's also Cc them.
Quoted 7 lines
Quoted 4 lines
Thanks for Ccing me. I tested the patch to make sure my changes still work and they do:
Since you said you tested the patch, may I replace the Acked-by with the stronger Tested-by?
Well, I only tested it against the changes I made earlier. I didn't do any other testing, which is why I'm reluctant to say "tested by".
Perhaps it can be:
-- Steve
Re: [PATCH V4 1/3] kallsyms: Simplify update_iter_mod()
Em Wed, Jun 06, 2018 at 03:13:00PM -0400, Steven Rostedt escreveu:
Quoted 28 lines
Quoted 17 lines · On Wed, 6 Jun 2018 15:59:14 -0300 Arnaldo Carvalho de Melo <[email protected]>…
Em Wed, Jun 06, 2018 at 02:37:27PM -0400, Steven Rostedt escreveu:
Quoted 16 lines
Quoted 12 lines · On Wed, 6 Jun 2018 15:13:02 +0200 Peter Zijlstra <[email protected]> wrote:
Quoted 8 lines · Adrian Hunter
The logic in
update_iter_mod()is overcomplicated and gets worse every time another get_ksymbol_* function is added.In preparation for adding another get_ksymbol_* function, simplify logic in
update_iter_mod().Signed-off-by Adrian Hunter <[email protected]>Acked-by Andi Kleen <[email protected]>Both Daniel and Steven touched this function last year, let's also Cc them.
Quoted 7 lines
Quoted 4 lines
Thanks for Ccing me. I tested the patch to make sure my changes still work and they do:
Since you said you tested the patch, may I replace the Acked-by with the stronger Tested-by?
Quoted 6 lines
Well, I only tested it against the changes I made earlier. I didn't do any other testing, which is why I'm reluctant to say "tested by".
Perhaps it can be:
I think that brings more useful information to the log, so should be useful.
- Arnaldo
tip-bot for Adrian Hunter
merge bot[tip:perf/urgent] kallsyms: Simplify update_iter_mod()
In reply to Adrian Hunterkallsyms: Simplify update_iter_mod()
Commit-ID: b96679422007c3fa04625be14977904c27c722eb Gitweb: https://git.kernel.org/tip/b96679422007c3fa04625be14977904c27c722eb Author: Adrian Hunter <[email protected]> AuthorDate: Wed, 6 Jun 2018 15:54:09 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 14 Aug 2018 19:10:23 -0300
kallsyms: Simplify update_iter_mod()
The logic in update_iter_mod() is overcomplicated and gets worse every time another get_ksymbol_* function is added.
In preparation for adding another get_ksymbol_* function, simplify logic in update_iter_mod().
--- kernel/kallsyms.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-)
kernel/kallsyms.c +11 -14
@@ -506,27 +506,24 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) } } +/* +* The end position (last + 1) of each additional kallsyms section is recorded +* in iter->pos_..._end as each section is added, and so can be used to +* determine which get_ksymbol_...() function to call next. +*/ static int update_iter_mod (struct kallsym_iter *iter,loff_t pos) { iter->pos = pos; -if (iter->pos_ftrace_mod_end >0 && - iter->pos_ftrace_mod_end < iter->pos) -return get_ksymbol_bpf (iter); - -if (iter->pos_mod_end >0 && - iter->pos_mod_end < iter->pos) { -if (!get_ksymbol_ftrace_mod (iter)) -return get_ksymbol_bpf (iter); +if ((!iter->pos_mod_end || iter->pos_mod_end > pos) && +get_ksymbol_mod (iter))return 1 ; - } -if (!get_ksymbol_mod (iter)) { -if (!get_ksymbol_ftrace_mod (iter)) -return get_ksymbol_bpf (iter); - } +if ((!iter->pos_ftrace_mod_end || iter->pos_ftrace_mod_end > pos) && +get_ksymbol_ftrace_mod (iter)) +return 1 ; -return 1 ; +return get_ksymbol_bpf (iter); }/* Returns false if pos at or past end of file. */
PATCH v4 2/3 kallsyms, x86: Export addresses of PTI entry trampolines
In reply to Adrian HunterFrom: Alexander Shishkin <[email protected]>
Currently, the addresses of PTI entry trampolines are not exported to user space. Kernel profiling tools need these addresses to identify the kernel code, so add a symbol and address for each CPU's PTI entry trampoline.
--- arch/x86/mm/cpu_entry_area.c | 23 +++++++++++++++++++++++ kernel/kallsyms.c | 28 +++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-)
arch/x86/mm/cpu_entry_area.c +23 -0
@@ -2,6 +2,7 @@#include <linux/spinlock.h> #include <linux/percpu.h> +#include <linux/kallsyms.h> #include <asm/cpu_entry_area.h> #include <asm/pgtable.h>
@@ -150,6 +151,28 @@ static void __init setup_cpu_entry_area(int cpu)percpu_setup_debug_store (cpu); } +#ifdef CONFIG_X86_64 +int arch_get_kallsym (unsigned int symnum,unsigned long *value,char *type, +char *name) +{ +unsigned int cpu, ncpu =0 ; + +if (symnum >=num_possible_cpus ()) +return -EINVAL ; + +for_each_possible_cpu (cpu) { +if (ncpu++ >= symnum) +break ; + } + + *value = (unsigned long )&get_cpu_entry_area (cpu)->entry_trampoline; + *type ='t' ; +strlcpy (name,"__entry_SYSCALL_64_trampoline" ,KSYM_NAME_LEN ); + +return 0 ; +} +#endif +static __init void setup_cpu_entry_area_ptes (void ) {#ifdef CONFIG_X86_32
kernel/kallsyms.c +27 -1
@@ -432,6 +432,7 @@ int sprint_backtrace(char *buffer, unsigned long address)/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ struct kallsym_iter {loff_t pos; +loff_t pos_arch_end;loff_t pos_mod_end;loff_t pos_ftrace_mod_end;unsigned long value;
@@ -443,9 +444,29 @@ struct kallsym_iter {int show_value; }; +int __weak arch_get_kallsym (unsigned int symnum,unsigned long *value, +char *type,char *name) +{ +return -EINVAL ; +} + +static int get_ksymbol_arch (struct kallsym_iter *iter) +{ +int ret =arch_get_kallsym (iter->pos - kallsyms_num_syms, + &iter->value, &iter->type, + iter->name); + +if (ret <0 ) { + iter->pos_arch_end = iter->pos; +return 0 ; + } + +return 1 ; +} +static int get_ksymbol_mod (struct kallsym_iter *iter) { -int ret =module_get_kallsym (iter->pos - kallsyms_num_syms, +int ret =module_get_kallsym (iter->pos - iter->pos_arch_end, &iter->value, &iter->type, iter->name, iter->module_name, &iter->exported);
@@ -501,6 +522,7 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) iter->nameoff =get_symbol_offset (new_pos); iter->pos = new_pos;if (new_pos ==0 ) { + iter->pos_arch_end =0 ; iter->pos_mod_end =0 ; iter->pos_ftrace_mod_end =0 ; }
@@ -515,6 +537,10 @@ static int update_iter_mod(struct kallsym_iter *iter, loff_t pos) { iter->pos = pos; +if ((!iter->pos_arch_end || iter->pos_arch_end > pos) && +get_ksymbol_arch (iter)) +return 1 ; +if ((!iter->pos_mod_end || iter->pos_mod_end > pos) &&get_ksymbol_mod (iter))return 1 ;
Signature · 1 line
1.9.1
Re: [PATCH V4 2/3] kallsyms, x86: Export addresses of PTI entry trampolines
Quoted 8 lines · Adrian Hunter
From: Alexander Shishkin <[email protected]>
Currently, the addresses of PTI entry trampolines are not exported to user space. Kernel profiling tools need these addresses to identify the kernel code, so add a symbol and address for each CPU's PTI entry trampoline.
Signed-off-by Alexander Shishkin <[email protected]>Acked-by Andi Kleen <[email protected]>
Thanks for the Changelog,
tip-bot for Alexander Shishkin
merge bot[tip:perf/urgent] kallsyms, x86: Export addresses of PTI entry trampolines
In reply to Adrian Hunterkallsyms, x86: Export addresses of PTI entry trampolines
Commit-ID: d83212d5dd6761625fe87cc23016bbaa47303271 Gitweb: https://git.kernel.org/tip/d83212d5dd6761625fe87cc23016bbaa47303271 Author: Alexander Shishkin <[email protected]> AuthorDate: Wed, 6 Jun 2018 15:54:10 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 14 Aug 2018 19:12:29 -0300
kallsyms, x86: Export addresses of PTI entry trampolines
Currently, the addresses of PTI entry trampolines are not exported to user space. Kernel profiling tools need these addresses to identify the kernel code, so add a symbol and address for each CPU's PTI entry trampoline.
--- arch/x86/mm/cpu_entry_area.c | 23 +++++++++++++++++++++++ kernel/kallsyms.c | 28 +++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-)
arch/x86/mm/cpu_entry_area.c +23 -0
@@ -2,6 +2,7 @@#include <linux/spinlock.h> #include <linux/percpu.h> +#include <linux/kallsyms.h> #include <asm/cpu_entry_area.h> #include <asm/pgtable.h>
@@ -150,6 +151,28 @@ static void __init setup_cpu_entry_area(int cpu)percpu_setup_debug_store (cpu); } +#ifdef CONFIG_X86_64 +int arch_get_kallsym (unsigned int symnum,unsigned long *value,char *type, +char *name) +{ +unsigned int cpu, ncpu =0 ; + +if (symnum >=num_possible_cpus ()) +return -EINVAL ; + +for_each_possible_cpu (cpu) { +if (ncpu++ >= symnum) +break ; + } + + *value = (unsigned long )&get_cpu_entry_area (cpu)->entry_trampoline; + *type ='t' ; +strlcpy (name,"__entry_SYSCALL_64_trampoline" ,KSYM_NAME_LEN ); + +return 0 ; +} +#endif +static __init void setup_cpu_entry_area_ptes (void ) {#ifdef CONFIG_X86_32
kernel/kallsyms.c +27 -1
@@ -432,6 +432,7 @@ int sprint_backtrace(char *buffer, unsigned long address)/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ struct kallsym_iter {loff_t pos; +loff_t pos_arch_end;loff_t pos_mod_end;loff_t pos_ftrace_mod_end;unsigned long value;
@@ -443,9 +444,29 @@ struct kallsym_iter {int show_value; }; +int __weak arch_get_kallsym (unsigned int symnum,unsigned long *value, +char *type,char *name) +{ +return -EINVAL ; +} + +static int get_ksymbol_arch (struct kallsym_iter *iter) +{ +int ret =arch_get_kallsym (iter->pos - kallsyms_num_syms, + &iter->value, &iter->type, + iter->name); + +if (ret <0 ) { + iter->pos_arch_end = iter->pos; +return 0 ; + } + +return 1 ; +} +static int get_ksymbol_mod (struct kallsym_iter *iter) { -int ret =module_get_kallsym (iter->pos - kallsyms_num_syms, +int ret =module_get_kallsym (iter->pos - iter->pos_arch_end, &iter->value, &iter->type, iter->name, iter->module_name, &iter->exported);
@@ -501,6 +522,7 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) iter->nameoff =get_symbol_offset (new_pos); iter->pos = new_pos;if (new_pos ==0 ) { + iter->pos_arch_end =0 ; iter->pos_mod_end =0 ; iter->pos_ftrace_mod_end =0 ; }
@@ -515,6 +537,10 @@ static int update_iter_mod(struct kallsym_iter *iter, loff_t pos) { iter->pos = pos; +if ((!iter->pos_arch_end || iter->pos_arch_end > pos) && +get_ksymbol_arch (iter)) +return 1 ; +if ((!iter->pos_mod_end || iter->pos_mod_end > pos) &&get_ksymbol_mod (iter))return 1 ;
PATCH v4 3/3 x86: Add entry trampolines to kcore
In reply to Adrian HunterWithout program headers for PTI entry trampoline pages, the trampoline virtual addresses do not map to anything.
Example before:
sudo gdb --quiet vmlinux /proc/kcore
Reading symbols from vmlinux...done.
[New process 1]
Core was generated by `BOOT_IMAGE=/boot/vmlinuz-4.16.0 root=UUID=a6096b83-b763-4101-807e-f33daff63233'. #0 0x0000000000000000 in irq_stack_union ()
(gdb) x /21ib 0xfffffe0000006000
0xfffffe0000006000: Cannot access memory at address 0xfffffe0000006000
(gdb) quit
After:
sudo gdb --quiet vmlinux /proc/kcore
[sudo] password for ahunter:
Reading symbols from vmlinux...done.
[New process 1]
Core was generated by `BOOT_IMAGE=/boot/vmlinuz-4.16.0-fix-4-00005-gd6e65a8b4072 root=UUID=a6096b83-b7'. #0 0x0000000000000000 in irq_stack_union ()
(gdb) x /21ib 0xfffffe0000006000
0xfffffe0000006000: swapgs
0xfffffe0000006003: mov %rsp,-0x3e12(%rip) # 0xfffffe00000021f8
0xfffffe000000600a: xchg %ax,%ax
0xfffffe000000600c: mov %cr3,%rsp
0xfffffe000000600f: bts $0x3f,%rsp
0xfffffe0000006014: and $0xffffffffffffe7ff,%rsp
0xfffffe000000601b: mov %rsp,%cr3
0xfffffe000000601e: mov -0x3019(%rip),%rsp # 0xfffffe000000300c
0xfffffe0000006025: pushq $0x2b
0xfffffe0000006027: pushq -0x3e35(%rip) # 0xfffffe00000021f8
0xfffffe000000602d: push %r11
0xfffffe000000602f: pushq $0x33
0xfffffe0000006031: push %rcx
0xfffffe0000006032: push %rdi
0xfffffe0000006033: mov $0xffffffff91a00010,%rdi
0xfffffe000000603a: callq 0xfffffe0000006046
0xfffffe000000603f: pause
0xfffffe0000006041: lfence
0xfffffe0000006044: jmp 0xfffffe000000603f
0xfffffe0000006046: mov %rdi,(%rsp)
0xfffffe000000604a: retq(gdb) quit
In addition, entry trampolines all map to the same page. Represent that by giving the corresponding program headers in kcore the same offset.
This has the benefit that, when perf tools uses /proc/kcore as a source for kernel object code, samples from different CPU trampolines are aggregated together. Note, such aggregation is normal for profiling i.e. people want to profile the object code, not every different virtual address the object code might be mapped to (across different processes for example).
--- arch/x86/mm/cpu_entry_area.c | 10 ++++++++++ fs/proc/kcore.c | 7 +++++-- include/linux/kcore.h | 13 +++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-)
arch/x86/mm/cpu_entry_area.c +10 -0
@@ -3,6 +3,7 @@#include <linux/spinlock.h> #include <linux/percpu.h> #include <linux/kallsyms.h> +#include <linux/kcore.h> #include <asm/cpu_entry_area.h> #include <asm/pgtable.h>
@@ -14,6 +15,7 @@#ifdef CONFIG_X86_64 static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]); +static DEFINE_PER_CPU(struct kcore_list, kcore_entry_trampoline);#endif struct cpu_entry_area *get_cpu_entry_area (int cpu)
@@ -147,6 +149,14 @@ static void __init setup_cpu_entry_area(int cpu)cea_set_pte (&get_cpu_entry_area (cpu)->entry_trampoline,__pa_symbol (_entry_trampoline),PAGE_KERNEL_RX ); +/* +* The cpu_entry_area alias addresses are not in the kernel binary +* so they do not show up in /proc/kcore normally. This adds entries +* for them manually. +*/ +kclist_add_remap (&per_cpu (kcore_entry_trampoline, cpu), + _entry_trampoline, + &get_cpu_entry_area (cpu)->entry_trampoline,PAGE_SIZE );#endif percpu_setup_debug_store (cpu); }
fs/proc/kcore.c +5 -2
@@ -383,8 +383,11 @@ static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff) phdr->p_type =PT_LOAD ; phdr->p_flags =PF_R |PF_W |PF_X ; phdr->p_offset =kc_vaddr_to_offset (m->addr) + dataoff; - phdr->p_vaddr = (size_t )m->addr; -if (m->type ==KCORE_RAM || m->type ==KCORE_TEXT ) +if (m->type ==KCORE_REMAP ) + phdr->p_vaddr = (size_t )m->vaddr; +else + phdr->p_vaddr = (size_t )m->addr; +if (m->type ==KCORE_RAM || m->type ==KCORE_TEXT || m->type ==KCORE_REMAP ) phdr->p_paddr =__pa (m->addr);else phdr->p_paddr = (elf_addr_t)-1 ;
include/linux/kcore.h +13 -0
@@ -12,11 +12,13 @@ enum kcore_type {KCORE_VMEMMAP ,KCORE_USER ,KCORE_OTHER , + KCORE_REMAP, };struct kcore_list {struct list_head list;unsigned long addr; +unsigned long vaddr;size_t size;int type; };
@@ -30,11 +32,22 @@ struct vmcore {#ifdef CONFIG_PROC_KCORE extern void kclist_add (struct kcore_list *,void *,size_t ,int type); +static inline +void kclist_add_remap (struct kcore_list *m,void *addr,void *vaddr,size_t sz) +{ + m->vaddr = (unsigned long )vaddr; +kclist_add (m, addr, sz,KCORE_REMAP ); +}#else static inline void kclist_add (struct kcore_list *new,void *addr,size_t size,int type) { } + +static inline +void kclist_add_remap (struct kcore_list *m,void *addr,void *vaddr,size_t sz) +{ +}#endif #endif /* _LINUX_KCORE_H */
Signature · 1 line
1.9.1
Re: [PATCH V4 3/3] x86: Add entry trampolines to kcore
Quoted 14 lines · Adrian Hunter
Without program headers for PTI entry trampoline pages, the trampoline virtual addresses do not map to anything.
In addition, entry trampolines all map to the same page. Represent that by giving the corresponding program headers in kcore the same offset.
This has the benefit that, when perf tools uses
/proc/kcoreas a source for kernel object code, samples from different CPU trampolines are aggregated together. Note, such aggregation is normal for profiling i.e. people want to profile the object code, not every different virtual address the object code might be mapped to (across different processes for example).
Quoted 7 lines
Signed-off-by Adrian Hunter <[email protected]>Acked-by Andi Kleen <[email protected]>--- arch/x86/mm/cpu_entry_area.c | 10 ++++++++++ fs/proc/kcore.c | 7 +++++-- include/linux/kcore.h | 13 +++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-)
This also adds the KCORE_REMAP functionality, but isn't mentioned at all in the Changelog.
Still, looks OK I suppose,
Re: [PATCH V4 3/3] x86: Add entry trampolines to kcore
Em Wed, Jun 06, 2018 at 03:16:31PM +0200, Peter Zijlstra escreveu:
Quoted 23 lines · Adrian Hunter
Quoted 14 lines
Without program headers for PTI entry trampoline pages, the trampoline virtual addresses do not map to anything.
In addition, entry trampolines all map to the same page. Represent that by giving the corresponding program headers in kcore the same offset.
This has the benefit that, when perf tools uses
/proc/kcoreas a source for kernel object code, samples from different CPU trampolines are aggregated together. Note, such aggregation is normal for profiling i.e. people want to profile the object code, not every different virtual address the object code might be mapped to (across different processes for example).Quoted 7 lines
Signed-off-by Adrian Hunter <[email protected]>Acked-by Andi Kleen <[email protected]>--- arch/x86/mm/cpu_entry_area.c | 10 ++++++++++ fs/proc/kcore.c | 7 +++++-- include/linux/kcore.h | 13 +++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-)
Quoted 4 lines
This also adds the
KCORE_REMAPfunctionality, but isn't mentioned at all in the Changelog.Still, looks OK I suppose,
I can add a note about that,
Quoted 1 line
Thanks, giving it some more hours and will apply and try to test it.
- Arnaldo
Re: [PATCH V4 3/3] x86: Add entry trampolines to kcore
Quoted 27 lines · Arnaldo Carvalho de Melo
Em Wed, Jun 06, 2018 at 03:16:31PM +0200, Peter Zijlstra escreveu:
Quoted 26 lines · Adrian Hunter
Quoted 14 lines
Without program headers for PTI entry trampoline pages, the trampoline virtual addresses do not map to anything.
In addition, entry trampolines all map to the same page. Represent that by giving the corresponding program headers in kcore the same offset.
This has the benefit that, when perf tools uses
/proc/kcoreas a source for kernel object code, samples from different CPU trampolines are aggregated together. Note, such aggregation is normal for profiling i.e. people want to profile the object code, not every different virtual address the object code might be mapped to (across different processes for example).Quoted 7 lines
Signed-off-by Adrian Hunter <[email protected]>Acked-by Andi Kleen <[email protected]>--- arch/x86/mm/cpu_entry_area.c | 10 ++++++++++ fs/proc/kcore.c | 7 +++++-- include/linux/kcore.h | 13 +++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-)This also adds the
KCORE_REMAPfunctionality, but isn't mentioned at all in the Changelog.
Quoted 7 lines
Quoted 1 line
Still, looks OK I suppose,
I can add a note about that,
Quoted 1 line
Thanks, giving it some more hours and will apply and try to test it.
Any update on this?
Re: [PATCH V4 3/3] x86: Add entry trampolines to kcore
Em Tue, Jul 17, 2018 at 11:54:30AM +0300, Adrian Hunter escreveu:
Quoted 30 lines · Arnaldo Carvalho de Melo
Quoted 29 lines
Em Wed, Jun 06, 2018 at 03:16:31PM +0200, Peter Zijlstra escreveu:
Quoted 27 lines · Adrian Hunter
Quoted 14 lines
Without program headers for PTI entry trampoline pages, the trampoline virtual addresses do not map to anything.
In addition, entry trampolines all map to the same page. Represent that by giving the corresponding program headers in kcore the same offset.
This has the benefit that, when perf tools uses
/proc/kcoreas a source for kernel object code, samples from different CPU trampolines are aggregated together. Note, such aggregation is normal for profiling i.e. people want to profile the object code, not every different virtual address the object code might be mapped to (across different processes for example).Quoted 7 lines
Signed-off-by Adrian Hunter <[email protected]>Acked-by Andi Kleen <[email protected]>--- arch/x86/mm/cpu_entry_area.c | 10 ++++++++++ fs/proc/kcore.c | 7 +++++-- include/linux/kcore.h | 13 +++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-)This also adds the
KCORE_REMAPfunctionality, but isn't mentioned at all in the Changelog.Still, looks OK I suppose,
Quoted 7 lines
Quoted 5 lines
I can add a note about that,
Quoted 1 line
Thanks, giving it some more hours and will apply and try to test it.
Any update on this?
On the post-vacation pile, will get to it.
- Arnaldo
tip-bot for Adrian Hunter
merge bot[tip:perf/urgent] x86: Add entry trampolines to kcore
In reply to Adrian Hunterx86: Add entry trampolines to kcore
Commit-ID: 6855dc41b24619c3d1de3dbd27dd0546b0e45272 Gitweb: https://git.kernel.org/tip/6855dc41b24619c3d1de3dbd27dd0546b0e45272 Author: Adrian Hunter <[email protected]> AuthorDate: Wed, 6 Jun 2018 15:54:11 +0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 14 Aug 2018 19:13:26 -0300
x86: Add entry trampolines to kcore
Without program headers for PTI entry trampoline pages, the trampoline virtual addresses do not map to anything.
Example before:
sudo gdb --quiet vmlinux /proc/kcore
Reading symbols from vmlinux...done.
[New process 1]
Core was generated by `BOOT_IMAGE=/boot/vmlinuz-4.16.0 root=UUID=a6096b83-b763-4101-807e-f33daff63233'. #0 0x0000000000000000 in irq_stack_union ()
(gdb) x /21ib 0xfffffe0000006000
0xfffffe0000006000: Cannot access memory at address 0xfffffe0000006000
(gdb) quit
After:
sudo gdb --quiet vmlinux /proc/kcore
[sudo] password for ahunter:
Reading symbols from vmlinux...done.
[New process 1]
Core was generated by `BOOT_IMAGE=/boot/vmlinuz-4.16.0-fix-4-00005-gd6e65a8b4072 root=UUID=a6096b83-b7'. #0 0x0000000000000000 in irq_stack_union ()
(gdb) x /21ib 0xfffffe0000006000
0xfffffe0000006000: swapgs
0xfffffe0000006003: mov %rsp,-0x3e12(%rip) # 0xfffffe00000021f8
0xfffffe000000600a: xchg %ax,%ax
0xfffffe000000600c: mov %cr3,%rsp
0xfffffe000000600f: bts $0x3f,%rsp
0xfffffe0000006014: and $0xffffffffffffe7ff,%rsp
0xfffffe000000601b: mov %rsp,%cr3
0xfffffe000000601e: mov -0x3019(%rip),%rsp # 0xfffffe000000300c
0xfffffe0000006025: pushq $0x2b
0xfffffe0000006027: pushq -0x3e35(%rip) # 0xfffffe00000021f8
0xfffffe000000602d: push %r11
0xfffffe000000602f: pushq $0x33
0xfffffe0000006031: push %rcx
0xfffffe0000006032: push %rdi
0xfffffe0000006033: mov $0xffffffff91a00010,%rdi
0xfffffe000000603a: callq 0xfffffe0000006046
0xfffffe000000603f: pause
0xfffffe0000006041: lfence
0xfffffe0000006044: jmp 0xfffffe000000603f
0xfffffe0000006046: mov %rdi,(%rsp)
0xfffffe000000604a: retq(gdb) quit
In addition, entry trampolines all map to the same page. Represent that by giving the corresponding program headers in kcore the same offset.
This has the benefit that, when perf tools uses /proc/kcore as a source for kernel object code, samples from different CPU trampolines are aggregated together. Note, such aggregation is normal for profiling i.e. people want to profile the object code, not every different virtual address the object code might be mapped to (across different processes for example).
Notes by PeterZ:
This also adds the KCORE_REMAP functionality.
--- arch/x86/mm/cpu_entry_area.c | 10 ++++++++++ fs/proc/kcore.c | 7 +++++-- include/linux/kcore.h | 13 +++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-)
arch/x86/mm/cpu_entry_area.c +10 -0
@@ -3,6 +3,7 @@#include <linux/spinlock.h> #include <linux/percpu.h> #include <linux/kallsyms.h> +#include <linux/kcore.h> #include <asm/cpu_entry_area.h> #include <asm/pgtable.h>
@@ -14,6 +15,7 @@ static DEFINE_PER_CPU_PAGE_ALIGNED(struct entry_stack_page, entry_stack_storage)#ifdef CONFIG_X86_64 static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]); +static DEFINE_PER_CPU(struct kcore_list, kcore_entry_trampoline);#endif struct cpu_entry_area *get_cpu_entry_area (int cpu)
@@ -147,6 +149,14 @@ static void __init setup_cpu_entry_area(int cpu)cea_set_pte (&get_cpu_entry_area (cpu)->entry_trampoline,__pa_symbol (_entry_trampoline),PAGE_KERNEL_RX ); +/* +* The cpu_entry_area alias addresses are not in the kernel binary +* so they do not show up in /proc/kcore normally. This adds entries +* for them manually. +*/ +kclist_add_remap (&per_cpu (kcore_entry_trampoline, cpu), + _entry_trampoline, + &get_cpu_entry_area (cpu)->entry_trampoline,PAGE_SIZE );#endif percpu_setup_debug_store (cpu); }
fs/proc/kcore.c +5 -2
@@ -383,8 +383,11 @@ static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff) phdr->p_type =PT_LOAD ; phdr->p_flags =PF_R |PF_W |PF_X ; phdr->p_offset =kc_vaddr_to_offset (m->addr) + dataoff; - phdr->p_vaddr = (size_t )m->addr; -if (m->type ==KCORE_RAM || m->type ==KCORE_TEXT ) +if (m->type ==KCORE_REMAP ) + phdr->p_vaddr = (size_t )m->vaddr; +else + phdr->p_vaddr = (size_t )m->addr; +if (m->type ==KCORE_RAM || m->type ==KCORE_TEXT || m->type ==KCORE_REMAP ) phdr->p_paddr =__pa (m->addr);else phdr->p_paddr = (elf_addr_t)-1 ;
include/linux/kcore.h +13 -0
@@ -12,11 +12,13 @@ enum kcore_type {KCORE_VMEMMAP ,KCORE_USER ,KCORE_OTHER , + KCORE_REMAP, };struct kcore_list {struct list_head list;unsigned long addr; +unsigned long vaddr;size_t size;int type; };
@@ -36,11 +38,22 @@ struct vmcoredd_node {#ifdef CONFIG_PROC_KCORE extern void kclist_add (struct kcore_list *,void *,size_t ,int type); +static inline +void kclist_add_remap (struct kcore_list *m,void *addr,void *vaddr,size_t sz) +{ + m->vaddr = (unsigned long )vaddr; +kclist_add (m, addr, sz,KCORE_REMAP ); +}#else static inline void kclist_add (struct kcore_list *new,void *addr,size_t size,int type) { } + +static inline +void kclist_add_remap (struct kcore_list *m,void *addr,void *vaddr,size_t sz) +{ +}#endif #endif /* _LINUX_KCORE_H */