Skip to content

Commit 6b71b0c

Browse files
nickalcockjfvogel
authored andcommitted
ctf: generate CTF information for the kernel
This introduces a new tool, dwarf2ctf, which runs whenever 'make ctf' is run, extracting information on the kernel's types and global variables from the DWARF-format debug information in the kernel build tree, deduplicating it, and emitting it in Sun's Compact Type Format into a mmappable type archive named vmlinux.ctfa, which is installed at 'make install' time into /lib/modules/$(uname -r)/kernel/. Out-of-tree modules cannot participate in this mechanism since the file is already written: CTF information for such modules is instead linked into such modules at build time as new sections named .SUNW_ctf (as a result, most of the build-time machinery for this is in scripts/Makefile.modpost). Care should be taken not to strip such sections into debug RPMs (they are small enough that this should not be a problem). Within the ctfa file, the type information is divided into a shared repository, containing all types used by more than one module, CTF for the core kernel, and separate CTF for each module built, whether or not this module has been compiled in or not: if a file *could* be built as a module, it will be considered to be a module from the perspective of CTF file emission (and kallmodsyms: see the next commit). This ensures that external consumers such as DTrace always find types for a given module in the same place, regardless of the local kernel configuration, as long as that module is present at all, assisting in portability of D scripts between installations. The ctf_ar tool in libdtrace-ctf can be used to inspect ctfa files, and the ctf_dump tool can be used to look at the ctf files they contain. This process needs a pair of new files, objects.builtin (which lists all object files that are unconditionally built into the kernel and cannot be built as modules) and modules_thick.builtin, which maps from the thin archives that make up built-in modules to their constituent object files. Taken together, these files let dwarf2ctf determine whether a given object file linked into vmlinux.o is part of a module, and if so, which one. There is a single manually-maintained blacklist of structure members dwarf2ctf cannot handle in scripts/dwarf2ctf/member.blacklist: this is used to identify structure members which have different definitions in different object files even though they are defined in the same location in the same source file, usually due to preprocessor magic. (Currently, the only item in this list is present for example purposes only, since the file in question was recently removed from the kernel: dwarf2ctf can these days identify most members needing blacklisting automatically, and will fail with an error if it needs more help. It is quite possible that dwarf2ctf will fail on make allyesconfig kernel configurations and other extreme cases: I hope to track all such bugs down in time.) The documentation for dwarf2ctf is currently somewhat outdated: an update is planned. It remains largely accurate except for some details of the deduplication pass. This introduces new kernel build-time dependencies on elfutils, zlib, glib, and the new libdtrace-ctf package (shared with DTrace userspace). No new runtime dependencies are introduced. Orabug: 30544408 Signed-off-by: Nick Alcock <[email protected]> Signed-off-by: Tomas Jedlicka <[email protected]> Reviewed-by: Kris Van Hees <[email protected]>
1 parent 6a84920 commit 6b71b0c

File tree

17 files changed

+6721
-8
lines changed

17 files changed

+6721
-8
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Module.symvers
4848
modules.builtin
4949
modules.order
5050
modules_thick.builtin
51+
objects.builtin
5152

5253
#
5354
# Top-level generic files
@@ -57,6 +58,7 @@ modules_thick.builtin
5758
/linux
5859
/vmlinux
5960
/vmlinux.32
61+
/vmlinux.ctfa
6062
/vmlinux-gdb.py
6163
/vmlinuz
6264
/System.map

Documentation/dontdiff

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ mkutf8data
179179
modpost
180180
modules.builtin
181181
modules.builtin.modinfo
182+
modules_thick.builtin
182183
modules.order
183184
modules_thick.builtin
184185
modversions.h*

Documentation/dwarf2ctf

Lines changed: 1054 additions & 0 deletions
Large diffs are not rendered by default.

