Skip to contentSkip to conversation

linux: add linker tables

RFC In review Luis R. Rodriguez 10 participants 46 messages Feb 19, 2016 – Jul 21, 2016

Subsystems (24)
lore
Share & tools
lore
#0 lore raw

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
#1 lore raw

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
index d70f9b68174e..f2dfd46bf30a 100644
@@ -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
maintainer
#2 lore raw

Re: [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.h

include/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

#3 lore raw

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.h

include/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

maintainer
#4 lore raw

Re: [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

#5 lore raw

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

#6 lore raw

RFC v2 2/7 tables.h: add linker table support

In reply to Luis R. Rodriguez

A 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
index f2dfd46bf30a..57ff543f4d38 100644
@@ -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
index 13f888a02a3d..a0a35445d968 100644
@@ -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
index 0c2fae8d929d..07b335c67139 100644
@@ -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
index c4bd0e2c173c..eb23738ef4bd 100644
@@ -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
index 7b47bea4956a..53de435e0056 100644
@@ -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
index 2c47f9c305aa..33720528edaf 100644
@@ -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
index 55c96cb8070f..0af1e12c9749 100644
@@ -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
index 2edbcadb3d7f..5c71d1b0631a 100644
@@ -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
new file mode 100644
index 000000000000..cc6f07f11583
@@ -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
#7 lore raw

Re: [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

#8 lore raw

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

#9 lore raw

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 standard SECTION_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

#10 lore raw

Re: [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 of LINKTABLE_TEXT would 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

#11 lore raw

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 of LINKTABLE_TEXT would 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

#12 lore raw

Re: [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

#13 lore raw

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
index d10ab6b9b5e0..d816c659f358 100644
@@ -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

#14 lore raw

Re: [RFC v2 2/7] tables.h: add linker table support

In reply to Luis R. Rodriguez
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.

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);
#15 lore raw

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

#16 lore raw

RFC v2 3/7 firmware: port built-in section to linker table

In reply to 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.

---
 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
index faec7120c508..7ee73cd64c95 100644
@@ -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
index b9250e564ebf..50b9cf3d0294 100644
@@ -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
index e297e1b52636..e13549362577 100644
@@ -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
index eb23738ef4bd..91815fb1f2fa 100644
@@ -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
#17 lore raw

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
#18 lore raw

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

#19 lore raw

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
maintainer
#20 lore raw

Re: [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

#21 lore raw

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

#22 lore raw

Re: [RFC v2 3/7] firmware: port built-in section to linker table

In reply to Kees Cook
Quoted 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

#23 lore raw

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

#24 lore raw

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

#25 lore raw

Re: [RFC v2 3/7] firmware: port built-in section to linker table

In reply to Luis R. Rodriguez
Quoted 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
maintainer
#26 lore raw

Re: [RFC v2 3/7] firmware: port built-in section to linker table

In reply to Luis R. Rodriguez
Quoted 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

maintainer
#27 lore raw

Re: [RFC v2 3/7] firmware: port built-in section to linker table

In reply to David Woodhouse
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?

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

#28 lore raw

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

#29 lore raw

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_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 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

#30 lore raw

RFC v2 4/7 asm/sections: add a generic push_section_tbl()

In reply to 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.

---
 include/asm-generic/sections.h | 10 ++++++++++
 1 file changed, 10 insertions(+)
include/asm-generic/sections.h +10 -0
index af0254c09424..f5ea98bd85d2 100644
@@ -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
#31 lore raw

Re: [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.

---
 include/asm-generic/sections.h | 10 ++++++++++
 1 file changed, 10 insertions(+)
include/asm-generic/sections.h +2 -0
index af0254c09424..f5ea98bd85d2 100644
@@ -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

#32 lore raw

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.

---
 include/asm-generic/sections.h | 10 ++++++++++
 1 file changed, 10 insertions(+)
include/asm-generic/sections.h +2 -0
index af0254c09424..f5ea98bd85d2 100644
@@ -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

#33 lore raw

Re: [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

#34 lore raw

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.

#35 lore raw

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

#36 lore raw

RFC v2 5/7 jump_label: port __jump_table to linker tables

In reply to Luis R. Rodriguez

Move 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
index 34f7b6980d21..c1df4f105df3 100644
@@ -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
index 1b5e0e843c3a..18f5ca294eaa 100644
@@ -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
index e77672539e8e..13e70e290830 100644
@@ -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
index 47e155f15433..5fffc7b12361 100644
@@ -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
index 7f9fd5e3f1bf..1ebfb7ddcb11 100644
@@ -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
index 62d0354d1727..848bece455bb 100644
@@ -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
index adc54c12cbd1..5b80a0e755df 100644
@@ -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
index 91815fb1f2fa..11e1adcbcb24 100644
@@ -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
index 0536524bb9eb..42b68b1e4a39 100644
@@ -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
index 05254eeb4b4e..66d6e24148be 100644
@@ -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
index 9537da37ce87..42249ee8e462 100644
@@ -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
#37 lore raw

RFC v2 6/7 dynamic_debug: port to use linker tables

In reply to Luis R. Rodriguez

This 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
index 11e1adcbcb24..c5fcac902cbe 100644
@@ -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
index 4f1bbc68cd1b..6cd14a22b795 100644
@@ -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
index 42249ee8e462..22d768abb1ec 100644
@@ -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
index fe42b6ec3f0c..ae7b9b4ac022 100644
@@ -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
#38 lore raw

RFC v2 7/7 kprobes: port to linker table

In reply to 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

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
index 894e696bddaa..52f23df2b9b6 100644
@@ -98,7 +98,6 @@ SECTIONS
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
-		KPROBES_TEXT
 		*(.fixup)
 		*(.gnu.warning)
 	}
arch/arm/kernel/entry-armv.S +1 -1
index 3ce377f7251f..4959a83833fd 100644
@@ -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
index 8b60fde5ce48..8de7921ac331 100644
@@ -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
index 7301f4806bbe..c0fe699d0a21 100644
@@ -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
index a4589176bed5..bf4f3f1f9dbb 100644
@@ -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
index c9eec84aa258..8a193fad4c5d 100644
@@ -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
index 5a6e141d1641..a23bed62cec3 100644
@@ -72,7 +72,6 @@ SECTIONS
 		SCHED_TEXT
 		LOCK_TEXT
 		IRQENTRY_TEXT
-		KPROBES_TEXT
 		*(.fixup)
 		*(.gnu.warning)
 	}
arch/hexagon/kernel/vmlinux.lds.S +0 -1
index 5f268c1071b3..a358b699ec64 100644
@@ -51,7 +51,6 @@ SECTIONS
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
-		KPROBES_TEXT
 		*(.fixup)
 	}
 	_etext = .;
arch/ia64/kernel/jprobes.S +1 -1
index f69389c7be1d..c6c23a3e92fb 100644
@@ -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
index dc506b05ffbd..884f36d38989 100644
@@ -47,7 +47,6 @@ SECTIONS {
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
-		KPROBES_TEXT
 		*(.gnu.linkonce.t*)
 	}
 
arch/ia64/lib/flush.S +2 -2
index 1d8c88860063..7f257810e858 100644
@@ -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
index e12055e88bfe..da1689c85bc8 100644
@@ -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
index be9488d69734..94c1c5574a77 100644
@@ -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
index 0a93e83cd014..9183e9235651 100644
@@ -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
index 13c4814c29f8..ead5efc01802 100644
@@ -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
index 326fab40a9de..dc8a84183700 100644
@@ -39,7 +39,6 @@ SECTIONS
 		SCHED_TEXT
 		LOCK_TEXT
 		IRQENTRY_TEXT
-		KPROBES_TEXT
 	} =0
 	_etext = .;
 
arch/openrisc/kernel/vmlinux.lds.S +0 -1
index 2d69a853b742..b010cb75edc4 100644
@@ -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
index 308f29081d46..9d9dc4984465 100644
@@ -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
index 499d9f89435a..4e36e86338f3 100644
@@ -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
index d41fd0af8980..8779ae180783 100644
@@ -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
index cd5a191381b9..b09aa9ab5a1f 100644
@@ -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
index 250f5972536a..376d4bd487c5 100644
@@ -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
index e499370fbccb..4572045b968e 100644
@@ -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
index 445657fe658c..4614b5bcab5e 100644
@@ -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
index 7274b5c4287e..36ebcb3b1215 100644
@@ -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
index db88cbf9eafd..af4f37375345 100644
@@ -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
index f1a2f688b28a..a1c8e3a3ebb6 100644
@@ -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
index b4f4733abc6e..a08fb40656ac 100644
@@ -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
index 0e059a0101ea..0f04268fc394 100644
@@ -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
index 1deffe6cc873..dde4ec0e0185 100644
@@ -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
index 74e4bf11f562..80a9f9106d2a 100644
@@ -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
index f5ea98bd85d2..0438aab5cb58 100644
@@ -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
index c5fcac902cbe..f1420714a549 100644
@@ -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
index 00b042c49ccd..8e33fc1ffd3c 100644
@@ -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
index 8f6849084248..544eb59cdbb9 100644
@@ -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
index d10ab6b9b5e0..d816c659f358 100644
@@ -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
index 48958d3cec9e..b0a8f519efb8 100644
@@ -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
index e167592793a7..f37dac17f033 100644
@@ -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
index 96e2486a6fc4..63e13009dda9 100755
@@ -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
#39 lore raw

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_end

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.

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.
#40 lore raw

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

#41 lore raw

RE: [RFC v2 7/7] kprobes: port to linker table

In reply to Luis R. Rodriguez
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_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:

Quoted 7 lines

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.

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

---

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
index 894e696bddaa..52f23df2b9b6 100644
@@ -98,7 +98,6 @@ SECTIONS
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
-		KPROBES_TEXT
 		*(.fixup)
 		*(.gnu.warning)
 	}
arch/arm/kernel/entry-armv.S +1 -1
index 3ce377f7251f..4959a83833fd 100644
@@ -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
index 8b60fde5ce48..8de7921ac331 100644
@@ -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
index 7301f4806bbe..c0fe699d0a21 100644
@@ -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
index a4589176bed5..bf4f3f1f9dbb 100644
@@ -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
index c9eec84aa258..8a193fad4c5d 100644
@@ -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
index 5a6e141d1641..a23bed62cec3 100644
@@ -72,7 +72,6 @@ SECTIONS
 		SCHED_TEXT
 		LOCK_TEXT
 		IRQENTRY_TEXT
-		KPROBES_TEXT
 		*(.fixup)
 		*(.gnu.warning)
 	}
arch/hexagon/kernel/vmlinux.lds.S +0 -1
index 5f268c1071b3..a358b699ec64 100644
@@ -51,7 +51,6 @@ SECTIONS
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
-		KPROBES_TEXT
 		*(.fixup)
 	}
 	_etext = .;
