| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| From: Sami Tolvanen <samitolvanen@google.com> |
| Date: Wed, 8 May 2019 13:53:41 -0700 |
| Subject: ANDROID: kbuild: fix dynamic ftrace with clang LTO |
| |
| With CONFIG_LTO_CLANG enabled, LLVM IR won't be compiled into object |
| files until modpost_link. This change postpones calls to recordmcount |
| until after this step. |
| |
| In order to exclude ftrace_process_locs from inspection, we add a new |
| code section .text..ftrace, which we tell recordmcount to ignore, and |
| a __norecordmcount attribute for moving functions to this section. |
| |
| Bug: 145210207 |
| Change-Id: Ib77f7c431fce54243c46d584b55761ed2342965c |
| Signed-off-by: Sami Tolvanen <samitolvanen@google.com> |
| --- |
| arch/Kconfig | 2 +- |
| include/asm-generic/vmlinux.lds.h | 1 + |
| include/linux/compiler-clang.h | 7 +++++++ |
| include/linux/compiler_types.h | 4 ++++ |
| kernel/trace/ftrace.c | 6 +++--- |
| scripts/Makefile.build | 11 +++++++++++ |
| scripts/Makefile.modfinal | 4 ++++ |
| scripts/link-vmlinux.sh | 18 ++++++++++++++++++ |
| scripts/recordmcount.c | 4 +++- |
| 9 files changed, 52 insertions(+), 5 deletions(-) |
| |
| diff --git a/arch/Kconfig b/arch/Kconfig |
| index 1766abf2f5c2..12f11fcba9cd 100644 |
| --- a/arch/Kconfig |
| +++ b/arch/Kconfig |
| @@ -590,7 +590,7 @@ config LTO_CLANG |
| bool "Use Clang's Link Time Optimization (LTO) (EXPERIMENTAL)" |
| depends on ARCH_SUPPORTS_LTO_CLANG |
| depends on !KASAN |
| - depends on !FTRACE_MCOUNT_RECORD |
| + depends on !FTRACE_MCOUNT_RECORD || HAVE_C_RECORDMCOUNT |
| depends on CC_IS_CLANG && CLANG_VERSION >= 100000 && LD_IS_LLD |
| select LTO |
| help |
| diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h |
| index ec4827773569..73a215a7d33f 100644 |
| --- a/include/asm-generic/vmlinux.lds.h |
| +++ b/include/asm-generic/vmlinux.lds.h |
| @@ -521,6 +521,7 @@ |
| ALIGN_FUNCTION(); \ |
| *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \ |
| *(.text..refcount) \ |
| + *(.text..ftrace) \ |
| *(.ref.text) \ |
| MEM_KEEP(init.text*) \ |
| MEM_KEEP(exit.text*) \ |
| diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h |
| index 18fc4d29ef27..5e97289e1e67 100644 |
| --- a/include/linux/compiler-clang.h |
| +++ b/include/linux/compiler-clang.h |
| @@ -48,3 +48,10 @@ |
| #else |
| # define __noscs |
| #endif |
| + |
| +#ifdef CONFIG_LTO_CLANG |
| +#ifdef CONFIG_FTRACE_MCOUNT_RECORD |
| +#define __norecordmcount \ |
| + __attribute__((__section__(".text..ftrace"))) |
| +#endif |
| +#endif |
| diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h |
| index be5d5be4b1ae..48e7e3396656 100644 |
| --- a/include/linux/compiler_types.h |
| +++ b/include/linux/compiler_types.h |
| @@ -206,6 +206,10 @@ struct ftrace_likely_data { |
| # define __noscs |
| #endif |
| |
| +#ifndef __norecordmcount |
| +# define __norecordmcount |
| +#endif |
| + |
| #ifndef asm_volatile_goto |
| #define asm_volatile_goto(x...) asm goto(x) |
| #endif |
| diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c |
| index 0708a41cfe2d..85d9f4931c3e 100644 |
| --- a/kernel/trace/ftrace.c |
| +++ b/kernel/trace/ftrace.c |
| @@ -5564,9 +5564,9 @@ static int ftrace_cmp_ips(const void *a, const void *b) |
| return 0; |
| } |
| |
| -static int ftrace_process_locs(struct module *mod, |
| - unsigned long *start, |
| - unsigned long *end) |
| +static int __norecordmcount ftrace_process_locs(struct module *mod, |
| + unsigned long *start, |
| + unsigned long *end) |
| { |
| struct ftrace_page *start_pg; |
| struct ftrace_page *pg; |
| diff --git a/scripts/Makefile.build b/scripts/Makefile.build |
| index 7aefd2a1347e..827945fc381d 100644 |
| --- a/scripts/Makefile.build |
| +++ b/scripts/Makefile.build |
| @@ -177,6 +177,12 @@ ifdef BUILD_C_RECORDMCOUNT |
| ifeq ("$(origin RECORDMCOUNT_WARN)", "command line") |
| RECORDMCOUNT_FLAGS = -w |
| endif |
| + |
| +ifdef CONFIG_LTO_CLANG |
| +# With LTO, we postpone running recordmcount until after the LTO link step, so |
| +# let's export the parameters for the link script. |
| +export RECORDMCOUNT_FLAGS |
| +else |
| # Due to recursion, we must skip empty.o. |
| # The empty.o file is created in the make process in order to determine |
| # the target endianness and word size. It is made before all other C |
| @@ -185,6 +191,8 @@ sub_cmd_record_mcount = \ |
| if [ $(@) != "scripts/mod/empty.o" ]; then \ |
| $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \ |
| fi; |
| +endif |
| + |
| recordmcount_source := $(srctree)/scripts/recordmcount.c \ |
| $(srctree)/scripts/recordmcount.h |
| else |
| @@ -194,10 +202,13 @@ sub_cmd_record_mcount = perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ |
| "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)" \ |
| "$(LD) $(KBUILD_LDFLAGS)" "$(NM)" "$(RM)" "$(MV)" \ |
| "$(if $(part-of-module),1,0)" "$(@)"; |
| + |
| recordmcount_source := $(srctree)/scripts/recordmcount.pl |
| endif # BUILD_C_RECORDMCOUNT |
| +ifndef CONFIG_LTO_CLANG |
| cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)), \ |
| $(sub_cmd_record_mcount)) |
| +endif # CONFIG_LTO_CLANG |
| endif # CC_USING_RECORD_MCOUNT |
| endif # CONFIG_FTRACE_MCOUNT_RECORD |
| |
| diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal |
| index 2164a84a45a2..216a3f84bafe 100644 |
| --- a/scripts/Makefile.modfinal |
| +++ b/scripts/Makefile.modfinal |
| @@ -41,6 +41,10 @@ ifdef CONFIG_LTO_CLANG |
| echo -T $(@:.ko=.o.symversions)) \ |
| -o $@ --whole-archive $(filter %.o, $^); \ |
| $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) |
| + |
| + ifdef CONFIG_FTRACE_MCOUNT_RECORD |
| + cmd_ld_ko_o += ; $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) $@ |
| + endif |
| else |
| cmd_ld_ko_o = \ |
| $(LD) -r $(KBUILD_LDFLAGS) \ |
| diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh |
| index e589ce9b0acd..370446faad0b 100755 |
| --- a/scripts/link-vmlinux.sh |
| +++ b/scripts/link-vmlinux.sh |
| @@ -87,6 +87,19 @@ modpost_link() |
| ${LD} ${KBUILD_LDFLAGS} -r -o ${1} $(modversions) ${objects} |
| } |
| |
| +# If CONFIG_LTO_CLANG is selected, we postpone running recordmcount until |
| +# we have compiled LLVM IR to an object file. |
| +recordmcount() |
| +{ |
| + if [ -z "${CONFIG_LTO_CLANG}" ]; then |
| + return |
| + fi |
| + |
| + if [ -n "${CONFIG_FTRACE_MCOUNT_RECORD}" ]; then |
| + scripts/recordmcount ${RECORDMCOUNT_FLAGS} $* |
| + fi |
| +} |
| + |
| # Link of vmlinux |
| # ${1} - output file |
| # ${2}, ${3}, ... - optional extra .o files |
| @@ -287,6 +300,11 @@ modpost_link vmlinux.o |
| # modpost vmlinux.o to check for section mismatches |
| ${MAKE} -f "${srctree}/scripts/Makefile.modpost" MODPOST_VMLINUX=1 |
| |
| +if [ -n "${CONFIG_LTO_CLANG}" ]; then |
| + # Call recordmcount if needed |
| + recordmcount vmlinux.o |
| +fi |
| + |
| info MODINFO modules.builtin.modinfo |
| ${OBJCOPY} -j .modinfo -O binary vmlinux.o modules.builtin.modinfo |
| |
| diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c |
| index 612268eabef4..a9fa776fb881 100644 |
| --- a/scripts/recordmcount.c |
| +++ b/scripts/recordmcount.c |
| @@ -408,7 +408,9 @@ static int is_mcounted_section_name(char const *const txtname) |
| strcmp(".irqentry.text", txtname) == 0 || |
| strcmp(".softirqentry.text", txtname) == 0 || |
| strcmp(".kprobes.text", txtname) == 0 || |
| - strcmp(".cpuidle.text", txtname) == 0; |
| + strcmp(".cpuidle.text", txtname) == 0 || |
| + (strncmp(".text.", txtname, 6) == 0 && |
| + strcmp(".text..ftrace", txtname) != 0); |
| } |
| |
| static char const *already_has_rel_mcount = "success"; /* our work here is done! */ |