Documentation/process/changes.rst

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,14 @@ iptables 1.4.2 iptables -V
5555
openssl & libcrypto 1.0.0 openssl version
5656
bc 1.06.95 bc --version
5757
Sphinx\ [#f1]_ 1.3 sphinx-build --version
58+
elfutils\ [#f2]_ 0.156 eu-readelf --version
59+
pkg-config\ [#f2]_ 0.16 pkg-config --version
60+
glib\ [#f2]_ 2.x pkg-config --exists glib-2.0 && echo present
61+
libdtrace-ctf\ [#f2]_ 1.1
5862
====================== =============== ========================================
5963

6064
.. [#f1] Sphinx is needed only to build the Kernel documentation
65+
.. [#f2] This is needed at build-time when CTF or DTrace are enabled
6166
6267
Kernel compilation
6368
******************
@@ -84,7 +89,8 @@ pkg-config
8489
The build system, as of 4.18, requires pkg-config to check for installed
8590
kconfig tools and to determine flags settings for use in
8691
'make {g,x}config'. Previously pkg-config was being used but not
87-
verified or documented.
92+
verified or documented. dwarf2ctf also relies on it during 'make ctf' and
93+
while building out-of-tree modules with CONFIG_CTF enabled.
8894

8995
Flex
9096
----
@@ -356,6 +362,21 @@ OpenSSL
356362

357363
- <https://www.openssl.org/>
358364

365+
elfutils
366+
--------
367+
368+
- <https://fedorahosted.org/elfutils/>
369+
370+
glib 2.x
371+
--------
372+
373+
- <http://www.gtk.org/>
374+
375+
libdtrace-ctf
376+
-------------
377+
378+
- <https://oss.oracle.com/git/?p=libdtrace-ctf.git>
379+
359380
System utilities
360381
****************
361382

Makefile

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,45 @@ modules: $(if $(KBUILD_BUILTIN),vmlinux) modules.order modules.builtin
12951295
modules.order: descend
12961296
$(Q)$(AWK) '!x[$$0]++' $(addsuffix /$@, $(build-dirs)) > $@
12971297

1298+
ifneq (CONFIG_CTF@,'@')
1299+
1300+
# We need to force everything to be built, since we need the .o files below.
1301+
KBUILD_BUILTIN := 1
1302+
1303+
# This contains all the object files that are built directly into the
1304+
# kernel (including built-in modules), for consumption by dwarf2ctf in
1305+
# Makefile.modpost.
1306+
# This is made doubly annoying by the presence of '.o' files which are actually
1307+
# thin ar archives, and the need to support file(1) versions too old to
1308+
# recognize them as archives at all. (So we assume that everything that is not
1309+
# an ELF object is an archive.)
1310+
ifeq ($(SRCARCH),x86)
1311+
objects.builtin: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),bzImage) FORCE
1312+
else
1313+
objects.builtin: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) FORCE
1314+
endif
1315+
@echo $(KBUILD_VMLINUX_OBJS) | \
1316+
tr " " "\n" | grep "\.o$$" | xargs -r file | \
1317+
grep ELF | cut -d: -f1 > objects.builtin
1318+
@for archive in $$(echo $(KBUILD_VMLINUX_OBJS) |\
1319+
tr " " "\n" | xargs -r file | grep -v ELF | cut -d: -f1); do \
1320+
$(AR) t "$$archive" >> objects.builtin; \
1321+
done
1322+
1323+
ctf: vmlinux.ctfa
1324+
PHONY += ctf
1325+
1326+
# Making CTF needs the builtin files unless out-of-tree.
1327+
ifeq ($(KBUILD_EXTMOD),)
1328+
vmlinux.ctfa: modules_thick.builtin objects.builtin
1329+
endif
1330+
vmlinux.ctfa:
1331+
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal vmlinux.ctfa
1332+
else
1333+
PHONY += objects.builtin
1334+
objects.builtin:
1335+
endif
1336+
12981337
# Target to prepare building external modules
12991338
PHONY += modules_prepare
13001339
modules_prepare: prepare
@@ -1316,6 +1355,9 @@ _modinst_:
13161355
@sed 's:^:kernel/:' modules.order > $(MODLIB)/modules.order
13171356
@sed 's:^:kernel/:' modules.builtin > $(MODLIB)/modules.builtin
13181357
@cp -f $(objtree)/modules.builtin.modinfo $(MODLIB)/
1358+
@if [ -f $(objtree)/vmlinux.ctfa ] ; then \
1359+
cp -f $(objtree)/vmlinux.ctfa $(MODLIB)/kernel ; \
1360+
fi
13191361
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst
13201362

13211363
# This depmod is only for convenience to give the initial
@@ -1382,8 +1424,8 @@ $(modbuiltin-thick-dirs): include/config/tristate.conf
13821424
# make distclean Remove editor backup files, patch leftover files and the like
13831425

13841426
# Directories & files removed with 'make clean'
1385-
CLEAN_DIRS += include/ksym
1386-
CLEAN_FILES += modules.builtin.modinfo
1427+
CLEAN_DIRS += include/ksym .ctf
1428+
CLEAN_FILES += modules.builtin.modinfo .ctf.filelist .ctf.filelist.raw
13871429

13881430
# Directories & files removed with 'make mrproper'
13891431
MRPROPER_DIRS += include/config include/generated \
@@ -1484,6 +1526,8 @@ help:
14841526
@echo ' (requires a recent binutils and recent build (System.map))'
14851527
@echo ' dir/file.ko - Build module including final link'
14861528
@echo ' modules_prepare - Set up for building external modules'
1529+
@echo ' ctf - Generate CTF type information for DTrace, installed by '
1530+
@echo ' make modules_install'
14871531
@echo ' tags/TAGS - Generate tags file for editors'
14881532
@echo ' cscope - Generate cscope index'
14891533
@echo ' gtags - Generate GNU GLOBAL index'
@@ -1693,9 +1737,9 @@ clean: $(clean-dirs)
16931737
-o -name '*.asn1.[ch]' \
16941738
-o -name '*.symtypes' -o -name 'modules.order' \
16951739
-o -name modules.builtin -o -name '.tmp_*.o.*' \
1696-
-o -name modules_thick.builtin \
1740+
-o -name modules_thick.builtin -o -name objects.builtin \
16971741
-o -name '*.c.[012]*.*' \
1698-
-o -name '*.ll' \
1742+
-o -name '*.ll' -o -name '*.ctfa' \
16991743
-o -name '*.gcno' \) -type f -print | xargs rm -f
17001744

17011745
# Generate tags for editors

lib/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,18 @@ config DIMLIB
565565
#
566566
config LIBFDT
567567
bool
568+
#
569+
# CTF support is select'ed if needed
570+
#
571+
config CTF
572+
bool "Compact Type Format generation"
573+
default y
574+
select STRIP_ASM_SYMS
575+
depends on DEBUG_INFO && !DEBUG_INFO_REDUCED && !DEBUG_INFO_SPLIT && !DEBUG_INFO_DWARF4
576+
help
577+
Emit a compact, compressed description of the kernel's datatypes and
578+
global variables into the vmlinux.ctfa archive (for in-tree modules)
579+
or into .ctf sections in kernel modules (for out-of-tree modules).
568580

569581
config OID_REGISTRY
570582
tristate

scripts/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ hostprogs-y += unifdef
3333

3434
subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
3535
subdir-$(CONFIG_MODVERSIONS) += genksyms
36+
subdir-$(CONFIG_CTF) += dwarf2ctf
3637
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
3738

3839
# Let clean descend into subdirs

scripts/Makefile.modfinal

Lines changed: 138 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
# ===========================================================================
3-
# Module final link
3+
# Module final link and CTF generation
44
# ===========================================================================
5+
# 1) compile all <module>.mod.c files
6+
# 2) for external modules, generate CTF for the module (there is an extra,
7+
# externally-invoked target that does this for the entire kernel but does
8+
# not invoke the rst of the module-building process)
9+
# 3) final link of the module to a <module.ko> file
10+
11+
# We need secondary expansion for 'module-ctfs-modular-prereq', below.
12+
13+
.SECONDEXPANSION:
514

615
PHONY := __modfinal
716
__modfinal:
817

18+
include include/config/auto.conf
919
include $(srctree)/scripts/Kbuild.include
1020

1121
# for c_flags
@@ -27,17 +37,142 @@ quiet_cmd_cc_o_c = CC [M] $@
2737
%.mod.o: %.mod.c FORCE
2838
$(call if_changed_dep,cc_o_c)
2939

40+
# Generate CTF for the entire kernel, or for the module alone if this is a
41+
# build of an external module.
42+
43+
# These are overridden below for standalone modules only.
44+
module-ctfs-modular-prereq =
45+
module-ctfs-modular =
46+
module-ctf-flags =
47+
cmd_touch_ctf =
48+
ctf-dir = ///.nonexistent
49+
cmd-touch-ctf = @:
50+
51+
ifdef CONFIG_CTF
52+
53+
# This is quite tricky. If called for non-external-modules, dwarf2ctf needs to
54+
# be told about all the built-in objects as well as all the external modules --
55+
# but Makefile.modpost only knows about the latter. So the toplevel makefile
56+
# emits the names of the built-in objects into a temporary file, which is
57+
# then catted and its contents used as prerequisites by this rule.
58+
#
59+
# We write the names of the object files to be scanned for CTF content into a
60+
# file, then use that, to avoid hitting command-line length limits.
61+
62+
ifeq ($(KBUILD_EXTMOD),)
63+
ctf-dir-mk :=
64+
quiet_cmd_ctf = CTFA
65+
cmd_ctf = scripts/dwarf2ctf/dwarf2ctf vmlinux.ctfa $(srctree) objects.builtin modules_thick.builtin $(srctree)/scripts/dwarf2ctf/member.blacklist $(ctf-filelist)
66+
ctf-builtins := objects.builtin
67+
ctf-builtins-prereq := $(ctf-builtins)
68+
ctf-modules := $(shell find . -name '*.ko' -print)
69+
ctf-filelist := .ctf.filelist
70+
ctf-filelist-raw := .ctf.filelist.raw
71+
ctf-stamp :=
72+
73+
else
74+
ctf-dir := $(KBUILD_EXTMOD)/.ctf
75+
ctf-dir-mk := $(ctf-dir)
76+
quiet_cmd_ctf = CTF
77+
cmd_ctf = scripts/dwarf2ctf/dwarf2ctf $(ctf-dir) -e $(ctf-filelist)
78+
ctf-builtins := ////.no-builtins
79+
ctf-builtins-prereq :=
80+
ctf-modules := $(modules:.ko=.o)
81+
ctf-filelist := $(ctf-dir)/$(notdir $(M)-extmod).ctf.filelist
82+
ctf-filelist-raw := $(ctf-dir)/$(notdir $(M)-extmod).ctf.filelist.raw
83+
ctf-stamp = $(ctf-dir)/$(notdir $(M)-extmod).stamp
84+
85+
# All the modules' CTF depends on the stamp file.
86+
87+
all-module-ctfs = $(addprefix $(ctf-dir)/,$(notdir $(modules:.ko=.mod.ctf)))
88+
$(all-module-ctfs): $(ctf-stamp)
89+
90+
endif
91+
92+
# Split a list up like shell xargs does.
93+
define xargs =
94+
$(1) $(wordlist 1,1024,$(2))
95+
$(if $(word 1025,$(2)),$(call xargs,$(1),$(wordlist 1025,$(words $(2)),$(2))))
96+
endef
97+
98+
$(ctf-filelist-raw): $(ctf-builtins-prereq) $(ctf-modules)
99+
@rm -f $(ctf-filelist-raw);
100+
@if [[ -n "$(ctf-dir-mk)" ]]; then \
101+
mkdir -p "$(ctf-dir-mk)"; \
102+
fi
103+
$(call xargs,@printf "%s\n" >> $(ctf-filelist-raw),$^)
104+
@touch $(ctf-filelist-raw)
105+
106+
$(ctf-filelist): $(ctf-filelist-raw)
107+
@rm -f $(ctf-filelist);
108+
@cat $(ctf-filelist-raw) | while read -r obj; do \
109+
case $$obj in \
110+
$(ctf-builtins)) cat $$obj >> $(ctf-filelist);; \
111+
*.a) ar t $$obj > $(ctf-filelist);; \
112+
*.builtin) cat $$obj >> $(ctf-filelist);; \
113+
*) echo "$$obj" >> $(ctf-filelist);; \
114+
esac; \
115+
done
116+
@touch $(ctf-filelist)
117+
118+
ifeq ($(KBUILD_EXTMOD),)
119+
# The CTF depends on the output CTF file list, and that depends
120+
# on the .ko files for the modules.
121+
vmlinux.ctfa: $(ctf-filelist)
122+
$(call if_changed,ctf)
123+
else
124+
125+
# The CTF depends on the output CTF file list, and that depends
126+
# on the .o files for the modules
127+
$(ctf-stamp): $(ctf-filelist)
128+
$(call if_changed,ctf)
129+
@shopt -s nullglob; \
130+
for name in $(ctf-dir)/*.ctf.new; do \
131+
$(srctree)/scripts/move-if-change $$name $${name%.new}; \
132+
done; \
133+
touch $(ctf-stamp)
134+
135+
# Expands to the names of the CTF files to be incorporated into this module.
136+
# The former is used in prerequisite lists, thanks to secondary expansion.
137+
138+
module-ctfs-modular-prereq = $$(addprefix $(ctf-dir)/,$$(notdir $$*.mod.ctf))
139+
module-ctfs-modular = $(addprefix $(ctf-dir)/,$(notdir $*.mod.ctf))
140+
141+
# Expands to the name of a CTF file, given a target of a module name given to
142+
# one of the link rules below.
143+
144+
ctf-module-name = $(addprefix $(ctf-dir)/,$(notdir $(basename $@)).mod.ctf)
145+
146+
# An objcopy --add-section argument to add the CTF section to a standalone
147+
# module.
148+
149+
module-ctf-flags = --add-section .ctf=$(ctf-module-name)
150+
151+
# We have to put content in our dummy no-CTF files because --add-section
152+
# in binutils 2.20 silently fails if asked to add an empty file as a section.
153+
154+
cmd_touch_ctf = @for name in $(filter $(ctf-dir)/%,$(module-ctfs-modular)); do \
155+
test -f $$name || dd if=/dev/zero of=$$name bs=1 count=1 2>/dev/null; \
156+
done
157+
158+
endif # KBUILD_EXTMOD
159+
160+
endif # !CONFIG_CTF
161+
30162
ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink)
31163

32164
quiet_cmd_ld_ko_o = LD [M] $@
33165
cmd_ld_ko_o = \
34166
$(LD) -r $(KBUILD_LDFLAGS) \
35167
$(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
36168
$(addprefix -T , $(KBUILD_LDS_MODULE)) \
37-
-o $@ $(filter %.o, $^); \
169+
$(LDFLAGS_$(modname)) -o [email protected] \
170+
-o [email protected] $(patsubst $(ctf-dir)/%,,$(filter %.o, $^)) && \
171+
$(OBJCOPY) $(module-ctf-flags) [email protected] $@ && rm -f [email protected] ; \
38172
$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
39173

40-
$(modules): %.ko: %.o %.mod.o $(KBUILD_LDS_MODULE) FORCE
174+
$(modules): %.ko: %.o %.mod.o $(KBUILD_LDS_MODULE) $(module-ctfs-modular-prereq) FORCE
175+
$(call cmd_touch_ctf)
41176
+$(call if_changed,ld_ko_o)
42177

43178
targets += $(modules) $(modules:.ko=.mod.o)

scripts/dwarf2ctf/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dwarf2ctf

scripts/dwarf2ctf/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
ifdef CONFIG_CTF
2+
hostprogs-y := dwarf2ctf
3+
always := $(hostprogs-y)
4+
5+
dwarf2ctf-objs := dwarf2ctf.o eu_simple.o
6+
7+
HOSTCFLAGS_eu_simple.o := -I$(srctree)/scripts
8+
HOSTCFLAGS_dwarf2ctf.o := $(shell pkg-config --cflags glib-2.0) -I$(srctree)/scripts
9+
10+
HOSTLDLIBS_dwarf2ctf := -ldtrace-ctf -lelf -ldw $(shell pkg-config --libs glib-2.0) -lz
11+
endif

0 commit comments

Comments
 (0)