| 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 |
| --- a/arch/Kconfig |
| +++ b/arch/Kconfig |
| @@ -569,7 +569,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 |
| --- a/include/asm-generic/vmlinux.lds.h |
| +++ b/include/asm-generic/vmlinux.lds.h |
| @@ -565,6 +565,7 @@ |
| *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \ |
| NOINSTR_TEXT \ |
| *(.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 |
| --- a/include/linux/compiler-clang.h |
| +++ b/include/linux/compiler-clang.h |
| @@ -42,3 +42,10 @@ |
| * compilers, like ICC. |
| */ |
| #define barrier() __asm__ __volatile__("" : : : "memory") |
| + |
| +#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 |
| --- a/include/linux/compiler_types.h |
| +++ b/include/linux/compiler_types.h |
| @@ -197,6 +197,10 @@ struct ftrace_likely_data { |
| # define randomized_struct_fields_end |
| #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 |
| --- a/kernel/trace/ftrace.c |
| +++ b/kernel/trace/ftrace.c |
| @@ -6062,9 +6062,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 |
| --- a/scripts/Makefile.build |
| +++ b/scripts/Makefile.build |
| @@ -178,6 +178,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 |
| @@ -186,6 +192,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 |
| @@ -195,10 +203,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 |
| --- a/scripts/Makefile.modfinal |
| +++ b/scripts/Makefile.modfinal |
| @@ -41,6 +41,10 @@ ifdef CONFIG_LTO_CLANG |
| -o $@ --whole-archive \ |
| $(filter-out FORCE,$(^:$(modpost-ext).o=.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 |
| --- 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 |
| +} |
| + |
| objtool_link() |
| { |
| local objtoolopt; |
| @@ -320,6 +333,11 @@ objtool_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 |
| info GEN modules.builtin |
| diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c |
| --- a/scripts/recordmcount.c |
| +++ b/scripts/recordmcount.c |
| @@ -412,7 +412,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! */ |