arch/ia64/kernel/jprobes.S +1 -1
index f69389c7be1d..c6c23a3e92fb 100644
@@ -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
index dc506b05ffbd..884f36d38989 100644
@@ -47,7 +47,6 @@ SECTIONS {
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
-		KPROBES_TEXT
 		*(.gnu.linkonce.t*)
 	}
 
arch/ia64/lib/flush.S +2 -2
index 1d8c88860063..7f257810e858 100644
@@ -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
index e12055e88bfe..da1689c85bc8 100644
@@ -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
index be9488d69734..94c1c5574a77 100644
@@ -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
index 0a93e83cd014..9183e9235651 100644
@@ -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
index 13c4814c29f8..ead5efc01802 100644
@@ -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
index 326fab40a9de..dc8a84183700 100644
@@ -39,7 +39,6 @@ SECTIONS
 		SCHED_TEXT
 		LOCK_TEXT
 		IRQENTRY_TEXT
-		KPROBES_TEXT
 	} =0
 	_etext = .;
 
arch/openrisc/kernel/vmlinux.lds.S +0 -1
index 2d69a853b742..b010cb75edc4 100644
@@ -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
index 308f29081d46..9d9dc4984465 100644
@@ -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
index 499d9f89435a..4e36e86338f3 100644
@@ -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
index d41fd0af8980..8779ae180783 100644
@@ -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 +1 -1
index cd5a191381b9..b09aa9ab5a1f 100644
@@ -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

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
index 250f5972536a..376d4bd487c5 100644
@@ -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
index e499370fbccb..4572045b968e 100644
@@ -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
index 445657fe658c..4614b5bcab5e 100644
@@ -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
index 7274b5c4287e..36ebcb3b1215 100644
@@ -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
index db88cbf9eafd..af4f37375345 100644
@@ -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
index f1a2f688b28a..a1c8e3a3ebb6 100644
@@ -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
index b4f4733abc6e..a08fb40656ac 100644
@@ -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
index 0e059a0101ea..0f04268fc394 100644
@@ -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
index 1deffe6cc873..dde4ec0e0185 100644
@@ -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
index 74e4bf11f562..80a9f9106d2a 100644
@@ -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
index f5ea98bd85d2..0438aab5cb58 100644
@@ -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
index c5fcac902cbe..f1420714a549 100644
@@ -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
index 00b042c49ccd..8e33fc1ffd3c 100644
@@ -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
index 8f6849084248..544eb59cdbb9 100644
@@ -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
index d10ab6b9b5e0..d816c659f358 100644
@@ -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
index 48958d3cec9e..b0a8f519efb8 100644
@@ -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
index e167592793a7..f37dac17f033 100644
@@ -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
index 96e2486a6fc4..63e13009dda9 100755
@@ -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

#42 lore raw

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_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:

Quoted 7 lines

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.

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
__kprobes prefix, 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 __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?

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

#43 lore raw

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_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:

Quoted 7 lines

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.

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]
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 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().

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
__kprobes prefix, 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 __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?

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 __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?

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

#44 lore raw
In reply to Luis R. Rodriguez
Quoted 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

#45 lore raw
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