linux: add linker tables
Subsystems (24)
v2 cover linux: add linker tables
This is my v2 of the original linker table work [0], now with six proof of concepts ports of existing code using custom section with custom linker script modifications:
* DEFINE_LINKTABLE_TEXT(char, kprobes);
* DEFINE_LINKTABLE_DATA(struct jump_entry, __jump_table);
* DEFINE_LINKTABLE_DATA(struct _ddebug, __verbose);
* DEFINE_LINKTABLE_RO(struct builtin_fw, builtin_fw);
* DEFINE_LINKTABLE_INIT(struct x86_init_fn, x86_init_fns);
* DEFINE_LINKTABLE_INIT_DATA(unsigned long, _kprobe_blacklist);
I've tested all except jump tables, I'd appreaciate some help with that.
As requested by hpa I've used standard sections and by doing so it gives us the ability to simply categorize any custom table by actual section used.
To help avoid further unnecessary linker script modifications, and to help bring some clarify to how all these works I went to some lengths to give documentating standard kernel sections a shot.
The implementation deviates now from iPXE's linker table solution more in favor for what we're used to and expect on Linux. This series leaves out the paravirt_enabled() changes, and the x86 use of linker tables. The paravirt_enabled() stuff is now being dealt with separately [1] [2], and the x86 use case for this will be sent as a separate series for review.
Although the diffstat is large, that's mostly documentation and the new code. If you skip that you get:
54 files changed, 104 insertions(+), 136 deletions(-)
Most of the savings come from the ability to skip custom linker table entries. The users space solutoin has a new home [3].
[0] http://[email protected]
[1] http://kernelnewbies.org/KernelProjects/remove-paravirt-enabled
[2] http://lkml.kernel.org/r/[email protected]
[3] https://git.kernel.org/cgit/linux/kernel/git/mcgrof/linker-tables.git/
Luis R. Rodriguez (7):
sections.h: add sections header to collect all section info tables.h: add linker table support
firmware: port built-in section to linker table asm/sections: add a generic push_section_tbl()
jump_label: port __jump_table to linker tables
dynamic_debug: port to use linker tables
kprobes: port to linker table
Documentation/DocBook/Makefile | 3 +- Documentation/DocBook/linker-tables.tmpl | 169 ++++++++ Documentation/DocBook/sections.tmpl | 99 +++++ Documentation/kbuild/makefiles.txt | 19 + arch/arc/kernel/vmlinux.lds.S | 1 - arch/arm/include/asm/jump_label.h | 4 +- arch/arm/kernel/entry-armv.S | 2 +- arch/arm/kernel/vmlinux.lds.S | 1 - arch/arm64/include/asm/jump_label.h | 4 +- arch/avr32/kernel/entry-avr32b.S | 4 +- arch/avr32/kernel/vmlinux.lds.S | 1 - arch/blackfin/kernel/vmlinux.lds.S | 1 - arch/c6x/kernel/vmlinux.lds.S | 1 - arch/hexagon/kernel/vmlinux.lds.S | 1 - arch/ia64/kernel/jprobes.S | 2 +- arch/ia64/kernel/vmlinux.lds.S | 1 - arch/ia64/lib/flush.S | 4 +- arch/metag/kernel/vmlinux.lds.S | 1 - arch/microblaze/kernel/vmlinux.lds.S | 1 - arch/mips/include/asm/jump_label.h | 4 +- arch/mips/kernel/vmlinux.lds.S | 1 - arch/mn10300/kernel/vmlinux.lds.S | 1 - arch/nios2/kernel/vmlinux.lds.S | 1 - arch/openrisc/kernel/vmlinux.lds.S | 1 - arch/parisc/kernel/vmlinux.lds.S | 1 - arch/powerpc/include/asm/jump_label.h | 6 +- arch/powerpc/include/asm/ppc_asm.h | 6 +- arch/powerpc/kernel/vmlinux.lds.S | 1 - arch/s390/include/asm/jump_label.h | 4 +- arch/s390/kernel/entry.S | 4 +- arch/s390/kernel/kprobes.c | 2 +- arch/s390/kernel/mcount.S | 2 +- arch/s390/kernel/vmlinux.lds.S | 1 - arch/score/kernel/vmlinux.lds.S | 1 - arch/sh/kernel/vmlinux.lds.S | 1 - arch/sparc/include/asm/jump_label.h | 4 +- arch/sparc/kernel/vmlinux.lds.S | 1 - arch/sparc/mm/ultra.S | 2 +- arch/tile/kernel/vmlinux.lds.S | 1 - arch/x86/include/asm/jump_label.h | 9 +- arch/x86/kernel/cpu/microcode/core.c | 7 +- arch/x86/kernel/kprobes/core.c | 10 +- arch/x86/kernel/vmlinux.lds.S | 1 - arch/x86/tools/relocs.c | 3 + drivers/base/firmware_class.c | 11 +- firmware/Makefile | 2 +- include/asm-generic/sections.h | 14 +- include/asm-generic/vmlinux.lds.h | 47 +-- include/linux/compiler.h | 3 +- include/linux/dynamic_debug.h | 6 +- include/linux/jump_label.h | 5 +- include/linux/kprobes.h | 7 +- include/linux/sections.h | 224 ++++++++++ include/linux/tables.h | 696 +++++++++++++++++++++++++++++++ kernel/jump_label.c | 16 +- kernel/kprobes.c | 16 +- kernel/module.c | 6 +- lib/dynamic_debug.c | 13 +- scripts/Makefile.build | 4 +- scripts/Makefile.clean | 1 + scripts/Makefile.lib | 12 + scripts/mod/modpost.c | 3 +- scripts/recordmcount.c | 3 +- scripts/recordmcount.pl | 2 +- tools/include/linux/sections.h | 13 + 65 files changed, 1355 insertions(+), 143 deletions(-) create mode 100644 Documentation/DocBook/linker-tables.tmpl create mode 100644 Documentation/DocBook/sections.tmpl create mode 100644 include/linux/sections.h create mode 100644 include/linux/tables.h create mode 100644 tools/include/linux/sections.h
Signature · 1 line
2.7.0
RFC v2 1/7 sections.h: add sections header to collect all section info
Linux makes extensive use of custom ELF header sections, documentation for these are well scatterred. Unify this documentation in a central place.
--- Documentation/DocBook/Makefile | 3 +- Documentation/DocBook/sections.tmpl | 99 ++++++++++++++++ include/linux/sections.h | 224 ++++++++++++++++++++++++++++++++++++ 3 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 Documentation/DocBook/sections.tmpl create mode 100644 include/linux/sections.h
Documentation/DocBook/Makefile +2 -1
@@ -15,7 +15,8 @@ DOCBOOKS := z8530book.xml device-drivers.xml \ 80211.xml debugobjects.xml sh.xml regulator.xml \ alsa-driver-api.xml writing-an-alsa-driver.xml \ tracepoint.xml gpu.xml media_api.xml w1.xml \ - writing_musb_glue_layer.xml crypto-API.xml iio.xml + writing_musb_glue_layer.xml crypto-API.xml iio.xml \ + sections.xml include Documentation/DocBook/media/Makefile
Documentation/DocBook/sections.tmpl new file +99 -0
99 lines not on this page · raw message
include/linux/sections.h new file +224 -0
224 lines not on this page · raw message
Signature · 1 line
2.7.0
Greg KH
maintainerRe: [RFC v2 1/7] sections.h: add sections header to collect all section info
Quoted 3 lines · Luis R. Rodriguez
Linux makes extensive use of custom ELF header sections, documentation for these are well scatterred. Unify this documentation in a central place.
Minor questions:
Documentation/DocBook/sections.tmpl line 43
Quoted 6 lines
Documentation/DocBook/sections.tmpl new file +6
-0+ <para> + You should have received a copy of the GNU General Public + License along with this documentation; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + </para>
Unless you are willing to personally track the office moves of the FSF for the next 20+ years, just drop this paragraph please :)
include/linux/sections.h line 11
Quoted 13 lines
+++
b/include/linux/sections.hinclude/linux/sections.h new file +11
-0@@ -0,0 +1,224 @@ +#ifndef _LINUX_SECTIONS_H +#define _LINUX_SECTIONS_H +/* +* Linux ELF sections +* +* Copyright (C) 2016 Luis R. Rodriguez <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version.
Do you really mean "any later version"?
include/linux/sections.h line 16
Quoted 4 lines
include/linux/sections.h new file +4
-0+* Due to this file being licensed under the GPL there is controversy over +* whether this permits you to write a module that #includes this file +* without placing your module under the GPL. Please consult a lawyer for +* advice before doing this.
Interesting wording, I don't think there's any "controversy" here, so I'd drop that word if at all possible.
thanks,
greg k-h
Re: [RFC v2 1/7] sections.h: add sections header to collect all section info
Quoted 14 lines · Greg KH
Quoted 3 lines · Luis R. Rodriguez
Linux makes extensive use of custom ELF header sections, documentation for these are well scatterred. Unify this documentation in a central place.
Minor questions:
Documentation/DocBook/sections.tmpl line 43
Quoted 6 lines
Documentation/DocBook/sections.tmpl new file +6
-0+ <para> + You should have received a copy of the GNU General Public + License along with this documentation; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + </para>
Quoted 2 lines
Unless you are willing to personally track the office moves of the FSF for the next 20+ years, just drop this paragraph please :)
Sure.
Quoted 7 lines
Quoted 7 lines
+++
b/include/linux/sections.hinclude/linux/sections.h new file +5
-0@@ -0,0 +1,224 @@ +#ifndef _LINUX_SECTIONS_H +#define _LINUX_SECTIONS_H +/* +* Linux ELF sections +*
Quoted 8 lines
include/linux/sections.h line 11
Quoted 6 lines
include/linux/sections.h new file +6
-0+* Copyright (C) 2016 Luis R. Rodriguez <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. Do you really mean "any later version"?
Yes.
Quoted 6 lines
include/linux/sections.h line 16
Quoted 4 lines
include/linux/sections.h new file +4
-0+* Due to this file being licensed under the GPL there is controversy over +* whether this permits you to write a module that #includes this file +* without placing your module under the GPL. Please consult a lawyer for +* advice before doing this. Interesting wording,
This was copied from security.h.
Quoted 2 lines
I don't think there's any "controversy" here, so I'd drop that word if at all possible.
Change it for something else? Any preference?
Luis
Greg KH
maintainerRe: [RFC v2 1/7] sections.h: add sections header to collect all section info
Quoted 10 lines · Luis R. Rodriguez
Quoted 7 lines · Greg KH
Quoted 4 lines · Luis R. Rodriguez
+ * Due to this file being licensed under the GPL there is controversy over
+ * whether this permits you to write a module that #includes this file
+ * without placing your module under the GPL. Please consult a lawyer for
+ * advice before doing this.Interesting wording,
This was copied from
security.h.
Ah, and look, I wrote that, nevermind then :)
sorry for the noise,
greg k-h
Re: [RFC v2 1/7] sections.h: add sections header to collect all section info
Quoted 8 lines · Greg KH
Quoted 7 lines · Luis R. Rodriguez
Quoted 6 lines · Greg KH
Quoted 4 lines · Luis R. Rodriguez
+ * Due to this file being licensed under the GPL there is controversy over
+ * whether this permits you to write a module that #includes this file
+ * without placing your module under the GPL. Please consult a lawyer for
+ * advice before doing this.
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
Interesting wording,
This was copied from
security.h.Ah, and look, I wrote that, nevermind then :)
sorry for the noise,
Heh, thanks I'll leave it as-is and modify that pesky address to a URL.
Luis
RFC v2 2/7 tables.h: add linker table support
In reply to Luis R. RodriguezA linker table is a data structure that is stitched together from items in multiple object files. Linux has historically implicitly used linker tables for ages, however they were all built in an adhoc manner which requires linker script modifications, per architecture. This adds a general linker table solution so that a new linker table can be implemented by changing C code only. The Linux linker table was originally based on Michael Brown's iPXE's linker table solution but has been significantly modified to fit Linux's use in its integration.
The same philosoph is borrowed, extended and further simplified:
Linker tables enable an extremely light weight linker build time solution for feature ordering and selection, this can help to both simplify init sequences in a generic fashion and helps avoiding code bit-rotting when desirable.
Bit rotting avoidance is enabled by *granting the option* to force compilation of code and only enable linking object code in when specific features have been enabled. It accomplishes this by using linker sections, the lightweight feature ordering of code is enabled by taking advantage of the old binutils ld SORT() on features specific sections.
Contrary to iPXE's solution, which strives to force compilation of all features, Linux' solution strives to encourage usage of linker tables to force compilation of code *only on designated code*. Linker tables can be used without requiring one to force code compilation of features that use it though, to take advantage of the simplification of init sequences.
Linux code that uses linker tables *and* wishes to always require compilation but selectively linking must use new kbuild target object that helps accomplishes this, table-y. Linux code that uses linker tables but does not want to require forcing compilation can use the good 'ol obj-y targets.
Used commit 67a10ef000cb7 from iPXE upstream [0] as the starting point for development and evaluation of Linux's integration, further changes made and evaluation of different linker table options for Linux are available on the linker-table userspace tree [1].
[0] git://git.ipxe.org/ipxe.git
[1] https://git.kernel.org/cgit/linux/kernel/git/mcgrof/linker-tables.git/
v2:
- modified completely to match feedback by community, made equivalent modifications to userspace solution. This is pretty much a complete rewrite of how we present and use linker tables. By using standard sections we no longer have to make custom linker script extensions for each new linker table solution, you just pick a linker table type by section type.
- extend documention considerably, including use of kdoc
- drop ICC hacks per popular request to ignore such issues for now
- use sections.h - this lets us streamline a clean use case of well documented sections. To help further with this make use of SECTION_TBL() to allow use of these in code and SECTION_TBL_ALL() on linker scripts, as well as SECTION_TBL_ALL_STR() on relocs.c when needed.
--- Documentation/DocBook/Makefile | 2 +- Documentation/DocBook/linker-tables.tmpl | 169 ++++++++ Documentation/kbuild/makefiles.txt | 19 + arch/x86/tools/relocs.c | 3 + include/asm-generic/vmlinux.lds.h | 15 +- include/linux/sections.h | 4 +- include/linux/tables.h | 696 +++++++++++++++++++++++++++++++ scripts/Makefile.build | 4 +- scripts/Makefile.clean | 1 + scripts/Makefile.lib | 12 + tools/include/linux/sections.h | 13 + 11 files changed, 929 insertions(+), 9 deletions(-) create mode 100644 Documentation/DocBook/linker-tables.tmpl create mode 100644 include/linux/tables.h create mode 100644 tools/include/linux/sections.h
Documentation/DocBook/Makefile +1 -1
@@ -16,7 +16,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \ alsa-driver-api.xml writing-an-alsa-driver.xml \ tracepoint.xml gpu.xml media_api.xml w1.xml \ writing_musb_glue_layer.xml crypto-API.xml iio.xml \ - sections.xml + sections.xml linker-tables.xml include Documentation/DocBook/media/Makefile
Documentation/DocBook/linker-tables.tmpl new file +169 -0
169 lines not on this page · raw message
Documentation/kbuild/makefiles.txt +19 -0
@@ -1088,6 +1088,25 @@ When kbuild executes, the following steps are followed (roughly): In this example, extra-y is used to list object files that shall be built, but shall not be linked as part of built-in.o. + table-y table-m and table- + + To avoid code bit-rot you may wish to avoid using #ifdefs on your + code. Bit-rot is possible if certain features may not be enabled + on certain build environments. The table-y, specifies targets which you + always wish to force compilation on, but wish to only enable linking in + if the feature is enabled, these are features taking advantage of + Linux's linker tables. For details on how to implement a feature using + linker tablesrefer to include/linux/tables.h. Use of table-m is not + yet supported. + + Example: + table-$(CONFIG-FEATURE_FOO) += foo.o + + An alternative to using table-y, is to use extra-y followed by the + respective obj-y: + + extra-y += foo.o + obj-$(CONFIG-FEATURE_FOO) += foo.o --- 6.7 Commands useful for building a boot image
arch/x86/tools/relocs.c +3 -0
@@ -1,4 +1,5 @@/* This is included from relocs_32/64.c */ +#include <linux/sections.h> #define ElfW (type) _ElfW(ELF_BITS, type)#define _ElfW (bits, type) __ElfW(bits, type)
@@ -68,6 +69,8 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {"__end_rodata|" "__initramfs_start|" "(jiffies|jiffies_64)|" + SECTION_TBL_ALL_STR(SECTION_RODATA) "|" + SECTION_TBL_ALL_STR(SECTION_INIT) "|" #if ELF_BITS == 64"__per_cpu_load|" "init_per_cpu__.*|"
include/asm-generic/vmlinux.lds.h +11 -4
@@ -55,6 +55,7 @@#endif #include <linux/export.h> +#include <linux/sections.h> /* Align . to a 8 byte boundary equals to maximum function alignment. */ #define ALIGN_FUNCTION () . = ALIGN(8)
@@ -199,7 +200,8 @@/* .data section */ #define DATA_DATA \ - *(.data) \ + *(SECTION_DATA) \ + *(SORT(SECTION_TBL_ALL(SECTION_DATA))) \ *(.ref.data) \ *(.data..shared_aligned)/* percpu related */ \MEM_KEEP (init.data) \
@@ -255,7 +257,9 @@ . = ALIGN((align)); \ .rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start_rodata) = .; \ - *(.rodata) *(.rodata.*) \ + *(.rodata) \ + *(SORT (SECTION_TBL_ALL (SECTION_RODATA ))) \ + *(.rodata.*) \ *(__vermagic)/* Kernel version magic */ \ . = ALIGN(8); \ VMLINUX_SYMBOL(__start___tracepoints_ptrs) = .; \
@@ -422,7 +426,8 @@* during second ld run in second ld pass when generating System.map */ #define TEXT_TEXT \ ALIGN_FUNCTION(); \ - *(.text.hot .text .text.fixup .text.unlikely) \ + *(.text.hot SECTION_TEXT .text.fixup .text.unlikely) \ + *(SORT(SECTION_TBL_ALL(SECTION_TEXT))) \ *(.ref.text) \ MEM_KEEP(init.text) \ MEM_KEEP(exit.text) \
@@ -507,7 +512,8 @@/* init and exit section handling */ #define INIT_DATA \ - *(.init.data) \ + *(SECTION_INIT_DATA) \ + *(SORT(SECTION_TBL_ALL(SECTION_INIT_DATA))) \ MEM_DISCARD(init.data) \ KERNEL_CTORS() \ MCOUNT_REC() \
@@ -531,6 +537,7 @@#define INIT_TEXT \ *(.init.text) \ + *(SORT(SECTION_TBL_ALL(SECTION_INIT))) \ MEM_DISCARD(init.text)#define EXIT_DATA \
include/linux/sections.h +2 -2
@@ -203,6 +203,8 @@#define SECTION_TBL (section, name, level) \ __SECTION_TBL(section, name, level) +#endif /* __ASSEMBLY__ */ +/* * For use on linker scripts and helpers */
@@ -219,6 +221,4 @@#define SECTION_TBL_ALL (section) \ ___SECTION_TBL(section,*) -#endif /* __ASSEMBLY__ */ -#endif /* _LINUX_SECTIONS_H */
include/linux/tables.h new file +696 -0
696 lines not on this page · raw message
scripts/Makefile.build +2 -2
@@ -91,7 +91,7 @@ modorder-target := $(obj)/modules.order # We keep a list of all modules in $(MODVERDIR) -__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \ +__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y) $(table-y)) \ $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \ $(subdir-ym) $(always) @:
@@ -294,7 +294,7 @@ $(obj)/%.o: $(src)/%.S FORCE $(call if_changed_dep,as_o_S) targets += $(real-objs-y) $(real-objs-m) $(lib-y) -targets += $(extra-y) $(MAKECMDGOALS) $(always) +targets += $(extra-y) $(table-y) $(MAKECMDGOALS) $(always) # Linker scripts preprocessor (.lds.S -> .lds) # ---------------------------------------------------------------------------
scripts/Makefile.clean +1 -0
@@ -36,6 +36,7 @@ subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn)) # directory __clean-files := $(extra-y) $(extra-m) $(extra-) \ + $(table-y) $(table-m) $(table-) \ $(always) $(targets) $(clean-files) \ $(host-progs) \ $(hostprogs-y) $(hostprogs-m) $(hostprogs-)
scripts/Makefile.lib +12 -0
@@ -12,6 +12,16 @@ export KBUILD_SUBDIR_CCFLAGS := $(KBUILD_SUBDIR_CCFLAGS) $(subdir-ccflags-y) # Figure out what we need to build from the various variables # =========================================================================== +# Linker tables objects always wish to be built to avoid bit-rot in +# code, but only linked in *iff* they were enabled. We accomplish this +# using pegging linker table objects into extra-y, which forces +# compilation and then using the respective table-y and table-m as +# as hints for things we do want enabled. Objects which we want to +# avoid linking in will be in table-, not table-y and table-m. +extra-y += $(table-) +obj-m += $(table-m) +obj-y += $(table-y) + # When an object is listed to be built compiled-in and modular, # only build the compiled-in version
@@ -72,6 +82,8 @@ real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y) # Add subdir path extra-y := $(addprefix $(obj)/,$(extra-y)) +table-y := $(addprefix $(obj)/,$(table-y)) +table-m := $(addprefix $(obj)/,$(table-m)) always := $(addprefix $(obj)/,$(always)) targets := $(addprefix $(obj)/,$(targets)) modorder := $(addprefix $(obj)/,$(modorder))
tools/include/linux/sections.h new file +13 -0
@@ -0,0 +1,13 @@ +#ifndef _TOOLS_LINUX_SECTIONS_H_ + +/* Mostly a copy of what we need only */ + +#define SECTION_INIT .init.text +#define SECTION_RODATA .rodata + +#define ___SECTION_TBL_STR (section, name) \ + #section ".tbl." #name +#define SECTION_TBL_ALL_STR (section) \ + ___SECTION_TBL_STR(section, *) + +#endif /* _TOOLS_LINUX_SECTIONS_H_ */
Signature · 1 line
2.7.0
H. Peter Anvin
reviewerRe: [RFC v2 2/7] tables.h: add linker table support
Quoted 12 lines · Luis R. Rodriguez
include/linux/tables.h new file +12
-0+ +/** +* DOC: Regular linker linker table constructors +* +* Regular constructors are expected to be used for valid linker table entries. +* Valid uses of weak entries other than the beginning and is currently +* untested but should in theory work. +*/ + +/** +* LINKTABLE_TEXT - Declares a linker table entry for execution +*
include/linux/tables.h line 424
Quoted 10 lines
include/linux/tables.h new file +10
-0+* @name: linker table name +* @level: order level +* +* Declares a linker table to be used for execution. +*/ +#define LINKTABLE_TEXT (name, level) \ + __typeof__(name[0]) \ + __attribute__((used, \ + __aligned__(LINKTABLE_ALIGNMENT(name)), \ + section(SECTION_TBL(SECTION_TEXT, name, level))))
I'm really confused by this. Text should obviously be readonly, but I'm not at all clear how this works here.
The issue with linktables for text is kind of confusing if nothing else; Russel is right about that. It doesn't prevent us from doing something similar, but perhaps it ought to have a different name.
For one thing, priority level is meaningless for text, since it is not a table that can be indexed into.
-hpa
Re: [RFC v2 2/7] tables.h: add linker table support
Quoted 17 lines · H. Peter Anvin
Quoted 16 lines · Luis R. Rodriguez
include/linux/tables.h new file +16
-0+ +/** +* DOC: Regular linker linker table constructors +* +* Regular constructors are expected to be used for valid linker table entries. +* Valid uses of weak entries other than the beginning and is currently +* untested but should in theory work. +*/ + +/** +* LINKTABLE_TEXT - Declares a linker table entry for execution +* +* @name: linker table name +* @level: order level +* +* Declares a linker table to be used for execution.
Quoted 8 lines
include/linux/tables.h line 424
Quoted 6 lines
+ */
include/linux/tables.h new file +5
-0+#define LINKTABLE_TEXT (name, level) \ + __typeof__(name[0]) \ + __attribute__((used, \ + __aligned__(LINKTABLE_ALIGNMENT(name)), \ + section(SECTION_TBL(SECTION_TEXT, name, level))))I'm really confused by this. Text should obviously be readonly,
So this uses SECTION_TEXT, so we just pegged the linker table entry right below the standard SECTION_TEXT:
@@ -422,7 +426,8 @@
* during second ld run in second ld pass when generating System.map */
#define TEXT_TEXT \
ALIGN_FUNCTION(); \
- *(.text.hot .text .text.fixup .text.unlikely) \
+ *(.text.hot SECTION_TEXT .text.fixup .text.unlikely) \
+ *(SORT(SECTION_TBL_ALL(SECTION_TEXT))) \
*(.ref.text) \
MEM_KEEP(init.text) \ MEM_KEEP(exit.text)
So this gets folded under TEXT_TEXT and we don't see to force all architectures for this to be read-only specifically. I can't be sure if it is always read-only for all architectures based on a cursory review.
Quoted 1 line
but I'm not at all clear how this works here.
Its simply trying to piggy back on top of where the standard section it is using so in this case SECTION_TEXT (.text). What attributes are part of that follow.
Quoted 3 lines
The issue with linktables for text is kind of confusing if nothing else; Russel is right about that. It doesn't prevent us from doing something similar, but perhaps it ought to have a different name.
Any recommendations?
Quoted 2 lines
For one thing, priority level is meaningless for text, since it is not a table that can be indexed into.
Ah right, there is no structure so we can't foo->in, let alone, know what arguments to pass... the order level certainly would still kick in but I agree that it would seem kind of pointless as something else would have to know how to use it. I could simply remove the iterator and order-level for SECTION_TEXT linker tables if we are sure we can't use it. The only gain then here would be that of saving custom linker script changes and having a unified way to represent the attributes.
If order is desired a structured data would would make more sense and I could document / recommend that, however I don't yet have a ported use case in mind yet, any ideas? The use case I have that follows similar logic is for the x86 init stuff which I am sending separately and that's a new use case though. It uses SECTION_INIT (.init.text) and that allows for both use of structuralized data + callbacks we can execute. It was not clear to me what section to use for this sort of stuff for non init stuff, and I can envision people highly wanting to use this to help clean up init paths on code, what sectoin should be used in those cases?
Luis
Re: [RFC v2 2/7] tables.h: add linker table support
Quoted 27 lines · Luis R. Rodriguez
Quoted 17 lines · H. Peter Anvin
Quoted 16 lines · Luis R. Rodriguez
include/linux/tables.h new file +16
-0+ +/** +* DOC: Regular linker linker table constructors +* +* Regular constructors are expected to be used for valid linker table entries. +* Valid uses of weak entries other than the beginning and is currently +* untested but should in theory work. +*/ + +/** +* LINKTABLE_TEXT - Declares a linker table entry for execution +* +* @name: linker table name +* @level: order level +* +* Declares a linker table to be used for execution. Quoted 8 lines
include/linux/tables.h line 424
Quoted 6 lines
+ */
include/linux/tables.h new file +5
-0+#define LINKTABLE_TEXT (name, level) \ + __typeof__(name[0]) \ + __attribute__((used, \ + __aligned__(LINKTABLE_ALIGNMENT(name)), \ + section(SECTION_TBL(SECTION_TEXT, name, level))))I'm really confused by this. Text should obviously be readonly,
Quoted 2 lines
So this uses
SECTION_TEXT, so we just pegged the linker table entry right below the standardSECTION_TEXT:
OK yes I see the issue now. I've modified this to use const, and retested the kprobe patch and it works well still. kprobe would not use LINKTABLE_TEXT, instead it uses its own macro, however users of LINKTABLE_TEXT would then have const declared. The implications are that you *can* declare structs so long as everything is const.
Folks may at times need to modify the structural definitions -- for that LINKTABLE_DATA() is more appropriate, and as per my testing it still allows execution of callbacks. I can document this.
Do we want .init.text to match this? I'd port my "struct x86_init_fn" to use LINKTABLE_INIT_DATA() then. FWIW below is a paste of a simple test program that demos what I mean.
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/tables.h>
static void stuff_todo(struct work_struct *work);
static DECLARE_WORK(stuff_work, stuff_todo);
struct stuff {
int a;
int b;
void (*print_a)(struct stuff *);
void (*print_b)(struct stuff *);
void (*print_a_ro)(const struct stuff *);
void (*print_b_ro)(const struct stuff *);
};
void print_a(struct stuff *s)
{pr_info("print_a a: %d\n", s->a);
}
void print_a_ro(const struct stuff *s)
{pr_info("print_a a: %d\n", s->a);
}
void print_b(struct stuff *s)
{pr_info("print_b b: %d\n", s->b);
}
void print_b_ro(const struct stuff *s)
{pr_info("print_b b: %d\n", s->b);
}
DEFINE_LINKTABLE_TEXT(struct stuff, my_stuff_fns_ro); DEFINE_LINKTABLE_DATA(struct stuff, my_stuff_fns);
static LINKTABLE_TEXT(my_stuff_fns_ro, 0000) stuff_a_ro = { .a = 1,
.b = 1,
.print_a_ro = print_a_ro,
.print_b_ro = print_b_ro,
};
static LINKTABLE_TEXT(my_stuff_fns_ro, 0000) stuff_b_ro = { .a = 2,
.b = 2,
.print_a_ro = print_a_ro,
.print_b_ro = print_b_ro,
};
static LINKTABLE_TEXT(my_stuff_fns_ro, 0000) stuff_c_ro = { .a = 3,
.b = 3,
.print_a_ro = print_a_ro,
.print_b_ro = print_b_ro,
};
static LINKTABLE_DATA(my_stuff_fns, 0000) stuff_a = { .a = 1,
.b = 1,
.print_a = print_a,
.print_b = print_b,
};
static LINKTABLE_DATA(my_stuff_fns, 0000) stuff_b = { .a = 2,
.b = 2,
.print_a = print_a,
.print_b = print_b,
};
static void stuff_todo(struct work_struct *work)
{
struct stuff *s;
const struct stuff *s_ro;
unsigned int i = 0;
pr_info("Looping over my_stuff_fns_ro\n");
LINKTABLE_FOR_EACH(s_ro, my_stuff_fns_ro) {pr_info("Looping on s ro %d\n", i++);s_ro->print_a_ro(s_ro);s_ro->print_b_ro(s_ro);
}
i=0;pr_info("Looping over my_stuff_fns\n");
LINKTABLE_FOR_EACH(s, my_stuff_fns) {pr_info("Looping on s %d\n", i++);s->print_a(s);s->print_b(s);
}
i=0;pr_info("Looping over my_stuff_fns and creating modifications\n");
LINKTABLE_FOR_EACH(s, my_stuff_fns) {s->a = 10;s->b = 10;s->print_a(s);s->print_b(s);
}
}
static int __init stuff_init(void)
{
/* get out of __init context */schedule_work(&stuff_work);
return 0;
}
static void __exit stuff_exit(void)
{cancel_work_sync(&stuff_work);
}
module_init(stuff_init)module_exit(stuff_exit)MODULE_LICENSE("GPL");
Luis
H. Peter Anvin
reviewerRe: [RFC v2 2/7] tables.h: add linker table support
Quoted 7 lines · Luis R. Rodriguez
OK yes I see the issue now. I've modified this to use const, and retested the kprobe patch and it works well still. kprobe would not use
LINKTABLE_TEXT, instead it uses its own macro, however users ofLINKTABLE_TEXTwould then have const declared. The implications are that you *can* declare structs so long as everything is const.
No, such structures belong in .rodata not in .text.
I have been thinking about it somewhat, and for text we really have text "ranges" rather than tables. The big difference between the two are:
1. priority ordering doesn't make any sense for ranges.
2. ranges can be hierarchial, that is, range "bar" can be entirely inside range "foo".
3. ranges aren't typed (although in C, that pretty much means they are "char" or "unsigned char" as there really isn't any way to define an "array of void".)
4. the only useful operator on a range is "is address X inside this range"; this operator is likely *not* useful for a table, since if you have to ever invoke it you are probably doing something very wrong.
For this to work, we need strings such that they will always sort in the appropriate order with the bracket symbols around subranges. I need to think about this a few minutes before I actually say anything about it...
-hpa
Re: [RFC v2 2/7] tables.h: add linker table support
Quoted 9 lines · H. Peter Anvin
Quoted 7 lines · Luis R. Rodriguez
OK yes I see the issue now. I've modified this to use const, and retested the kprobe patch and it works well still. kprobe would not use
LINKTABLE_TEXT, instead it uses its own macro, however users ofLINKTABLE_TEXTwould then have const declared. The implications are that you *can* declare structs so long as everything is const.
Quoted 6 lines
No, such structures belong in .rodata not in .text.
I have been thinking about it somewhat, and for text we really have text "ranges" rather than tables. The big difference between the two are:
1. priority ordering doesn't make any sense for ranges.
I considered the possibility perhaps we want to just split out a series of initial basic macros that enables *only* such basic functionality and declarations, and linker tables would then build on top of these. I think that ma help here.
Quoted 2 lines
2. ranges can be hierarchial, that is, range "bar" can be entirely inside range "foo".
We'd want to enable this without having to modify the linker script further -- I thought about how such things might be possible but not for this case but rather, for the case where in linker tables a developer may wish to get range addresses for a specific order level. Although separate, the problem seems similar. At least in theory I was convinced I had a solution to the order level problem, perhaps it may suffice for this too:
When and if you need an intermediary set of range addresses you then also declare another set of extern pointers, similar in nature with the empty string and ~ ending delimiter, we just move one notch in. SORT() will take care of ordering things for us, but the issue here is the empty string doesn't allow hierarchies so perhaps to enable that we may need another beginning delimiter that would enable recursive hierarchies. If this seems to at least in theory make sense I can give it a shot through a simple proof of concept and see if it works.
Quoted 3 lines
3. ranges aren't typed (although in C, that pretty much means they are "char" or "unsigned char" as there really isn't any way to define an "array of void".)
Sure. kprobe is a good example.
Quoted 4 lines
4. the only useful operator on a range is "is address X inside this range"; this operator is likely *not* useful for a table, since if you have to ever invoke it you are probably doing something very wrong.
kprobe uses it :P
Quoted 3 lines
For this to work, we need strings such that they will always sort in the appropriate order with the bracket symbols around subranges. I need to think about this a few minutes before I actually say anything about it...
Ah seems we're in the same line of thought ?
Luis
H. Peter Anvin
reviewerRe: [RFC v2 2/7] tables.h: add linker table support
Quoted 8 lines · Luis R. Rodriguez
Quoted 5 lines
4. the only useful operator on a range is "is address X inside this range"; this operator is likely *not* useful for a table, since if you have to ever invoke it you are probably doing something very wrong.
kprobe uses it :P
Could you explain how?
-hpa
Re: [RFC v2 2/7] tables.h: add linker table support
Quoted 4 lines · H. Peter Anvin
Quoted 3 lines · Luis R. Rodriguez
Quoted 3 lines
4. the only useful operator on a range is "is address X inside this range"; this operator is likely *not* useful for a table, since
^^^^^^^^^^^^
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
if you have to ever invoke it you are probably doing something very wrong.
kprobe uses it :P
Could you explain how?
Sorry I misread this as "unless you are a table", kprobes has two ranges, one is a table (blacklist) and the other just a range (for kprobes); only kprobes uses "address inside this range", as reflected below. So I agree with you.
index d10ab6b9b5e0..d816c659f358 100644
kernel/kprobes.c +1 -2
@@ -1328,8 +1328,7 @@ out:bool __weak arch_within_kprobe_blacklist (unsigned long addr) {/* The __kprobes marked functions and entry code must not be probed */ -return addr >= (unsigned long )__kprobes_text_start && - addr < (unsigned long )__kprobes_text_end; +return LINKTABLE_ADDR_WITHIN (kprobes, addr); }bool within_kprobe_blacklist (unsigned long addr)
kernel/kprobes.c +1 -2
@@ -1328,8 +1328,7 @@ out:bool __weak arch_within_kprobe_blacklist (unsigned long addr) {/* The __kprobes marked functions and entry code must not be probed */ -return addr >= (unsigned long )__kprobes_text_start && - addr < (unsigned long )__kprobes_text_end; +return LINKTABLE_ADDR_WITHIN (kprobes, addr); }
What about rebranding general section primitives under section.h
#define DECLARE_SECTION_TEXT_TYPE(type, name) \
extern const type name[], name##__end[];#define DECLARE_SECTION_TEXT(name) \
DECLARE_SECTION_TEXT_TYPE(char, name)
Then tables.h would use the TYPE version:
#define DECLARE_LINKTABLE_TEXT(type, name) \
DECLARE_SECTION_TEXT_TYPE(type, name)
Since I've been making _TEXT the implicit type for section names(SECTION_INIT is .init.text) the above could just be DECLARE_SECTION_TYPE() and DECLARE_SECTION() for text if we prefer.
Luis
H. Peter Anvin
reviewerRe: [RFC v2 2/7] tables.h: add linker table support
In reply to Luis R. RodriguezQuoted 9 lines · Luis R. Rodriguez
include/linux/tables.h new file +9
-0+/** +* LINKTABLE_RUN_ERR - run each linker table entry func and return error if any +* +* @tbl: linker table +* @func: structure name for the function name we want to call. +* @args...: arguments to pass to func +* +* Example usage: +*
include/linux/tables.h line 694
Quoted 10 lines
include/linux/tables.h new file +10
-0+* unsigned int err = LINKTABLE_RUN_ERR(frobnicator_fns, some_run,); +*/ +#define LINKTABLE_RUN_ERR(tbl, func, args...) \ +({ \ + size_t i; \ + int err = 0; \ + for (i = 0; !err && i < LINKTABLE_SIZE(tbl); i++) \ + err = (tbl[i]).func (args); \ + err; \ +})
This is wrong and pointless. As written it returns the error code of the last instance.
What I suggested for this macro was that we ought to exit the loop on error.
Furthermore:
1. Using an advancing pointer would make more sense than a counter.
2. .func doesn't make any sense -- it ought to be "func"; otherwise you
can't call into either a table containing pure function pointers,
nor into a field of table *pointed to* by the table; which is
likely to be quite common.
So the idea is to use something like:
/* Array of function pointers */
LINKTABLE_RUN_ALL(frobnicator_fns, , arg1, arg2);
/* Array of structures */
LINKTABLE_RUN_ALL(frobnicator_fns, .some_run, arg1, arg2);
/* Array of structure pointers */
LINKTABLE_RUN_ALL(frobnicator_fns, ->some_run, arg1, arg2);Re: [RFC v2 2/7] tables.h: add linker table support
Quoted 24 lines · H. Peter Anvin
Quoted 9 lines · Luis R. Rodriguez
include/linux/tables.h new file +9
-0+/** +* LINKTABLE_RUN_ERR - run each linker table entry func and return error if any +* +* @tbl: linker table +* @func: structure name for the function name we want to call. +* @args...: arguments to pass to func +* +* Example usage: +* include/linux/tables.h line 694
Quoted 10 lines
include/linux/tables.h new file +10
-0+* unsigned int err = LINKTABLE_RUN_ERR(frobnicator_fns, some_run,); +*/ +#define LINKTABLE_RUN_ERR(tbl, func, args...) \ +({ \ + size_t i; \ + int err = 0; \ + for (i = 0; !err && i < LINKTABLE_SIZE(tbl); i++) \ + err = (tbl[i]).func (args); \ + err; \ +})This is wrong and pointless. As written it returns the error code of the last instance.
Quoted 5 lines
What I suggested for this macro was that we ought to exit the loop on error.
Furthermore:
1. Using an advancing pointer would make more sense than a counter.
OK I'll modify to use LINKTABLE_FOR_EACH and much cleaner and obvious code to bail on error.
Quoted 15 lines
2. .func doesn't make any sense -- it ought to be "func"; otherwise you
can't call into either a table containing pure function pointers, nor into a field of table *pointed to* by the table; which is likely to be quite common. So the idea is to use something like: /* Array of function pointers */ LINKTABLE_RUN_ALL(frobnicator_fns, , arg1, arg2); /* Array of structures */ LINKTABLE_RUN_ALL(frobnicator_fns, .some_run, arg1, arg2); /* Array of structure pointers */ LINKTABLE_RUN_ALL(frobnicator_fns, ->some_run, arg1, arg2);
Ah that's sexy, thanks. Will amend.
Luis
RFC v2 3/7 firmware: port built-in section to linker table
In reply to Luis R. RodriguezThis ports built-in firmware to use linker tables, this replaces the custom section solution with a generic solution.
This also demos the use of the .rodata (SECTION_RO) linker tables.
Tested with 0 built-in firmware, 1 and 2 built-in
firmwares successfully.
--- arch/x86/kernel/cpu/microcode/core.c | 7 +++---- drivers/base/firmware_class.c | 11 +++++------ firmware/Makefile | 2 +- include/asm-generic/vmlinux.lds.h | 7 ------- 4 files changed, 9 insertions(+), 18 deletions(-)
arch/x86/kernel/cpu/microcode/core.c +3 -4
@@ -99,15 +99,14 @@ static bool __init check_loader_disabled_bsp(void)return *res; } -extern struct builtin_fw __start_builtin_fw[]; -extern struct builtin_fw __end_builtin_fw[]; +DECLARE_LINKTABLE_RO(struct builtin_fw, builtin_fw);bool get_builtin_firmware (struct cpio_data *cd,const char *name) {#ifdef CONFIG_FW_LOADER -struct builtin_fw *b_fw; +const struct builtin_fw *b_fw; -for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) { + LINKTABLE_FOR_EACH(b_fw, builtin_fw) {if (!strcmp (name, b_fw->name)) { cd->size = b_fw->size; cd->data = b_fw->data;
drivers/base/firmware_class.c +5 -6
@@ -42,14 +42,13 @@ MODULE_LICENSE("GPL");#ifdef CONFIG_FW_LOADER -extern struct builtin_fw __start_builtin_fw[]; -extern struct builtin_fw __end_builtin_fw[]; +DEFINE_LINKTABLE_RO(struct builtin_fw, builtin_fw);static bool fw_get_builtin_firmware (struct firmware *fw,const char *name) { -struct builtin_fw *b_fw; +const struct builtin_fw *b_fw; -for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) { + LINKTABLE_FOR_EACH(b_fw, builtin_fw) {if (strcmp (name, b_fw->name) ==0 ) { fw->size = b_fw->size; fw->data = b_fw->data;
@@ -62,9 +61,9 @@ static bool fw_get_builtin_firmware(struct firmware *fw, const char *name)static bool fw_is_builtin_firmware (const struct firmware *fw) { -struct builtin_fw *b_fw; +const struct builtin_fw *b_fw; -for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) + LINKTABLE_FOR_EACH(b_fw, builtin_fw)if (fw->data == b_fw->data)return true;
firmware/Makefile +1 -1
@@ -164,7 +164,7 @@ quiet_cmd_fwbin = MK_FW $@ echo " .p2align $${ASM_ALIGN}" >>$@;\ echo "_fw_$${FWSTR}_name:" >>$@;\ echo " .string \"$$FWNAME\"" >>$@;\ - echo " .section .builtin_fw,\"a\",$${PROGBITS}" >>$@;\ + echo " .section .rodata.tbl.builtin_fw.all,\"a\",$${PROGBITS}" >>$@;\ echo " .p2align $${ASM_ALIGN}" >>$@;\ echo " $${ASM_WORD} _fw_$${FWSTR}_name" >>$@;\ echo " $${ASM_WORD} _fw_$${FWSTR}_bin" >>$@;\
include/asm-generic/vmlinux.lds.h +0 -7
@@ -302,13 +302,6 @@ VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \ } \ \ -/* Built-in firmware blobs */ \ - .builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start_builtin_fw) = .; \ - *(.builtin_fw) \ - VMLINUX_SYMBOL(__end_builtin_fw) = .; \ - } \ - \TRACEDATA \ \/* Kernel symbol table: Normal symbols */ \
Signature · 1 line
2.7.0
Re: [RFC v2 3/7] firmware: port built-in section to linker table
Quoted 9 lines · Luis R. Rodriguez
This ports built-in firmware to use linker tables, this replaces the custom section solution with a generic solution.
This also demos the use of the .rodata (
SECTION_RO) linker tables.Tested with 0 built-in firmware, 1 and 2 built-in
firmwares successfully.
I think we'd do better to rip this support out entirely. It just isn't needed; firmware can live in an initramfs and don't even need *any* actual running userspace support to load it from there these days, do we?
Signature · 1 line
dwmw2
Re: [RFC v2 3/7] firmware: port built-in section to linker table
Quoted 8 lines · David Woodhouse
Quoted 7 lines · Luis R. Rodriguez
This ports built-in firmware to use linker tables, this replaces the custom section solution with a generic solution.
This also demos the use of the .rodata (
SECTION_RO) linker tables.
Quoted 7 lines
Quoted 2 lines
Tested with 0 built-in firmware, 1 and 2 built-in
firmwares successfully.I think we'd do better to rip this support out entirely. It just isn't needed; firmware can live in an initramfs and don't even need *any* actual running userspace support to load it from there these days, do we?
I think this is reasonable if and only if we really don't know of anyone out there not able to use initramfs. I'm happy to rip it out.
Luis
Re: [RFC v2 3/7] firmware: port built-in section to linker table
Quoted 12 lines · Luis R. Rodriguez
Quoted 11 lines · David Woodhouse
Quoted 9 lines · Luis R. Rodriguez
This ports built-in firmware to use linker tables, this replaces the custom section solution with a generic solution.
This also demos the use of the .rodata (
SECTION_RO) linker tables.Tested with 0 built-in firmware, 1 and 2 built-in
firmwares successfully.
Quoted 7 lines
Quoted 4 lines
I think we'd do better to rip this support out entirely. It just isn't needed; firmware can live in an initramfs and don't even need *any* actual running userspace support to load it from there these days, do we?
I think this is reasonable if and only if we really don't know of anyone out there not able to use initramfs. I'm happy to rip it out.
The changelog for this doesn't say anything about _why_ the change is being made? (and what about other architectures.) Also, Chrome OS doesn't use an initramfs (and plenty of other things don't too). Being able to build monolithic kernels (e.g. Android and Brillo) with builtin firmware is very handy. Please don't remove built-in firmware support.
-Kees
Signature · 2 lines
Kees Cook Chrome OS & Brillo Security
Greg KH
maintainerRe: [RFC v2 3/7] firmware: port built-in section to linker table
Quoted 21 lines · Kees Cook
Quoted 12 lines · Luis R. Rodriguez
Quoted 11 lines · David Woodhouse
Quoted 9 lines · Luis R. Rodriguez
This ports built-in firmware to use linker tables, this replaces the custom section solution with a generic solution.
This also demos the use of the .rodata (
SECTION_RO) linker tables.Tested with 0 built-in firmware, 1 and 2 built-in
firmwares successfully.Quoted 7 lines
Quoted 4 lines
I think we'd do better to rip this support out entirely. It just isn't needed; firmware can live in an initramfs and don't even need *any* actual running userspace support to load it from there these days, do we?
I think this is reasonable if and only if we really don't know of anyone out there not able to use initramfs. I'm happy to rip it out.
Quoted 6 lines
The changelog for this doesn't say anything about _why_ the change is being made? (and what about other architectures.) Also, Chrome OS doesn't use an initramfs (and plenty of other things don't too). Being able to build monolithic kernels (e.g. Android and Brillo) with builtin firmware is very handy. Please don't remove built-in firmware support.
I second this, we can't break existing systems at all. I thought we were going to keep built-in firmware, right Luis?
thanks,
greg k-h
Re: [RFC v2 3/7] firmware: port built-in section to linker table
Quoted 29 lines · Greg KH
Quoted 21 lines · Kees Cook
Quoted 12 lines · Luis R. Rodriguez
Quoted 11 lines · David Woodhouse
Quoted 9 lines · Luis R. Rodriguez
This ports built-in firmware to use linker tables, this replaces the custom section solution with a generic solution.
This also demos the use of the .rodata (
SECTION_RO) linker tables.Tested with 0 built-in firmware, 1 and 2 built-in
firmwares successfully.Quoted 7 lines
Quoted 4 lines
I think we'd do better to rip this support out entirely. It just isn't needed; firmware can live in an initramfs and don't even need *any* actual running userspace support to load it from there these days, do we?
I think this is reasonable if and only if we really don't know of anyone out there not able to use initramfs. I'm happy to rip it out.
Quoted 6 lines
The changelog for this doesn't say anything about _why_ the change is being made? (and what about other architectures.) Also, Chrome OS doesn't use an initramfs (and plenty of other things don't too). Being able to build monolithic kernels (e.g. Android and Brillo) with builtin firmware is very handy. Please don't remove built-in firmware support.
Quoted 2 lines
I second this, we can't break existing systems at all. I thought we were going to keep built-in firmware, right Luis?
Removing built-in firmware was simply a suggestion by David which we were evaluating here -- patches were not even yet produced, although I have them now if we wanted to rip it out. Since Kees noted it has users, we'll keep it.
Luis
Re: [RFC v2 3/7] firmware: port built-in section to linker table
In reply to Kees CookQuoted 18 lines · Kees Cook
Quoted 17 lines · Luis R. Rodriguez
Quoted 15 lines · David Woodhouse
Quoted 9 lines · Luis R. Rodriguez
This ports built-in firmware to use linker tables, this replaces the custom section solution with a generic solution.
This also demos the use of the .rodata (
SECTION_RO) linker tables.Tested with 0 built-in firmware, 1 and 2 built-in
firmwares successfully.I think we'd do better to rip this support out entirely. It just isn't needed; firmware can live in an initramfs and don't even need *any* actual running userspace support to load it from there these days, do we?
Quoted 5 lines
Quoted 2 lines
I think this is reasonable if and only if we really don't know of anyone out there not able to use initramfs. I'm happy to rip it out.
The changelog for this doesn't say anything about _why_ the change is being made? (and what about other architectures.)
To be clear the RFC patch here is about linker table use and porting custom table uses for a generic linker table solution. The topic of conversation later changed to suggest that instead of porting built-in firmware to linker tables we should just consider removing built-in firmware all together. As for the reason _why_ we'd port built-in firmware to linker tables, I'll be sure to add that in the next iteration. The reason is that Linux has scattered strategies to both extend and use custom linker sections, often requiring modifying the custom linker script. The effort behind the linker script provides a unified mechanism to do this, and also enables us to avoid having to extend the custom linker script for this type of use.
Quoted 5 lines
Also, Chrome OS
doesn't use an initramfs (and plenty of other things don't too). Being able to build monolithic kernels (e.g. Android and Brillo) with builtin firmware is very handy. Please don't remove built-in firmware support.
Thanks! Can you confirm if any Android or Brillo builds are already using it?
Luis
Re: [RFC v2 3/7] firmware: port built-in section to linker table
Quoted 1 line · Luis R. Rodriguez
Thanks! Can you confirm if any Android or Brillo builds are already using it?
Also more importantly, any chance you can provide any technical reasons why initramfs cannot be used, or it was decided to not use it on these systems? It should help others in the future as well.
Luis
Re: [RFC v2 3/7] firmware: port built-in section to linker table
Quoted 1 line · Luis R. Rodriguez
or it was decided
Sorry I meant to say: 'or _why_ it was decided to not use initramfs on these systems?'
Luis
Re: [RFC v2 3/7] firmware: port built-in section to linker table
In reply to Luis R. RodriguezQuoted 6 lines · Luis R. Rodriguez
Quoted 1 line · Luis R. Rodriguez
Thanks! Can you confirm if any Android or Brillo builds are already using it?
Also more importantly, any chance you can provide any technical reasons why initramfs cannot be used, or it was decided to not use it on these systems? It should help others in the future as well.
In Chrome OS, the kernels are built specifically for the hardware they're going to be on, so an initramfs was seen as a needless additional boot step. Since Chrome OS was heavily optimized for boot speed, it was designed to not need the initramfs at all. This is actually enforced by the read-only boot firmware, so there's no trivial way to _start_ using an initramfs on (existing) Chrome OS devices either.
-Kees
Signature · 2 lines
Kees Cook Chrome OS & Brillo Security
Greg KH
maintainerRe: [RFC v2 3/7] firmware: port built-in section to linker table
In reply to Luis R. RodriguezQuoted 6 lines · Luis R. Rodriguez
Quoted 1 line · Luis R. Rodriguez
Thanks! Can you confirm if any Android or Brillo builds are already using it?
Also more importantly, any chance you can provide any technical reasons why initramfs cannot be used, or it was decided to not use it on these systems? It should help others in the future as well.
Some systems just don't need it, nor want it. We can't break working systems, so this is not something we can remove, sorry.
thanks,
greg k-h
James Bottomley
maintainerRe: [RFC v2 3/7] firmware: port built-in section to linker table
In reply to David WoodhouseQuoted 8 lines · David Woodhouse
Quoted 7 lines · Luis R. Rodriguez
This ports built-in firmware to use linker tables, this replaces the custom section solution with a generic solution.
This also demos the use of the .rodata (
SECTION_RO) linker tables.
Quoted 7 lines
Quoted 2 lines
Tested with 0 built-in firmware, 1 and 2 built-in
firmwares successfully.I think we'd do better to rip this support out entirely. It just isn't needed; firmware can live in an initramfs and don't even need *any* actual running userspace support to load it from there these days, do we?
We have lots of SCSI drivers with built in firmware. The obvious examples are 53c700, aic7xxx and aic79xx. For them, we actually have the firmware compilers in tree. The firmware model they use just isn't amenable to the firmware loader: they're not monolithic blobs, it's a set of firmware scripts we use to handle particular operations before giving control back to the host, so the firmware and the driver are very much symbiotic.
On the other hand, I don't think any of them uses firmware sections, so it's not an argument for not ripping out this type.
James
Re: [RFC v2 3/7] firmware: port built-in section to linker table
Quoted 17 lines · James Bottomley
Quoted 8 lines · David Woodhouse
Quoted 7 lines · Luis R. Rodriguez
This ports built-in firmware to use linker tables, this replaces the custom section solution with a generic solution.
This also demos the use of the .rodata (
SECTION_RO) linker tables.Quoted 7 lines
Quoted 2 lines
Tested with 0 built-in firmware, 1 and 2 built-in
firmwares successfully.I think we'd do better to rip this support out entirely. It just isn't needed; firmware can live in an initramfs and don't even need *any* actual running userspace support to load it from there these days, do we?
Quoted 7 lines
We have lots of SCSI drivers with built in firmware. The obvious examples are 53c700, aic7xxx and aic79xx. For them, we actually have the firmware compilers in tree. The firmware model they use just isn't amenable to the firmware loader: they're not monolithic blobs, it's a set of firmware scripts we use to handle particular operations before giving control back to the host, so the firmware and the driver are very much symbiotic.
I'm in the process of doing some other cleanups with the firmware_class stuff so that odd requirements get supported but clean interfaces are also not hampered by these odd requirements, so I'll take a look at this later. If you have other oddball firmware requirements please let me know so I can also keep in mind.
Quoted 2 lines
On the other hand, I don't think any of them uses firmware sections, so it's not an argument for not ripping out this type.
Thanks for confirming. I'll rip this out.
Luis
Re: [RFC v2 3/7] firmware: port built-in section to linker table
Quoted 32 lines · Luis R. Rodriguez
Quoted 17 lines · James Bottomley
Quoted 8 lines · David Woodhouse
Quoted 7 lines · Luis R. Rodriguez
This ports built-in firmware to use linker tables, this replaces the custom section solution with a generic solution.
This also demos the use of the .rodata (
SECTION_RO) linker tables.Quoted 7 lines
Quoted 2 lines
Tested with 0 built-in firmware, 1 and 2 built-in
firmwares successfully.I think we'd do better to rip this support out entirely. It just isn't needed; firmware can live in an initramfs and don't even need *any* actual running userspace support to load it from there these days, do we?
Quoted 7 lines
We have lots of SCSI drivers with built in firmware. The obvious examples are 53c700, aic7xxx and aic79xx. For them, we actually have the firmware compilers in tree. The firmware model they use just isn't amenable to the firmware loader: they're not monolithic blobs, it's a set of firmware scripts we use to handle particular operations before giving control back to the host, so the firmware and the driver are very much symbiotic.
I'm in the process of doing some other cleanups with the
firmware_classstuff so that odd requirements get supported but clean interfaces are also not hampered by these odd requirements, so I'll take a look at this later. If you have other oddball firmware requirements please let me know so I can also keep in mind.
Quoted 4 lines
Quoted 2 lines
On the other hand, I don't think any of them uses firmware sections, so it's not an argument for not ripping out this type.
Thanks for confirming. I'll rip this out.
Just a heads up, I've put the removal through 0-day without issues, I'll be folding the removal into another series of changes for the firmware API which should help compartmentalize the user mode helper stuff as well.
Luis
RFC v2 4/7 asm/sections: add a generic push_section_tbl()
In reply to Luis R. RodriguezWith a generic linker tables solution in place we need a general asm solution for declaring entries with asm. The first easy target is to cover the C asm declarations, guard the header file for now and define a first generic entry push_section_tbl() to be used later for custom linker table annotations.
--- include/asm-generic/sections.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
include/asm-generic/sections.h +10 -0
@@ -3,8 +3,10 @@/* References to section boundaries */ +#ifndef __ASSEMBLY__#include <linux/compiler.h> #include <linux/types.h> +#include <linux/sections.h> /* * Usage guidelines:
@@ -128,4 +130,12 @@ static inline bool init_section_intersects(void *virt, size_t size)return memory_intersects (__init_begin, __init_end, virt, size); } +/* +* Some architectures do not like the "\t" at the end (s39), we should be +* able to generalize this further, but so far this covers most architectures. +*/ +#define push_section_tbl (section, name, level, flags) \ + ".pushsection " SECTION_TBL(section,name,level) ", \"" #flags "\"\n\t" +#endif +#endif /* _ASM_GENERIC_SECTIONS_H_ */
Signature · 1 line
2.7.0
H. Peter Anvin
reviewerRe: [RFC v2 4/7] asm/sections: add a generic push_section_tbl()
Quoted 29 lines · Luis R. Rodriguez
With a generic linker tables solution in place we need a general asm solution for declaring entries with asm. The first easy target is to cover the C asm declarations, guard the header file for now and define a first generic entry
push_section_tbl()to be used later for custom linker table annotations.Signed-off-by Luis R. Rodriguez <[email protected]>--- include/asm-generic/sections.h | 10 ++++++++++ 1 file changed, 10 insertions(+)include/asm-generic/sections.h +2
-0@@ -3,8 +3,10 @@/* References to section boundaries */ +#ifndef __ASSEMBLY__#include <linux/compiler.h> #include <linux/types.h> +#include <linux/sections.h> /* * Usage guidelines: @@ -128,4 +130,12 @@ static inline bool init_section_intersects(void *virt, size_t size)return memory_intersects (__init_begin, __init_end, virt, size);
include/asm-generic/sections.h static inline bool init_section_intersects(void *virt, size_t size) · line 140
Quoted 10 lines
include/asm-generic/sections.h +8
-0} +/* +* Some architectures do not like the "\t" at the end (s39), we should be +* able to generalize this further, but so far this covers most architectures. +*/ +#define push_section_tbl (section, name, level, flags) \ + ".pushsection " SECTION_TBL(section,name,level) ", \"" #flags "\"\n\t" +#endif +
I think the \n\t is unnecessary.
-hpa
Re: [RFC v2 4/7] asm/sections: add a generic push_section_tbl()
Quoted 32 lines · H. Peter Anvin
Quoted 31 lines · Luis R. Rodriguez
With a generic linker tables solution in place we need a general asm solution for declaring entries with asm. The first easy target is to cover the C asm declarations, guard the header file for now and define a first generic entry
push_section_tbl()to be used later for custom linker table annotations.Signed-off-by Luis R. Rodriguez <[email protected]>--- include/asm-generic/sections.h | 10 ++++++++++ 1 file changed, 10 insertions(+)include/asm-generic/sections.h +2
-0@@ -3,8 +3,10 @@/* References to section boundaries */ +#ifndef __ASSEMBLY__#include <linux/compiler.h> #include <linux/types.h> +#include <linux/sections.h> /* * Usage guidelines: @@ -128,4 +130,12 @@ static inline bool init_section_intersects(void *virt, size_t size)return memory_intersects (__init_begin, __init_end, virt, size); }
Quoted 10 lines
include/asm-generic/sections.h static inline bool init_section_intersects(void *virt, size_t size) · line 140
Quoted 8 lines
include/asm-generic/sections.h +8
-0+/* +* Some architectures do not like the "\t" at the end (s39), we should be +* able to generalize this further, but so far this covers most architectures. +*/ +#define push_section_tbl (section, name, level, flags) \ + ".pushsection " SECTION_TBL(section,name,level) ", \"" #flags "\"\n\t" +#endif +I think the \n\t is unnecessary.
Super! I wonder if we we can just use this on s390 as well without it pooping? I ask as this would set a precedent.
Luis
H. Peter Anvin
reviewerRe: [RFC v2 4/7] asm/sections: add a generic push_section_tbl()
Quoted 6 lines · Luis R. Rodriguez
Quoted 2 lines
I think the \n\t is unnecessary.
Super! I wonder if we we can just use this on s390 as well without it pooping? I ask as this would set a precedent.
Ask Heike, but I think just ; or \n ought be be fine. I do not know of *any* case where \t at the end of a string would ever be necessary, and it would *always* be possible to replace it with a space in a pinch.
-hpa
Re: [RFC v2 4/7] asm/sections: add a generic push_section_tbl()
Quoted 11 lines · H. Peter Anvin
Quoted 6 lines · Luis R. Rodriguez
Quoted 2 lines
I think the \n\t is unnecessary.
Super! I wonder if we we can just use this on s390 as well without it pooping? I ask as this would set a precedent.
Ask Heike, but I think just ; or \n ought be be fine. I do not know of *any* case where \t at the end of a string would ever be necessary, and it would *always* be possible to replace it with a space in a pinch.
\n should be fine on s390.
Re: [RFC v2 4/7] asm/sections: add a generic push_section_tbl()
Quoted 9 lines · Heiko Carstens
Quoted 8 lines · H. Peter Anvin
Quoted 6 lines · Luis R. Rodriguez
Quoted 2 lines
I think the \n\t is unnecessary.
Super! I wonder if we we can just use this on s390 as well without it pooping? I ask as this would set a precedent.
Quoted 5 lines
Quoted 3 lines
Ask Heike, but I think just ; or \n ought be be fine. I do not know of *any* case where \t at the end of a string would ever be necessary, and it would *always* be possible to replace it with a space in a pinch.
\n should be fine on s390.
Great, thanks, I'll move forward with just \n in v3.
Luis
RFC v2 5/7 jump_label: port __jump_table to linker tables
In reply to Luis R. RodriguezMove the __jump_table from the a custom section solution to a generic solution, this avoiding extra vmlinux.lds.h customizations.
This also demos the use of the .data (SECTION_DATA) linker tables and of push_section_tbl().
--- arch/arm/include/asm/jump_label.h | 4 ++-- arch/arm64/include/asm/jump_label.h | 4 ++-- arch/mips/include/asm/jump_label.h | 4 ++-- arch/powerpc/include/asm/jump_label.h | 6 +++--- arch/s390/include/asm/jump_label.h | 4 ++-- arch/sparc/include/asm/jump_label.h | 4 ++-- arch/x86/include/asm/jump_label.h | 9 +++++---- include/asm-generic/vmlinux.lds.h | 4 ---- include/linux/jump_label.h | 5 +++-- kernel/jump_label.c | 16 +++++++++------- kernel/module.c | 4 +++- 11 files changed, 33 insertions(+), 31 deletions(-)
arch/arm/include/asm/jump_label.h +2 -2
@@ -12,7 +12,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran { asm_volatile_goto("1:\n\t" WASM(nop) "\n\t" - ".pushsection __jump_table, \"aw\"\n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw) ".word 1b, %l[l_yes], %c0\n\t" ".popsection\n\t" : : "i" (&((char *)key)[branch]) : : l_yes);
@@ -26,7 +26,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool { asm_volatile_goto("1:\n\t" WASM(b) " %l[l_yes]\n\t" - ".pushsection __jump_table, \"aw\"\n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw) ".word 1b, %l[l_yes], %c0\n\t" ".popsection\n\t" : : "i" (&((char *)key)[branch]) : : l_yes);
arch/arm64/include/asm/jump_label.h +2 -2
@@ -29,7 +29,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool branch) { asm goto("1: nop\n\t" -".pushsection __jump_table, \"aw\"\n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw)".align 3\n\t" ".quad 1b, %l[l_yes], %c0\n\t" ".popsection\n\t"
@@ -43,7 +43,7 @@ l_yes: static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) { asm goto("1: b %l[l_yes]\n\t" -".pushsection __jump_table, \"aw\"\n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw)".align 3\n\t" ".quad 1b, %l[l_yes], %c0\n\t" ".popsection\n\t"
arch/mips/include/asm/jump_label.h +2 -2
@@ -30,7 +30,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran { asm_volatile_goto("1:\t" NOP_INSN "\n\t" "nop\n\t" - ".pushsection __jump_table, \"aw\"\n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw) WORD_INSN " 1b, %l[l_yes], %0\n\t" ".popsection\n\t" : : "i" (&((char *)key)[branch]) : : l_yes);
@@ -44,7 +44,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool { asm_volatile_goto("1:\tj %l[l_yes]\n\t" "nop\n\t" - ".pushsection __jump_table, \"aw\"\n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw) WORD_INSN " 1b, %l[l_yes], %0\n\t" ".popsection\n\t" : : "i" (&((char *)key)[branch]) : : l_yes);
arch/powerpc/include/asm/jump_label.h +3 -3
@@ -22,7 +22,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran { asm_volatile_goto("1:\n\t" "nop\n\t" - ".pushsection __jump_table, \"aw\"\n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw) JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t" ".popsection \n\t" : : "i" (&((char *)key)[branch]) : : l_yes);
@@ -36,7 +36,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool { asm_volatile_goto("1:\n\t" "b %l[l_yes]\n\t" - ".pushsection __jump_table, \"aw\"\n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw) JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t" ".popsection \n\t" : : "i" (&((char *)key)[branch]) : : l_yes);
@@ -61,7 +61,7 @@ struct jump_entry {#else #define ARCH_STATIC_BRANCH (LABEL ,KEY ) \ 1098: nop; \ - .pushsection __jump_table, "aw"; \ + .pushsection .data.tbl.__jump_table.all, "aw"; \ FTR_ENTRY_LONG 1098b, LABEL, KEY; \ .popsection#endif
arch/s390/include/asm/jump_label.h +2 -2
@@ -15,7 +15,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool branch) { asm_volatile_goto("0: brcl 0,"__stringify(JUMP_LABEL_NOP_OFFSET)"\n" -".pushsection __jump_table, \"aw\"\n" +".pushsection .data.tbl.__jump_table.all, \"aw\"\n" ".balign 8\n" ".quad 0b, %l[label], %0\n" ".popsection\n"
@@ -29,7 +29,7 @@ label: static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) {asm_volatile_goto ("0: brcl 15, %l[label]\n" -".pushsection __jump_table, \"aw\"\n" +".pushsection .data.tbl.__jump_table.all, \"aw\"\n" ".balign 8\n" ".quad 0b, %l[label], %0\n" ".popsection\n"
arch/sparc/include/asm/jump_label.h +2 -2
@@ -12,7 +12,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran asm_volatile_goto("1:\n\t" "nop\n\t" "nop\n\t" -".pushsection __jump_table, \"aw\"\n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw)".align 4\n\t" ".word 1b, %l[l_yes], %c0\n\t" ".popsection \n\t"
@@ -28,7 +28,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool asm_volatile_goto("1:\n\t" "b %l[l_yes]\n\t" "nop\n\t" -".pushsection __jump_table, \"aw\"\n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw)".align 4\n\t" ".word 1b, %l[l_yes], %c0\n\t" ".popsection \n\t"
arch/x86/include/asm/jump_label.h +5 -4
@@ -29,12 +29,13 @@#include <linux/stringify.h> #include <linux/types.h> +#include <asm-generic/sections.h> static __always_inline bool arch_static_branch(struct static_key *key, bool branch) { asm_volatile_goto("1:" ".byte " __stringify(STATIC_KEY_INIT_NOP) "\n\t" -".pushsection __jump_table, \"aw\" \n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw) _ASM_ALIGN"\n\t" _ASM_PTR"1b, %l[l_yes], %c0 + %c1 \n\t" ".popsection \n\t"
@@ -50,7 +51,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key *key, bool asm_volatile_goto("1:" ".byte 0xe9\n\t .long %l[l_yes] - 2f\n\t" "2:\n\t" -".pushsection __jump_table, \"aw\" \n\t" + push_section_tbl(SECTION_DATA, __jump_table, all, aw) _ASM_ALIGN"\n\t" _ASM_PTR"1b, %l[l_yes], %c0 + %c1 \n\t" ".popsection \n\t"
@@ -85,7 +86,7 @@ struct jump_entry { .else .byte STATIC_KEY_INIT_NOP .endif - .pushsection __jump_table, "aw" + .pushsection .data.tbl.__jump_table.all,"aw" _ASM_ALIGN _ASM_PTR .Lstatic_jump_\@, \target, \key .popsection
@@ -101,7 +102,7 @@ struct jump_entry { .long \target - .Lstatic_jump_after_\@ .Lstatic_jump_after_\@: .endif - .pushsection __jump_table, "aw" + .pushsection .data.tbl.__jump_table.all, "aw" _ASM_ALIGN _ASM_PTR .Lstatic_jump_\@, \target, \key + 1 .popsection
include/asm-generic/vmlinux.lds.h +0 -4
@@ -210,10 +210,6 @@STRUCT_ALIGN (); \ *(__tracepoints) \/* implement dynamic printk debug */ \ - . = ALIGN(8); \ - VMLINUX_SYMBOL(__start___jump_table) = .; \ - *(__jump_table ) \ - VMLINUX_SYMBOL(__stop___jump_table) = .; \ . = ALIGN(8); \ VMLINUX_SYMBOL(__start___verbose) = .; \ *(__verbose) \
include/linux/jump_label.h +3 -2
@@ -1,6 +1,8 @@#ifndef _LINUX_JUMP_LABEL_H#define _LINUX_JUMP_LABEL_H +#include <linux/tables.h> +/* * Jump label support *
@@ -138,8 +140,7 @@ static __always_inline bool static_key_true(struct static_key *key)return !arch_static_branch (key, true); } -extern struct jump_entry __start___jump_table[]; -extern struct jump_entry __stop___jump_table[]; +DECLARE_LINKTABLE_DATA(struct jump_entry, __jump_table);extern void jump_label_init (void );extern void jump_label_lock (void );
kernel/jump_label.c +9 -7
@@ -17,6 +17,8 @@#ifdef HAVE_JUMP_LABEL +DEFINE_LINKTABLE_DATA(struct jump_entry, __jump_table); +/* mutex to protect coming/going of the the jump_label table */ static DEFINE_MUTEX (jump_label_mutex);
@@ -200,15 +202,14 @@ static void __jump_label_update(struct static_key *key,void __init jump_label_init (void ) { -struct jump_entry *iter_start = __start___jump_table; -struct jump_entry *iter_stop = __stop___jump_table;struct static_key *key =NULL ;struct jump_entry *iter;jump_label_lock (); -jump_label_sort_entries (iter_start, iter_stop); +jump_label_sort_entries (LINKTABLE_START (__jump_table), +LINKTABLE_END (__jump_table)); -for (iter = iter_start; iter < iter_stop; iter++) { + LINKTABLE_FOR_EACH(iter, __jump_table) {struct static_key *iterk;/* rewrite NOPs */
@@ -450,8 +451,9 @@ early_initcall(jump_label_init_module);*/ int jump_label_text_reserved (void *start,void *end) { -int ret =__jump_label_text_reserved (__start___jump_table, - __stop___jump_table, start, end); +int ret =__jump_label_text_reserved (LINKTABLE_START (__jump_table), +LINKTABLE_END (__jump_table), + start, end);if (ret)return ret;
@@ -464,7 +466,7 @@ int jump_label_text_reserved(void *start, void *end)static void jump_label_update (struct static_key *key) { -struct jump_entry *stop = __stop___jump_table; +struct jump_entry *stop =LINKTABLE_END (__jump_table);struct jump_entry *entry =static_key_entries (key);#ifdef CONFIG_MODULES struct module *mod;
kernel/module.c +3 -1
@@ -2930,7 +2930,9 @@ static int find_module_sections(struct module *mod, struct load_info *info) &mod->num_tracepoints);#endif #ifdef HAVE_JUMP_LABEL - mod->jump_entries =section_objs (info,"__jump_table" , + mod->jump_entries =section_objs (info, +SECTION_TBL (SECTION_DATA , + __jump_table,),sizeof (*mod->jump_entries), &mod->num_jump_entries);#endif
Signature · 1 line
2.7.0
RFC v2 6/7 dynamic_debug: port to use linker tables
In reply to Luis R. RodriguezThis removes the custom vmlinux.lds.h hacks and uses the generalized solution for .data (SECTION_DATA) entries.
This is much more potential for further fine tuning here though in the future. For instance, linker tables enable an extra postfix for order level annotations, this could easily be used as the KBUILD_MODNAME and with a bit of linker table changes we may be able to get a direct O(1) count of the entries for that KBUILD_MODNAME: it would just be a count on the number of entries for the given order level. This should help make dynamic_debug_init() cleaner and also reduce the amount of time it takes at boot time. Instead of iterating over each print until we have all for a KBUILD_MODNAME, we'd instead directly operate on each KBUILD_MODNAME directly.
Tested dynamic debug with dyndbg query ana debugfs control and it works as expected.
--- include/asm-generic/vmlinux.lds.h | 5 ----- include/linux/dynamic_debug.h | 6 ++++-- kernel/module.c | 2 +- lib/dynamic_debug.c | 13 ++++++------- 4 files changed, 11 insertions(+), 15 deletions(-)
include/asm-generic/vmlinux.lds.h +0 -5
@@ -209,11 +209,6 @@ *(.data.unlikely) \STRUCT_ALIGN (); \ *(__tracepoints ) \ -/* implement dynamic printk debug */ \ - . = ALIGN(8); \ - VMLINUX_SYMBOL(__start___verbose) = .; \ - *(__verbose ) \ - VMLINUX_SYMBOL(__stop___verbose) = .; \ LIKELY_PROFILE() \ BRANCH_PROFILE() \TRACE_PRINTKS () \
include/linux/dynamic_debug.h +4 -2
@@ -1,6 +1,8 @@#ifndef _DYNAMIC_DEBUG_H#define _DYNAMIC_DEBUG_H +#include <linux/tables.h> +/* * An instance of this structure is created in a special * ELF section at every dynamic debug callsite. At runtime,
@@ -40,6 +42,7 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n, const char *modname);#if defined(CONFIG_DYNAMIC_DEBUG ) +DECLARE_LINKTABLE_DATA(struct _ddebug, __verbose);extern int ddebug_remove_module (const char *mod_name); extern __printf(2, 3) void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
@@ -61,8 +64,7 @@ void __dynamic_netdev_dbg(struct _ddebug *descriptor, const char *fmt, ...);#define DEFINE_DYNAMIC_DEBUG_METADATA (name, fmt) \ - static struct _ddebug __aligned(8) \ - __attribute__((section("__verbose"))) name = { \ + static LINKTABLE_DATA(__verbose, all) name = { \ .modname = KBUILD_MODNAME, \ .function = __func__, \ .filename = __FILE__, \
kernel/module.c +1 -1
@@ -2962,7 +2962,7 @@ static int find_module_sections(struct module *mod, struct load_info *info)if (section_addr (info,"__obsparm" ))pr_warn ("%s: Ignoring obsolete parameters\n" , mod->name); - info->debug =section_objs (info,"__verbose" , + info->debug = section_objs(info, SECTION_TBL(SECTION_DATA, __verbose,),sizeof (*info->debug), &info->num_debug);return 0 ;
lib/dynamic_debug.c +6 -7
@@ -37,8 +37,7 @@#include <linux/device.h> #include <linux/netdevice.h> -extern struct _ddebug __start___verbose[]; -extern struct _ddebug __stop___verbose[]; +DEFINE_LINKTABLE_DATA(struct _ddebug, __verbose);struct ddebug_table {struct list_head link;
@@ -971,14 +970,14 @@ static int __init dynamic_debug_init(void)int n =0 , entries =0 , modct =0 ;int verbose_bytes =0 ; -if (__start___verbose == __stop___verbose) { -pr_warn ("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n" ); +if (LINKTABLE_EMPTY (__verbose)) { +pr_warn ("dynamic debug linker table empty on CONFIG_DYNAMIC_DEBUG build\n" );return 1 ; } - iter = __start___verbose; + iter =LINKTABLE_START (__verbose); modname = iter->modname; iter_start = iter; -for (; iter < __stop___verbose; iter++) { + LINKTABLE_FOR_EACH(iter, __verbose) { entries++; verbose_bytes +=strlen (iter->modname) +strlen (iter->function) +strlen (iter->filename) +strlen (iter->format);
@@ -1001,7 +1000,7 @@ static int __init dynamic_debug_init(void) ddebug_init_success =1 ;vpr_info ("%d modules, %d entries and %d bytes in ddebug tables, %d bytes in (readonly) verbose section\n" , modct, entries, (int )(modct *sizeof (struct ddebug_table )), - verbose_bytes + (int )(__stop___verbose - __start___verbose)); + verbose_bytes + (int )(LINKTABLE_SIZE (__verbose)));/* apply ddebug_query boot param, dont unload tables on err */ if (ddebug_setup_string[0 ] !='\0' ) {
Signature · 1 line
2.7.0
RFC v2 7/7 kprobes: port to linker table
In reply to Luis R. Rodriguezkprobe makes use of two custom sections:
type name begin end
init.data _kprobe_blacklist __start_kprobe_blacklist __stop_kprobe_blacklist
text .kprobes.text __kprobes_text_start __kprobes_text_end
Port these to the linker table generic solution. This lets us remove all the custom kprobe section declarations on the linker script.
Tested with CONFIG_KPROBES_SANITY_TEST, it passes with:
Kprobe smoke test: started
Kprobe smoke test: passed successfully
Then tested CONFIG_SAMPLE_KPROBES on do_fork, and the kprobe bites and kicks as expected. Lastly tried registering a kprobe on a kprobe blacklisted symbol (NOKPROBE_SYMBOL()), and confirms that fails to work.
--- arch/arc/kernel/vmlinux.lds.S | 1 - arch/arm/kernel/entry-armv.S | 2 +- arch/arm/kernel/vmlinux.lds.S | 1 - arch/avr32/kernel/entry-avr32b.S | 4 ++-- arch/avr32/kernel/vmlinux.lds.S | 1 - arch/blackfin/kernel/vmlinux.lds.S | 1 - arch/c6x/kernel/vmlinux.lds.S | 1 - arch/hexagon/kernel/vmlinux.lds.S | 1 - arch/ia64/kernel/jprobes.S | 2 +- arch/ia64/kernel/vmlinux.lds.S | 1 - arch/ia64/lib/flush.S | 4 ++-- arch/metag/kernel/vmlinux.lds.S | 1 - arch/microblaze/kernel/vmlinux.lds.S | 1 - arch/mips/kernel/vmlinux.lds.S | 1 - arch/mn10300/kernel/vmlinux.lds.S | 1 - arch/nios2/kernel/vmlinux.lds.S | 1 - arch/openrisc/kernel/vmlinux.lds.S | 1 - arch/parisc/kernel/vmlinux.lds.S | 1 - arch/powerpc/include/asm/ppc_asm.h | 6 +++--- arch/powerpc/kernel/vmlinux.lds.S | 1 - arch/s390/kernel/entry.S | 4 ++-- arch/s390/kernel/kprobes.c | 2 +- arch/s390/kernel/mcount.S | 2 +- arch/s390/kernel/vmlinux.lds.S | 1 - arch/score/kernel/vmlinux.lds.S | 1 - arch/sh/kernel/vmlinux.lds.S | 1 - arch/sparc/kernel/vmlinux.lds.S | 1 - arch/sparc/mm/ultra.S | 2 +- arch/tile/kernel/vmlinux.lds.S | 1 - arch/x86/kernel/kprobes/core.c | 10 ++++++---- arch/x86/kernel/vmlinux.lds.S | 1 - include/asm-generic/sections.h | 4 ++-- include/asm-generic/vmlinux.lds.h | 16 ---------------- include/linux/compiler.h | 3 ++- include/linux/kprobes.h | 7 +++++-- kernel/kprobes.c | 16 +++++++--------- scripts/mod/modpost.c | 3 ++- scripts/recordmcount.c | 3 ++- scripts/recordmcount.pl | 2 +- 39 files changed, 41 insertions(+), 72 deletions(-)
arch/arc/kernel/vmlinux.lds.S +0 -1
@@ -98,7 +98,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.fixup) *(.gnu.warning) }
arch/arm/kernel/entry-armv.S +1 -1
@@ -83,7 +83,7 @@ .endm #ifdef CONFIG_KPROBES - .section .kprobes.text,"ax",%progbits + .section .text.tbl.kprobes.all,"ax",%progbits #else .text #endif
arch/arm/kernel/vmlinux.lds.S +0 -1
@@ -108,7 +108,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.gnu.warning) *(.glue_7) *(.glue_7t)
arch/avr32/kernel/entry-avr32b.S +2 -2
@@ -605,7 +605,7 @@ fault_exit_work: brcc fault_resume_user rjmp enter_monitor_mode - .section .kprobes.text, "ax", @progbits + .section .text.tbl.kprobes.all, "ax", @progbits .type handle_debug, @function handle_debug: sub sp, 4 /* r12_orig */
@@ -826,7 +826,7 @@ irq_level\level: IRQ_LEVEL 2 IRQ_LEVEL 3 - .section .kprobes.text, "ax", @progbits + .section .text.tbl.kprobes.all, "ax", @progbits .type enter_monitor_mode, @function enter_monitor_mode: /*
arch/avr32/kernel/vmlinux.lds.S +0 -1
@@ -49,7 +49,6 @@ SECTIONS _stext = .; *(.ex.text) *(.irq.text) - KPROBES_TEXT TEXT_TEXT SCHED_TEXT LOCK_TEXT
arch/blackfin/kernel/vmlinux.lds.S +0 -1
@@ -35,7 +35,6 @@ SECTIONS #endif LOCK_TEXT IRQENTRY_TEXT - KPROBES_TEXT #ifdef CONFIG_ROMKERNEL __sinittext = .; INIT_TEXT
arch/c6x/kernel/vmlinux.lds.S +0 -1
@@ -72,7 +72,6 @@ SECTIONS SCHED_TEXT LOCK_TEXT IRQENTRY_TEXT - KPROBES_TEXT *(.fixup) *(.gnu.warning) }
arch/hexagon/kernel/vmlinux.lds.S +0 -1
@@ -51,7 +51,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.fixup) } _etext = .;
arch/ia64/kernel/jprobes.S +1 -1
@@ -50,7 +50,7 @@ /* * void jprobe_break(void) */ - .section .kprobes.text, "ax" + .section .text.tbl.kprobes.all, "ax" ENTRY(jprobe_break) break.m __IA64_BREAK_JPROBE END(jprobe_break)
arch/ia64/kernel/vmlinux.lds.S +0 -1
@@ -47,7 +47,6 @@ SECTIONS { TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.gnu.linkonce.t*) }
arch/ia64/lib/flush.S +2 -2
@@ -20,7 +20,7 @@ * * Note: "in0" and "in1" are preserved for debugging purposes. */ - .section .kprobes.text,"ax" + .section .text.tbl.kprobes.all,"ax" GLOBAL_ENTRY(flush_icache_range) .prologue
@@ -72,7 +72,7 @@ END(flush_icache_range) * * Note: "in0" and "in1" are preserved for debugging purposes. */ - .section .kprobes.text,"ax" + .section .text.tbl.kprobes.all,"ax" GLOBAL_ENTRY(clflush_cache_range) .prologue
arch/metag/kernel/vmlinux.lds.S +0 -1
@@ -22,7 +22,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.text.*) *(.gnu.warning)
arch/microblaze/kernel/vmlinux.lds.S +0 -1
@@ -34,7 +34,6 @@ SECTIONS { EXIT_CALL SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT . = ALIGN (4) ; _etext = . ;
arch/mips/kernel/vmlinux.lds.S +0 -1
@@ -56,7 +56,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.text.*) *(.fixup)
arch/mn10300/kernel/vmlinux.lds.S +0 -1
@@ -31,7 +31,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.fixup) *(.gnu.warning) } = 0xcb
arch/nios2/kernel/vmlinux.lds.S +0 -1
@@ -39,7 +39,6 @@ SECTIONS SCHED_TEXT LOCK_TEXT IRQENTRY_TEXT - KPROBES_TEXT } =0 _etext = .;
arch/openrisc/kernel/vmlinux.lds.S +0 -1
@@ -48,7 +48,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.fixup) *(.text.__*)
arch/parisc/kernel/vmlinux.lds.S +0 -1
@@ -70,7 +70,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.text.do_softirq) *(.text.sys_exit)
arch/powerpc/include/asm/ppc_asm.h +3 -3
@@ -218,7 +218,7 @@ name: \ .localentry name,.-name#define _KPROBE (name) \ - .section ".kprobes.text","a"; \ + .section ".text.tbl.kprobes.all","a"; \ .align 2 ; \ .type name,@function; \ .globl name; \
@@ -248,7 +248,7 @@ GLUE(.,name):#define _GLOBAL_TOC (name) _GLOBAL(name)#define _KPROBE (name) \ - .section ".kprobes.text","a"; \ + .section ".text.tbl.kprobes.all","a"; \ .align 2 ; \ .globl name; \ .globl GLUE(.,name); \
@@ -280,7 +280,7 @@ n:#define _GLOBAL_TOC (name) _GLOBAL(name)#define _KPROBE (n) \ - .section ".kprobes.text","a"; \ + .section ".text.tbl.kprobes.all","a"; \ .globl n; \ n:
arch/powerpc/kernel/vmlinux.lds.S +0 -1
@@ -53,7 +53,6 @@ SECTIONS *(.text .fixup __ftr_alt_* .ref.text) SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT #ifdef CONFIG_PPC32
arch/s390/kernel/entry.S +2 -2
@@ -162,7 +162,7 @@ _PIF_WORK = (_PIF_PER_TRAP) tm off+\addr, \mask .endm - .section .kprobes.text, "ax" + .section .text.tbl.kprobes.all, "ax" /* * Scheduler resume function, called by switch_to
@@ -965,7 +965,7 @@ ENTRY(restart_int_handler) brc 2,2b 3: j 3b - .section .kprobes.text, "ax" + .section .text.tbl.kprobes.all, "ax" #ifdef CONFIG_CHECK_STACK /*
arch/s390/kernel/kprobes.c +1 -1
@@ -288,7 +288,7 @@ static void kprobe_reenter_check(struct kprobe_ctlblk *kcb, struct kprobe *p)default :/* * A kprobe on the code path to single step an instruction -* is a BUG. The code path resides in the .kprobes.text +* is a BUG. The code path resides in the .text.tbl.kprobes.all * section and is executed with interrupts disabled. */ printk (KERN_EMERG "Invalid kprobe detected at %p.\n" , p->addr);
arch/s390/kernel/mcount.S +1 -1
@@ -10,7 +10,7 @@ #include <asm/ftrace.h> #include <asm/ptrace.h> - .section .kprobes.text, "ax" + .section .text.tbl.kprobes.all, "ax" ENTRY(ftrace_stub) br %r14
arch/s390/kernel/vmlinux.lds.S +0 -1
@@ -26,7 +26,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.fixup) *(.gnu.warning)
arch/score/kernel/vmlinux.lds.S +0 -1
@@ -41,7 +41,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.text.*) *(.fixup) . = ALIGN (4) ;
arch/sh/kernel/vmlinux.lds.S +0 -1
@@ -37,7 +37,6 @@ SECTIONS EXTRA_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.fixup) *(.gnu.warning)
arch/sparc/kernel/vmlinux.lds.S +0 -1
@@ -46,7 +46,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.gnu.warning) } = 0
arch/sparc/mm/ultra.S +1 -1
@@ -148,7 +148,7 @@ __spitfire_flush_tlb_mm_slow: /* * The following code flushes one page_size worth. */ - .section .kprobes.text, "ax" + .section .text.tbl.kprobes.all, "ax" .align 32 .globl __flush_icache_page __flush_icache_page: /* %o0 = phys_page */
arch/tile/kernel/vmlinux.lds.S +0 -1
@@ -43,7 +43,6 @@ SECTIONS HEAD_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT __fix_text_end = .; /* tile-cpack won't rearrange before this */ ALIGN_FUNCTION();
arch/x86/kernel/kprobes/core.c +6 -4
@@ -577,7 +577,10 @@ static int reenter_kprobe(struct kprobe *p, struct pt_regs *regs,case KPROBE_REENTER :/* A probe has been hit in the codepath leading up to, or just * after, single-stepping of a probed instruction. This entire -* codepath should strictly reside in .kprobes.text section. +* codepath should strictly reside in the kprobes section: +* +* SECTION_TBL(SECTION_TEXT, kprobes, all) +* * Raise a BUG or we'll continue in an endless reentering loop * and eventually a stack overflow. */
@@ -1114,10 +1117,9 @@ NOKPROBE_SYMBOL(longjmp_break_handler);bool arch_within_kprobe_blacklist (unsigned long addr) { -return (addr >= (unsigned long )__kprobes_text_start && - addr < (unsigned long )__kprobes_text_end) || +return (LINKTABLE_ADDR_WITHIN (kprobes, addr) || (addr >= (unsigned long )__entry_text_start && - addr < (unsigned long )__entry_text_end); + addr < (unsigned long )__entry_text_end)); }int __init arch_init_kprobes (void )
arch/x86/kernel/vmlinux.lds.S +0 -1
@@ -99,7 +99,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT ENTRY_TEXT IRQENTRY_TEXT *(.fixup)
include/asm-generic/sections.h +2 -2
@@ -24,7 +24,7 @@* Following global variables are optional and may be unavailable on some * architectures and/or kernel configurations. * _text, _data -* __kprobes_text_start, __kprobes_text_end +* LINKTABLE_START(kprobes), LINKTABLE_END(kprobes) * __entry_text_start, __entry_text_end * __ctors_start, __ctors_end */
@@ -35,7 +35,7 @@ extern char __init_begin[], __init_end[];extern char _sinittext[], _einittext[];extern char _end[];extern char __per_cpu_load[], __per_cpu_start[], __per_cpu_end[]; -extern char __kprobes_text_start[], __kprobes_text_end[]; +DECLARE_LINKTABLE_TEXT (char, kprobes);extern char __entry_text_start[], __entry_text_end[];extern char __start_rodata[], __end_rodata[];
include/asm-generic/vmlinux.lds.h +0 -16
@@ -112,15 +112,6 @@#define BRANCH_PROFILE ()#endif -#ifdef CONFIG_KPROBES -#define KPROBE_BLACKLIST () . = ALIGN(8); \ - VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \ - *(_kprobe_blacklist) \ - VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .; -#else -#define KPROBE_BLACKLIST () -#endif -#ifdef CONFIG_EVENT_TRACING #define FTRACE_EVENTS () . = ALIGN(8); \ VMLINUX_SYMBOL(__start_ftrace_events) = .; \
@@ -433,12 +424,6 @@ *(.spinlock.text) \ VMLINUX_SYMBOL(__lock_text_end) = .; -#define KPROBES_TEXT \ - ALIGN_FUNCTION(); \ - VMLINUX_SYMBOL(__kprobes_text_start) = .; \ - *(.kprobes.text) \ - VMLINUX_SYMBOL(__kprobes_text_end) = .; -#define ENTRY_TEXT \ ALIGN_FUNCTION(); \ VMLINUX_SYMBOL(__entry_text_start) = .; \
@@ -504,7 +489,6 @@ *(.init.rodata) \ FTRACE_EVENTS() \ TRACE_SYSCALLS() \ - KPROBE_BLACKLIST() \ MEM_DISCARD(init.rodata) \ CLK_OF_TABLES() \RESERVEDMEM_OF_TABLES () \
include/linux/compiler.h +2 -1
@@ -546,7 +546,8 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s/* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */ #ifdef CONFIG_KPROBES -# define __kprobes __attribute__((__section__(".kprobes.text"))) +#include <linux/sections.h> +# define __kprobes __attribute__((__section__(SECTION_TBL(SECTION_TEXT, kprobes, all))))# define nokprobe_inline __always_inline#else # define __kprobes
include/linux/kprobes.h +5 -2
@@ -42,8 +42,12 @@#include <linux/ftrace.h> #ifdef CONFIG_KPROBES +#include <linux/tables.h> #include <asm/kprobes.h> +DECLARE_LINKTABLE_TEXT (char, kprobes); +DECLARE_LINKTABLE_INIT_DATA(unsigned long, _kprobe_blacklist); +/* kprobe_status settings */ #define KPROBE_HIT_ACTIVE 0x00000001#define KPROBE_HIT_SS 0x00000002
@@ -487,8 +491,7 @@ static inline int enable_jprobe(struct jprobe *jp)* by using this macro. */ #define __NOKPROBE_SYMBOL (fname) \ -static unsigned long __used \ - __attribute__((section("_kprobe_blacklist"))) \ +static LINKTABLE_INIT_DATA(_kprobe_blacklist, all) \ _kbl_addr_##fname = (unsigned long)fname;#define NOKPROBE_SYMBOL (fname) __NOKPROBE_SYMBOL(fname)#else
kernel/kprobes.c +7 -9
@@ -1328,8 +1328,7 @@ out:bool __weak arch_within_kprobe_blacklist (unsigned long addr) {/* The __kprobes marked functions and entry code must not be probed */ -return addr >= (unsigned long )__kprobes_text_start && - addr < (unsigned long )__kprobes_text_end; +return LINKTABLE_ADDR_WITHIN (kprobes, addr); }bool within_kprobe_blacklist (unsigned long addr)
@@ -2054,14 +2053,13 @@ NOKPROBE_SYMBOL(dump_kprobe);* since a kprobe need not necessarily be at the beginning * of a function. */ -static int __init populate_kprobe_blacklist (unsigned long *start, -unsigned long *end) +static int __init populate_kprobe_blacklist (void ) {unsigned long *iter;struct kprobe_blacklist_entry *ent;unsigned long entry, offset =0 , size =0 ; -for (iter = start; iter < end; iter++) { + LINKTABLE_FOR_EACH(iter, _kprobe_blacklist) { entry =arch_deref_entry_point ((void *)*iter); if (!kernel_text_address(entry) ||
@@ -2126,8 +2124,9 @@ static struct notifier_block kprobe_module_nb = { };/* Markers of _kprobe_blacklist section */ -extern unsigned long __start_kprobe_blacklist[]; -extern unsigned long __stop_kprobe_blacklist[]; +DEFINE_LINKTABLE_INIT_DATA(unsigned long, _kprobe_blacklist); +/* Actual kprobes linker table */ +DEFINE_LINKTABLE_TEXT (char, kprobes);static int __init init_kprobes (void ) {
@@ -2141,8 +2140,7 @@ static int __init init_kprobes(void)raw_spin_lock_init (&(kretprobe_table_locks[i].lock)); } - err =populate_kprobe_blacklist (__start_kprobe_blacklist, - __stop_kprobe_blacklist); + err =populate_kprobe_blacklist ();if (err) {pr_err ("kprobes: failed to populate blacklist: %d\n" , err);pr_err ("Please take care of using kprobes.\n" );
scripts/mod/modpost.c +2 -1
@@ -22,6 +22,7 @@#include "../../include/generated/autoconf.h" #include "../../include/linux/license.h" #include "../../include/linux/export.h" +#include "../../include/linux/sections.h" /* Are we using CONFIG_MODVERSIONS? */ static int modversions =0 ;
@@ -888,7 +889,7 @@ static void check_section(const char *modname, struct elf_info *elf,#define DATA_SECTIONS ".data", ".data.rel"#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \ - ".kprobes.text" + SECTION_TBL(SECTION_TEXT, kprobes, all)#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ ".fixup", ".entry.text", ".exception.text", ".text.*", \ ".coldtext"
scripts/recordmcount.c +2 -1
@@ -32,6 +32,7 @@#include <stdlib.h> #include <string.h> #include <unistd.h> +#include "../../include/linux/sections.h" #ifndef EM_METAG /* Remove this when these make it to the standard system elf.h. */
@@ -356,7 +357,7 @@ is_mcounted_section_name(char const *const txtname)strcmp (".sched.text" , txtname) ==0 ||strcmp (".spinlock.text" , txtname) ==0 ||strcmp (".irqentry.text" , txtname) ==0 || -strcmp (".kprobes.text" , txtname) ==0 || +strcmp (SECTION_TBL (SECTION_TEXT , kprobe, all), txtname) ==0 ||strcmp (".text.unlikely" , txtname) ==0 ; }
scripts/recordmcount.pl +1 -1
@@ -134,7 +134,7 @@ my %text_sections = ( ".sched.text" => 1, ".spinlock.text" => 1, ".irqentry.text" => 1, - ".kprobes.text" => 1, + ".text.tbl.kprobes.all" => 1, ".text.unlikely" => 1, );
Signature · 1 line
2.7.0
Re: [RFC v2 7/7] kprobes: port to linker table
Quoted 9 lines · Luis R. Rodriguez
kprobe makes use of two custom sections:
type name begin end
init.data_kprobe_blacklist__start_kprobe_blacklist__stop_kprobe_blacklist
text .kprobes.text__kprobes_text_start__kprobes_text_endPort these to the linker table generic solution. This lets us remove all the custom kprobe section declarations on the linker script.
I don't like this. You create this "table" thing, which you use for tables, and then you go and use it for something else - for kprobes text which is not a table. The kprobes text section is a section for text which is not kprobe-able.
So, it seems to be a complete mis-nomer to me. Maybe you can explain the rationale here?
Signature · 3 lines
RMK's Patch system: http://www.arm.linux.org.uk/developer/patches/ FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up according to speedtest.net.
Re: [RFC v2 7/7] kprobes: port to linker table
Quoted 7 lines · Russell King - ARM Linux
Quoted 6 lines · Luis R. Rodriguez
kprobe makes use of two custom sections:
type name begin end
init.data_kprobe_blacklist__start_kprobe_blacklist__stop_kprobe_blacklist
text .kprobes.text__kprobes_text_start__kprobes_text_end
Quoted 8 lines
Quoted 3 lines
Port these to the linker table generic solution. This lets us remove all the custom kprobe section declarations on the linker script.
I don't like this. You create this "table" thing, which you use for tables, and then you go and use it for something else - for kprobes text which is not a table. The kprobes text section is a section for text which is not kprobe-able.
No the thing about linker tables is its generalizing custom section solutions we have scattered all over the place.
Quoted 2 lines
So, it seems to be a complete mis-nomer to me. Maybe you can explain the rationale here?
Sure, so each custom section solution requires modifying the linker script. With linker tables we end up only with a few basic types of tables, a read-only, text, data, init init_data, etc. A linker table belongs to one of these. The linker table provides a means by which to describe explicitly what type of section you are using for your solution but also allows us to enable such custom solutions without furthering the custom linker script.
Luis
RE: [RFC v2 7/7] kprobes: port to linker table
In reply to Luis R. RodriguezQuoted 14 lines
From: Luis R. Rodriguez [mailto:[email protected]]
kprobe makes use of two custom sections:
type name begin end
init.data_kprobe_blacklist__start_kprobe_blacklist__stop_kprobe_blacklist
text .kprobes.text__kprobes_text_start__kprobes_text_endPort these to the linker table generic solution. This lets us remove all the custom kprobe section declarations on the linker script.
Tested with
CONFIG_KPROBES_SANITY_TEST, it passes with:
Quoted 7 lines
Kprobe smoke test: started
Kprobe smoke test: passed successfullyThen tested
CONFIG_SAMPLE_KPROBESondo_fork, and the kprobe bites and kicks as expected. Lastly tried registering a kprobe on a kprobe blacklisted symbol (NOKPROBE_SYMBOL()), and confirms that fails to work.
Could you also check to run the testcases by using ftracetest as below?
$ cd tools/testing/selftests/ftrace/ $ sudo ./ftracetest
And I'm not sure about linker table. Is that possible to support __kprobes prefix, which moves the functions into kprobes.text? Actually, I'm on the way to replacing __kprobes to NOKPROBE_SYMBOL macro, since NOKPROBE_SYMBOL() doesn't effect the kernel text itself. On x86, it is already replaced (see commit 820aede0209a), and same work should be done on other archs. So, could you hold this after that? I think we should remove .kprobes.text first and move to linker table.
Thank you,
Quoted 701 lines
Signed-off-by Luis R. Rodriguez <[email protected]>---
arch/arc/kernel/vmlinux.lds.S | 1 - arch/arm/kernel/entry-armv.S | 2 +- arch/arm/kernel/vmlinux.lds.S | 1 - arch/avr32/kernel/entry-avr32b.S | 4 ++-- arch/avr32/kernel/vmlinux.lds.S | 1 - arch/blackfin/kernel/vmlinux.lds.S | 1 - arch/c6x/kernel/vmlinux.lds.S | 1 - arch/hexagon/kernel/vmlinux.lds.S | 1 - arch/ia64/kernel/jprobes.S | 2 +- arch/ia64/kernel/vmlinux.lds.S | 1 - arch/ia64/lib/flush.S | 4 ++-- arch/metag/kernel/vmlinux.lds.S | 1 - arch/microblaze/kernel/vmlinux.lds.S | 1 - arch/mips/kernel/vmlinux.lds.S | 1 - arch/mn10300/kernel/vmlinux.lds.S | 1 - arch/nios2/kernel/vmlinux.lds.S | 1 - arch/openrisc/kernel/vmlinux.lds.S | 1 - arch/parisc/kernel/vmlinux.lds.S | 1 - arch/powerpc/include/asm/ppc_asm.h | 6 +++--- arch/powerpc/kernel/vmlinux.lds.S | 1 - arch/s390/kernel/entry.S | 4 ++-- arch/s390/kernel/kprobes.c | 2 +- arch/s390/kernel/mcount.S | 2 +- arch/s390/kernel/vmlinux.lds.S | 1 - arch/score/kernel/vmlinux.lds.S | 1 - arch/sh/kernel/vmlinux.lds.S | 1 - arch/sparc/kernel/vmlinux.lds.S | 1 - arch/sparc/mm/ultra.S | 2 +- arch/tile/kernel/vmlinux.lds.S | 1 - arch/x86/kernel/kprobes/core.c | 10 ++++++---- arch/x86/kernel/vmlinux.lds.S | 1 - include/asm-generic/sections.h | 4 ++-- include/asm-generic/vmlinux.lds.h | 16 ---------------- include/linux/compiler.h | 3 ++- include/linux/kprobes.h | 7 +++++-- kernel/kprobes.c | 16 +++++++--------- scripts/mod/modpost.c | 3 ++- scripts/recordmcount.c | 3 ++- scripts/recordmcount.pl | 2 +- 39 files changed, 41 insertions(+), 72 deletions(-)arch/arc/kernel/vmlinux.lds.S +0
-1@@ -98,7 +98,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.fixup) *(.gnu.warning) }arch/arm/kernel/entry-armv.S +1
-1@@ -83,7 +83,7 @@ .endm #ifdef CONFIG_KPROBES - .section .kprobes.text,"ax",%progbits + .section .text.tbl.kprobes.all,"ax",%progbits #else .text #endifarch/arm/kernel/vmlinux.lds.S +0
-1@@ -108,7 +108,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.gnu.warning) *(.glue_7) *(.glue_7t)arch/avr32/kernel/entry-avr32b.S +1
-1@@ -605,7 +605,7 @@ fault_exit_work: brcc fault_resume_user rjmp enter_monitor_mode - .section .kprobes.text, "ax", @progbits + .section .text.tbl.kprobes.all, "ax", @progbits .type handle_debug, @function
handle_debug:sub sp, 4 /* r12_orig */arch/avr32/kernel/entry-avr32b.S +1
-1@@ -826,7 +826,7 @@ irq_level\level: IRQ_LEVEL 2 IRQ_LEVEL 3 - .section .kprobes.text, "ax", @progbits + .section .text.tbl.kprobes.all, "ax", @progbits .type enter_monitor_mode, @function
enter_monitor_mode:/*arch/avr32/kernel/vmlinux.lds.S +0
-1@@ -49,7 +49,6 @@ SECTIONS _stext = .; *(.ex.text) *(.irq.text) - KPROBES_TEXT TEXT_TEXT SCHED_TEXT LOCK_TEXTarch/blackfin/kernel/vmlinux.lds.S +0
-1@@ -35,7 +35,6 @@ SECTIONS #endif LOCK_TEXT IRQENTRY_TEXT - KPROBES_TEXT #ifdef CONFIG_ROMKERNEL __sinittext = .; INIT_TEXTarch/c6x/kernel/vmlinux.lds.S +0
-1@@ -72,7 +72,6 @@ SECTIONS SCHED_TEXT LOCK_TEXT IRQENTRY_TEXT - KPROBES_TEXT *(.fixup) *(.gnu.warning) }arch/hexagon/kernel/vmlinux.lds.S +0
-1@@ -51,7 +51,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.fixup) } _etext = .;arch/ia64/kernel/jprobes.S +1
-1@@ -50,7 +50,7 @@ /* * void jprobe_break(void) */ - .section .kprobes.text, "ax" + .section .text.tbl.kprobes.all, "ax" ENTRY(jprobe_break) break.m __IA64_BREAK_JPROBE END(jprobe_break)arch/ia64/kernel/vmlinux.lds.S +0
-1@@ -47,7 +47,6 @@ SECTIONS { TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.gnu.linkonce.t*) }arch/ia64/lib/flush.S +2
-2@@ -20,7 +20,7 @@ * * Note: "in0" and "in1" are preserved for debugging purposes. */ - .section .kprobes.text,"ax" + .section .text.tbl.kprobes.all,"ax" GLOBAL_ENTRY(flush_icache_range) .prologue@@ -72,7 +72,7 @@ END(flush_icache_range) * * Note: "in0" and "in1" are preserved for debugging purposes. */ - .section .kprobes.text,"ax" + .section .text.tbl.kprobes.all,"ax" GLOBAL_ENTRY(clflush_cache_range) .prologuearch/metag/kernel/vmlinux.lds.S +0
-1@@ -22,7 +22,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.text.*) *(.gnu.warning)arch/microblaze/kernel/vmlinux.lds.S +0
-1@@ -34,7 +34,6 @@ SECTIONS { EXIT_CALL SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT . = ALIGN (4) ; _etext = . ;arch/mips/kernel/vmlinux.lds.S +0
-1@@ -56,7 +56,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.text.*) *(.fixup)arch/mn10300/kernel/vmlinux.lds.S +0
-1@@ -31,7 +31,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.fixup) *(.gnu.warning) } = 0xcbarch/nios2/kernel/vmlinux.lds.S +0
-1@@ -39,7 +39,6 @@ SECTIONS SCHED_TEXT LOCK_TEXT IRQENTRY_TEXT - KPROBES_TEXT } =0 _etext = .;arch/openrisc/kernel/vmlinux.lds.S +0
-1@@ -48,7 +48,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.fixup) *(.text.__*)arch/parisc/kernel/vmlinux.lds.S +0
-1@@ -70,7 +70,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.text.do_softirq) *(.text.sys_exit)arch/powerpc/include/asm/ppc_asm.h +3
-3@@ -218,7 +218,7 @@ name: \ .localentry name,.-name#define _KPROBE (name) \ - .section ".kprobes.text","a"; \ + .section ".text.tbl.kprobes.all","a"; \ .align 2 ; \ .type name,@function; \ .globl name; \@@ -248,7 +248,7 @@ GLUE(.,name):#define _GLOBAL_TOC (name) _GLOBAL(name)#define _KPROBE (name) \ - .section ".kprobes.text","a"; \ + .section ".text.tbl.kprobes.all","a"; \ .align 2 ; \ .globl name; \ .globl GLUE(.,name); \@@ -280,7 +280,7 @@ n:#define _GLOBAL_TOC (name) _GLOBAL(name)#define _KPROBE (n) \ - .section ".kprobes.text","a"; \ + .section ".text.tbl.kprobes.all","a"; \ .globl n; \n:
arch/powerpc/kernel/vmlinux.lds.S +0
-1@@ -53,7 +53,6 @@ SECTIONS *(.text .fixup __ftr_alt_* .ref.text) SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT #ifdef CONFIG_PPC32arch/s390/kernel/entry.S +1
-1@@ -162,7 +162,7 @@ _PIF_WORK = (_PIF_PER_TRAP) tm off+\addr, \mask .endm - .section .kprobes.text, "ax" + .section .text.tbl.kprobes.all, "ax" /* * Scheduler resume function, called by switch_to@@ -965,7 +965,7 @@ ENTRY(restart_int_handler) brc 2,2b3: j 3b
arch/s390/kernel/entry.S +1
-1- .section .kprobes.text, "ax" + .section .text.tbl.kprobes.all, "ax"#ifdef
CONFIG_CHECK_STACK
/*arch/s390/kernel/kprobes.c +1
-1@@ -288,7 +288,7 @@ static void kprobe_reenter_check(struct kprobe_ctlblk *kcb, struct kprobe *p)default :/* * A kprobe on the code path to single step an instruction -* is a BUG. The code path resides in the .kprobes.text +* is a BUG. The code path resides in the .text.tbl.kprobes.all * section and is executed with interrupts disabled. */ printk (KERN_EMERG "Invalid kprobe detected at %p.\n" , p->addr);arch/s390/kernel/mcount.S +1
-1@@ -10,7 +10,7 @@ #include <asm/ftrace.h> #include <asm/ptrace.h> - .section .kprobes.text, "ax" + .section .text.tbl.kprobes.all, "ax" ENTRY(ftrace_stub) br %r14arch/s390/kernel/vmlinux.lds.S +0
-1@@ -26,7 +26,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.fixup) *(.gnu.warning)arch/score/kernel/vmlinux.lds.S +0
-1@@ -41,7 +41,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT *(.text.*) *(.fixup) . = ALIGN (4) ;arch/sh/kernel/vmlinux.lds.S +0
-1@@ -37,7 +37,6 @@ SECTIONS EXTRA_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.fixup) *(.gnu.warning)arch/sparc/kernel/vmlinux.lds.S +0
-1@@ -46,7 +46,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT *(.gnu.warning) } = 0arch/sparc/mm/ultra.S +1
-1@@ -148,7 +148,7 @@ __spitfire_flush_tlb_mm_slow: /* * The following code flushes one page_size worth. */ - .section .kprobes.text, "ax" + .section .text.tbl.kprobes.all, "ax" .align 32 .globl __flush_icache_page
__flush_icache_page: /* %o0 =phys_page*/arch/tile/kernel/vmlinux.lds.S +0
-1@@ -43,7 +43,6 @@ SECTIONS HEAD_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT IRQENTRY_TEXT __fix_text_end = .; /* tile-cpack won't rearrange before this */ ALIGN_FUNCTION();arch/x86/kernel/kprobes/core.c +6
-4@@ -577,7 +577,10 @@ static int reenter_kprobe(struct kprobe *p, struct pt_regs *regs,case KPROBE_REENTER :/* A probe has been hit in the codepath leading up to, or just * after, single-stepping of a probed instruction. This entire -* codepath should strictly reside in .kprobes.text section. +* codepath should strictly reside in the kprobes section: +* +* SECTION_TBL(SECTION_TEXT, kprobes, all) +* * Raise a BUG or we'll continue in an endless reentering loop * and eventually a stack overflow. */ @@ -1114,10 +1117,9 @@ NOKPROBE_SYMBOL(longjmp_break_handler);bool arch_within_kprobe_blacklist (unsigned long addr) { -return (addr >= (unsigned long )__kprobes_text_start && - addr < (unsigned long )__kprobes_text_end) || +return (LINKTABLE_ADDR_WITHIN (kprobes, addr) || (addr >= (unsigned long )__entry_text_start && - addr < (unsigned long )__entry_text_end); + addr < (unsigned long )__entry_text_end)); }int __init arch_init_kprobes (void )arch/x86/kernel/vmlinux.lds.S +0
-1@@ -99,7 +99,6 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - KPROBES_TEXT ENTRY_TEXT IRQENTRY_TEXT *(.fixup)include/asm-generic/sections.h +2
-2@@ -24,7 +24,7 @@* Following global variables are optional and may be unavailable on some * architectures and/or kernel configurations. * _text, _data -* __kprobes_text_start, __kprobes_text_end +* LINKTABLE_START(kprobes), LINKTABLE_END(kprobes) * __entry_text_start, __entry_text_end * __ctors_start, __ctors_end */ @@ -35,7 +35,7 @@ extern char __init_begin[], __init_end[];extern char _sinittext[], _einittext[];extern char _end[];extern char __per_cpu_load[], __per_cpu_start[], __per_cpu_end[]; -extern char __kprobes_text_start[], __kprobes_text_end[]; +DECLARE_LINKTABLE_TEXT (char, kprobes);extern char __entry_text_start[], __entry_text_end[];extern char __start_rodata[], __end_rodata[];include/asm-generic/vmlinux.lds.h +0
-16@@ -112,15 +112,6 @@#define BRANCH_PROFILE ()#endif -#ifdef CONFIG_KPROBES -#define KPROBE_BLACKLIST () . = ALIGN(8); \ - VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \ - *(_kprobe_blacklist) \ - VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .; -#else -#define KPROBE_BLACKLIST () -#endif -#ifdef CONFIG_EVENT_TRACING #define FTRACE_EVENTS () . = ALIGN(8); \ VMLINUX_SYMBOL(__start_ftrace_events) = .; \@@ -433,12 +424,6 @@ *(.spinlock.text) \ VMLINUX_SYMBOL(__lock_text_end) = .; -#define KPROBES_TEXT \ - ALIGN_FUNCTION(); \ - VMLINUX_SYMBOL(__kprobes_text_start) = .; \ - *(.kprobes.text) \ - VMLINUX_SYMBOL(__kprobes_text_end) = .; -#define ENTRY_TEXT \ ALIGN_FUNCTION(); \ VMLINUX_SYMBOL(__entry_text_start) = .; \@@ -504,7 +489,6 @@ *(.init.rodata) \ FTRACE_EVENTS() \ TRACE_SYSCALLS() \ - KPROBE_BLACKLIST() \ MEM_DISCARD(init.rodata) \ CLK_OF_TABLES() \RESERVEDMEM_OF_TABLES () \include/linux/compiler.h +2
-1@@ -546,7 +546,8 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s/* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */ #ifdef CONFIG_KPROBES -# define __kprobes __attribute__((__section__(".kprobes.text"))) +#include <linux/sections.h> +# define __kprobes __attribute__((__section__(SECTION_TBL(SECTION_TEXT, kprobes, all))))# define nokprobe_inline __always_inline#else # define __kprobesinclude/linux/kprobes.h +5
-2@@ -42,8 +42,12 @@#include <linux/ftrace.h> #ifdef CONFIG_KPROBES +#include <linux/tables.h> #include <asm/kprobes.h> +DECLARE_LINKTABLE_TEXT (char, kprobes); +DECLARE_LINKTABLE_INIT_DATA(unsigned long, _kprobe_blacklist); +/* kprobe_status settings */ #define KPROBE_HIT_ACTIVE 0x00000001#define KPROBE_HIT_SS 0x00000002@@ -487,8 +491,7 @@ static inline int enable_jprobe(struct jprobe *jp)* by using this macro. */ #define __NOKPROBE_SYMBOL (fname) \ -static unsigned long __used \ - __attribute__((section("_kprobe_blacklist"))) \ +static LINKTABLE_INIT_DATA(_kprobe_blacklist, all) \ _kbl_addr_##fname = (unsigned long)fname;#define NOKPROBE_SYMBOL (fname) __NOKPROBE_SYMBOL(fname)#else kernel/kprobes.c +7
-9@@ -1328,8 +1328,7 @@ out:bool __weak arch_within_kprobe_blacklist (unsigned long addr) {/* The __kprobes marked functions and entry code must not be probed */ -return addr >= (unsigned long )__kprobes_text_start && - addr < (unsigned long )__kprobes_text_end; +return LINKTABLE_ADDR_WITHIN (kprobes, addr); }bool within_kprobe_blacklist (unsigned long addr)@@ -2054,14 +2053,13 @@ NOKPROBE_SYMBOL(dump_kprobe);* since a kprobe need not necessarily be at the beginning * of a function. */ -static int __init populate_kprobe_blacklist (unsigned long *start, -unsigned long *end) +static int __init populate_kprobe_blacklist (void ) {unsigned long *iter;struct kprobe_blacklist_entry *ent;unsigned long entry, offset =0 , size =0 ; -for (iter = start; iter < end; iter++) { + LINKTABLE_FOR_EACH(iter, _kprobe_blacklist) { entry =arch_deref_entry_point ((void *)*iter); if (!kernel_text_address(entry) ||@@ -2126,8 +2124,9 @@ static struct notifier_block kprobe_module_nb = { };/* Markers of _kprobe_blacklist section */ -extern unsigned long __start_kprobe_blacklist[]; -extern unsigned long __stop_kprobe_blacklist[]; +DEFINE_LINKTABLE_INIT_DATA(unsigned long, _kprobe_blacklist); +/* Actual kprobes linker table */ +DEFINE_LINKTABLE_TEXT (char, kprobes);static int __init init_kprobes (void ) {@@ -2141,8 +2140,7 @@ static int __init init_kprobes(void)raw_spin_lock_init (&(kretprobe_table_locks[i].lock)); } - err =populate_kprobe_blacklist (__start_kprobe_blacklist, - __stop_kprobe_blacklist); + err =populate_kprobe_blacklist ();if (err) {pr_err ("kprobes: failed to populate blacklist: %d\n" , err);pr_err ("Please take care of using kprobes.\n" );scripts/mod/modpost.c +2
-1@@ -22,6 +22,7 @@#include "../../include/generated/autoconf.h" #include "../../include/linux/license.h" #include "../../include/linux/export.h" +#include "../../include/linux/sections.h" /* Are we using CONFIG_MODVERSIONS? */ static int modversions =0 ;@@ -888,7 +889,7 @@ static void check_section(const char *modname, struct elf_info *elf,#define DATA_SECTIONS ".data", ".data.rel"#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \ - ".kprobes.text" + SECTION_TBL(SECTION_TEXT, kprobes, all)#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ ".fixup", ".entry.text", ".exception.text", ".text.*", \ ".coldtext"scripts/recordmcount.c +2
-1@@ -32,6 +32,7 @@#include <stdlib.h> #include <string.h> #include <unistd.h> +#include "../../include/linux/sections.h" #ifndef EM_METAG /* Remove this when these make it to the standard system elf.h. */ @@ -356,7 +357,7 @@ is_mcounted_section_name(char const *const txtname)strcmp (".sched.text" , txtname) ==0 ||strcmp (".spinlock.text" , txtname) ==0 ||strcmp (".irqentry.text" , txtname) ==0 || -strcmp (".kprobes.text" , txtname) ==0 || +strcmp (SECTION_TBL (SECTION_TEXT , kprobe, all), txtname) ==0 ||strcmp (".text.unlikely" , txtname) ==0 ; }scripts/recordmcount.pl +1
-2@@ -134,7 +134,7 @@ my %text_sections = ( ".sched.text" => 1, ".spinlock.text" => 1, ".irqentry.text" => 1, - ".kprobes.text" => 1, + ".text.tbl.kprobes.all" => 1, ".text.unlikely" => 1, ); --2.7.0
Re: [Xen-devel] [RFC v2 7/7] kprobes: port to linker table
Quoted 22 lines · 平松雅巳 / HIRAMATU,MASAMI
Quoted 14 lines
From: Luis R. Rodriguez [mailto:[email protected]]
kprobe makes use of two custom sections:
type name begin end
init.data_kprobe_blacklist__start_kprobe_blacklist__stop_kprobe_blacklist
text .kprobes.text__kprobes_text_start__kprobes_text_endPort these to the linker table generic solution. This lets us remove all the custom kprobe section declarations on the linker script.
Tested with
CONFIG_KPROBES_SANITY_TEST, it passes with:Quoted 7 lines
Kprobe smoke test: started
Kprobe smoke test: passed successfullyThen tested
CONFIG_SAMPLE_KPROBESondo_fork, and the kprobe bites and kicks as expected. Lastly tried registering a kprobe on a kprobe blacklisted symbol (NOKPROBE_SYMBOL()), and confirms that fails to work.
Quoted 4 lines
Could you also check to run the testcases by using ftracetest as below?
$ cd tools/testing/selftests/ftrace/ $ sudo ./ftracetest
Sure, it all passed:
$ sudo ./ftracetest === Ftrace unit tests === [1] Basic trace file check [PASS] [2] Basic test for tracers [PASS] [3] Basic trace clock test [PASS] [4] Basic event tracing check [PASS] [5] event tracing - enable/disable with event level files [PASS] [6] event tracing - enable/disable with subsystem level files [PASS] [7] event tracing - enable/disable with top level files [PASS] [8] ftrace - function graph filters with stack tracer [PASS] [9] ftrace - function graph filters [PASS] [10] ftrace - function profiler with function tracing [PASS] [11] Test creation and deletion of trace instances [PASS] [12] Kprobe dynamic event - adding and removing [PASS] [13] Kprobe dynamic event - busy event check [PASS] [14] Kprobe dynamic event with arguments [PASS] [15] Kprobe dynamic event with function tracer [PASS] [16] Kretprobe dynamic event with arguments [PASS]
# of passed: 16 # of failed: 0 # of unresolved: 0 # of untested: 0 # of unsupported: 0 # of xfailed: 0 # of undefined(test bug): 0
Quoted 1 line
And I'm not sure about linker table.
So there's really a few parts to the linker table work, out of the ones that relate to kprobes:
* linker tables try to generalize our section use, and provide some helpers for common section use
* provides helpers to make it easier to make custom section, but by re-using standard sections
* when a custom section uses standard sections and helpers we also get a few gains:
- developers reviewing code can more easily get a quicker understanding and have expectations set of how the code feature using the custom section could be used
- people grep'ing on the kernel can more easily find specific types of custom section use by looking for the type of interest
- developers adding features do not need to modify
any linker scripts (vmlinux.lds.S) to make use of custom sections
In kprobe's case, since it uses two custom sections, we have only a small use for the first case: .kprobe.text is just used as a place holder for future developer annotated special cased executable code. It also makes use of the generic helpers:LINKTABLE_ADDR_WITHIN(), LINKTABLE_START(), LINKTABLE_END().
The second use case, for the _kprobe_blacklist, makes much more use of the more advanced linker table helpers, for instance the iterator LINKTABLE_FOR_EACH().
For both though we now have each custom section's actual section clearly highlighted:
* kprobes: .text (SECTION_TEXT)
* kprobe blacklist: init.data (SECTION_INIT_DATA)
A reader / developer can more easily gain an understanding of how the above custom sections could be used just by its type.
Another feature of linker tables, but outside of the scope of how kprobe would use linker tables, is the ability to enable folks to avoid code bit rot by using table-$(CONFIG_FOO) instead of oby-$(CONFIG_FOO) on init paths of code but since this is outside of the scope of how kprobe would use I leave that just as a reference as another part of linker table. Unless of course you want to make people force compile all kprobe support code but only have it linked in when actually enabled. That would be outside of the scope and purpose of this patch though.
Quoted 2 lines
Is that possible to support
__kprobesprefix, which moves the functions into kprobes.text?
Absolutely, the respective change was just to annotate and make it clear the section kprobes were using:
-# define __kprobes __attribute__((__section__(".kprobes.text")))
+#include <linux/sections.h>
+# define __kprobes __attribute__((__section__(SECTION_TBL(SECTION_TEXT, kprobes, all))))
Quoted 5 lines
Actually, I'm on the way to replacing
__kprobestoNOKPROBE_SYMBOLmacro, sinceNOKPROBE_SYMBOL()doesn't effect the kernel text itself. On x86, it is already replaced (see commit820aede0209a), and same work should be done on other archs. So, could you hold this after that?
Sure.
Quoted 1 line
I think we should remove .kprobes.text first
You mean just remove the incorrect users of .kprobes.text because as I read what you described above we have abuse of __kprobes use to protect against kprobes being introduced on those routines, and we should be using NOKPROBE_SYMBOL() instead. So from what I gather its not that you will remove .kprobes.text but rather clean our current abuse of __kprobes for protection to use NOKPROBE_SYMBOL() instead. Is that right?
Quoted 1 line
and move to linker table.
Sure, can you Cc me on your patches? I can follow up later.
Luis
Re: [Xen-devel] [RFC v2 7/7] kprobes: port to linker table
Quoted 49 lines · Luis R. Rodriguez
Quoted 22 lines · 平松雅巳 / HIRAMATU,MASAMI
Quoted 14 lines
From: Luis R. Rodriguez [mailto:[email protected]]
kprobe makes use of two custom sections:
type name begin end
init.data_kprobe_blacklist__start_kprobe_blacklist__stop_kprobe_blacklist
text .kprobes.text__kprobes_text_start__kprobes_text_endPort these to the linker table generic solution. This lets us remove all the custom kprobe section declarations on the linker script.
Tested with
CONFIG_KPROBES_SANITY_TEST, it passes with:Quoted 7 lines
Kprobe smoke test: started
Kprobe smoke test: passed successfullyThen tested
CONFIG_SAMPLE_KPROBESondo_fork, and the kprobe bites and kicks as expected. Lastly tried registering a kprobe on a kprobe blacklisted symbol (NOKPROBE_SYMBOL()), and confirms that fails to work.Quoted 4 lines
Could you also check to run the testcases by using ftracetest as below?
$ cd tools/testing/selftests/ftrace/ $ sudo ./ftracetestSure, it all passed:
$ sudo ./ftracetest === Ftrace unit tests === [1] Basic trace file check [PASS] [2] Basic test for tracers [PASS] [3] Basic trace clock test [PASS] [4] Basic event tracing check [PASS] [5] event tracing - enable/disable with event level files [PASS] [6] event tracing - enable/disable with subsystem level files [PASS] [7] event tracing - enable/disable with top level files [PASS] [8] ftrace - function graph filters with stack tracer [PASS] [9] ftrace - function graph filters [PASS] [10] ftrace - function profiler with function tracing [PASS] [11] Test creation and deletion of trace instances [PASS] [12] Kprobe dynamic event - adding and removing [PASS] [13] Kprobe dynamic event - busy event check [PASS] [14] Kprobe dynamic event with arguments [PASS] [15] Kprobe dynamic event with function tracer [PASS] [16] Kretprobe dynamic event with arguments [PASS]
Quoted 7 lines
# of passed: 16 # of failed: 0 # of unresolved: 0 # of untested: 0 # of unsupported: 0 # of xfailed: 0 # of undefined(test bug): 0
The number of tests have grown, this still passes in the new rebase.
Quoted 31 lines
Quoted 1 line
And I'm not sure about linker table.
So there's really a few parts to the linker table work, out of the ones that relate to kprobes:
* linker tables try to generalize our section use, and provide some helpers for common section use
* provides helpers to make it easier to make custom section, but by re-using standard sections
* when a custom section uses standard sections and helpers we also get a few gains:
- developers reviewing code can more easily get a quicker understanding and have expectations set of how the code feature using the custom section could be used
- people grep'ing on the kernel can more easily find specific types of custom section use by looking for the type of interest
- developers adding features do not need to modify
any linker scripts (vmlinux.lds.S) to make use of custom sectionsIn kprobe's case, since it uses two custom sections, we have only a small use for the first case: .kprobe.text is just used as a place holder for future developer annotated special cased executable code. It also makes use of the generic helpers:
LINKTABLE_ADDR_WITHIN(),LINKTABLE_START(),LINKTABLE_END().The second use case, for the
_kprobe_blacklist, makes much more use of the more advanced linker table helpers, for instance the iteratorLINKTABLE_FOR_EACH().
Quoted 5 lines
For both though we now have each custom section's actual section clearly highlighted:
* kprobes: .text (
SECTION_TEXT)
* kprobe blacklist: init.data (SECTION_INIT_DATA)
I ended up splitting this in two patches, in the new v3 series kprobes will go under a simple section range, while the blacklist stuff gets its linker table.
Quoted 31 lines
A reader / developer can more easily gain an understanding of how the above custom sections could be used just by its type.
Another feature of linker tables, but outside of the scope of how kprobe would use linker tables, is the ability to enable folks to avoid code bit rot by using table-$(CONFIG_FOO) instead of oby-$(CONFIG_FOO) on init paths of code but since this is outside of the scope of how kprobe would use I leave that just as a reference as another part of linker table. Unless of course you want to make people force compile all kprobe support code but only have it linked in when actually enabled. That would be outside of the scope and purpose of this patch though.
Quoted 2 lines
Is that possible to support
__kprobesprefix, which moves the functions into kprobes.text?Absolutely, the respective change was just to annotate and make it clear the section kprobes were using:
include/linux/compiler.h +2
-1-# define __kprobes __attribute__((__section__(".kprobes.text"))) +#include <linux/sections.h> +# define __kprobes __attribute__((__section__(SECTION_TBL(SECTION_TEXT, kprobes, all))))Quoted 6 lines
Actually, I'm on the way to replacing
__kprobestoNOKPROBE_SYMBOLmacro, sinceNOKPROBE_SYMBOL()doesn't effect the kernel text itself. On x86, it is already replaced (see commit820aede0209a), and same work should be done on other archs. So, could you hold this after that?Sure.
Quoted 8 lines
Quoted 1 line
I think we should remove .kprobes.text first
You mean just remove the incorrect users of .kprobes.text because as I read what you described above we have abuse of
__kprobesuse to protect against kprobes being introduced on those routines, and we should be usingNOKPROBE_SYMBOL()instead. So from what I gather its not that you will remove .kprobes.text but rather clean our current abuse of__kprobesfor protection to useNOKPROBE_SYMBOL()instead. Is that right?
I never heard back :(
Quoted 3 lines
Quoted 1 line
and move to linker table.
Sure, can you Cc me on your patches? I can follow up later.
And I was never Cc'd on these patches so its unclear if this work is done. I'll be posting a v3 series now.
Luis
H. Peter Anvin
reviewerQuoted 4 lines · Luis R. Rodriguez
This is my v2 of the original linker table work [0], now with six proof of concepts ports of existing code using custom section with custom linker script modifications:
Quoted 9 lines
*
DEFINE_LINKTABLE_TEXT(char, kprobes);
*DEFINE_LINKTABLE_DATA(struct jump_entry, __jump_table);
*DEFINE_LINKTABLE_DATA(struct _ddebug, __verbose);
*DEFINE_LINKTABLE_RO(struct builtin_fw, builtin_fw);
*DEFINE_LINKTABLE_INIT(struct x86_init_fn, x86_init_fns);
*DEFINE_LINKTABLE_INIT_DATA(unsigned long, _kprobe_blacklist);I've tested all except jump tables, I'd appreaciate some help with that.
We should add support for read-mostly, probably. In fact, some of these probably *are* read-mostly.
-hpa
Quoted 12 lines · H. Peter Anvin
Quoted 11 lines · Luis R. Rodriguez
This is my v2 of the original linker table work [0], now with six proof of concepts ports of existing code using custom section with custom linker script modifications:
*
DEFINE_LINKTABLE_TEXT(char, kprobes);
*DEFINE_LINKTABLE_DATA(struct jump_entry, __jump_table);
*DEFINE_LINKTABLE_DATA(struct _ddebug, __verbose);
*DEFINE_LINKTABLE_RO(struct builtin_fw, builtin_fw);
*DEFINE_LINKTABLE_INIT(struct x86_init_fn, x86_init_fns);
*DEFINE_LINKTABLE_INIT_DATA(unsigned long, _kprobe_blacklist);
Quoted 4 lines
Quoted 2 lines
I've tested all except jump tables, I'd appreaciate some help with that.
We should add support for read-mostly, probably.
Sure, any candidate in mind? I actually don't see any hacks built on top of READ_MOSTLY_DATA include/asm-generic/vmlinux.lds.h so pointers appreciated for a case I could try.
Quoted 1 line
In fact, some of these probably *are* read-mostly.
To avoid regressions I made sure to use the same exact section that these original solutions came from, do we want to move some? If so I think perhaps that's best done as a separate atomic patch and it may be easier to read and review once ported on linker tables?
Luis