Merge branch 'misc' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6
* 'misc' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6: (39 commits) Revert "namespace: add source file location exceptions" Coccinelle: Add contextual message Coccinelle: Fix documentation Coccinelle: Find doubled arguments to boolean or bit operators. Coccinelle: Find nested lock+irqsave functions that use the same flags variables. namespace: add source file location exceptions scripts/extract-ikconfig: add support for bzip2, lzma and lzo kbuild: check return value of asprintf() scripts/namespace.pl: improve to get more correct results scripts/namespace.pl: some bug fixes scripts/namespace.pl: update file exclusion list scripts/namespace.pl: fix wrong source path Coccinelle: Use the -no_show_diff option for org and report mode Coccinelle: Add a new mode named 'chain' Coccinelle: Use new comment format to explain kfree.cocci Coccinelle: Improve user information with a new kind of comment Coccinelle: Update documentation MAINTAINERS: Coccinelle: Update email address Documentation/kbuild: modules.txt cleanup Documentation/kbuild: major edit of modules.txt sections 5-8 ...
This commit is contained in:
Коммит
e596c79050
|
@ -24,6 +24,9 @@ of many distributions, e.g. :
|
||||||
You can get the latest version released from the Coccinelle homepage at
|
You can get the latest version released from the Coccinelle homepage at
|
||||||
http://coccinelle.lip6.fr/
|
http://coccinelle.lip6.fr/
|
||||||
|
|
||||||
|
Information and tips about Coccinelle are also provided on the wiki
|
||||||
|
pages at http://cocci.ekstranet.diku.dk/wiki/doku.php
|
||||||
|
|
||||||
Once you have it, run the following command:
|
Once you have it, run the following command:
|
||||||
|
|
||||||
./configure
|
./configure
|
||||||
|
@ -41,20 +44,22 @@ A Coccinelle-specific target is defined in the top level
|
||||||
Makefile. This target is named 'coccicheck' and calls the 'coccicheck'
|
Makefile. This target is named 'coccicheck' and calls the 'coccicheck'
|
||||||
front-end in the 'scripts' directory.
|
front-end in the 'scripts' directory.
|
||||||
|
|
||||||
Four modes are defined: report, patch, context, and org. The mode to
|
Four modes are defined: patch, report, context, and org. The mode to
|
||||||
use is specified by setting the MODE variable with 'MODE=<mode>'.
|
use is specified by setting the MODE variable with 'MODE=<mode>'.
|
||||||
|
|
||||||
|
'patch' proposes a fix, when possible.
|
||||||
|
|
||||||
'report' generates a list in the following format:
|
'report' generates a list in the following format:
|
||||||
file:line:column-column: message
|
file:line:column-column: message
|
||||||
|
|
||||||
'patch' proposes a fix, when possible.
|
|
||||||
|
|
||||||
'context' highlights lines of interest and their context in a
|
'context' highlights lines of interest and their context in a
|
||||||
diff-like style.Lines of interest are indicated with '-'.
|
diff-like style.Lines of interest are indicated with '-'.
|
||||||
|
|
||||||
'org' generates a report in the Org mode format of Emacs.
|
'org' generates a report in the Org mode format of Emacs.
|
||||||
|
|
||||||
Note that not all semantic patches implement all modes.
|
Note that not all semantic patches implement all modes. For easy use
|
||||||
|
of Coccinelle, the default mode is "chain" which tries the previous
|
||||||
|
modes in the order above until one succeeds.
|
||||||
|
|
||||||
To make a report for every semantic patch, run the following command:
|
To make a report for every semantic patch, run the following command:
|
||||||
|
|
||||||
|
@ -68,9 +73,9 @@ To produce patches, run:
|
||||||
|
|
||||||
|
|
||||||
The coccicheck target applies every semantic patch available in the
|
The coccicheck target applies every semantic patch available in the
|
||||||
subdirectories of 'scripts/coccinelle' to the entire Linux kernel.
|
sub-directories of 'scripts/coccinelle' to the entire Linux kernel.
|
||||||
|
|
||||||
For each semantic patch, a changelog message is proposed. It gives a
|
For each semantic patch, a commit message is proposed. It gives a
|
||||||
description of the problem being checked by the semantic patch, and
|
description of the problem being checked by the semantic patch, and
|
||||||
includes a reference to Coccinelle.
|
includes a reference to Coccinelle.
|
||||||
|
|
||||||
|
@ -93,12 +98,35 @@ or
|
||||||
make coccicheck COCCI=<my_SP.cocci> MODE=report
|
make coccicheck COCCI=<my_SP.cocci> MODE=report
|
||||||
|
|
||||||
|
|
||||||
|
Using Coccinelle on (modified) files
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
To apply Coccinelle on a file basis, instead of a directory basis, the
|
||||||
|
following command may be used:
|
||||||
|
|
||||||
|
make C=1 CHECK="scripts/coccicheck"
|
||||||
|
|
||||||
|
To check only newly edited code, use the value 2 for the C flag, i.e.
|
||||||
|
|
||||||
|
make C=2 CHECK="scripts/coccicheck"
|
||||||
|
|
||||||
|
This runs every semantic patch in scripts/coccinelle by default. The
|
||||||
|
COCCI variable may additionally be used to only apply a single
|
||||||
|
semantic patch as shown in the previous section.
|
||||||
|
|
||||||
|
The "chain" mode is the default. You can select another one with the
|
||||||
|
MODE variable explained above.
|
||||||
|
|
||||||
|
In this mode, there is no information about semantic patches
|
||||||
|
displayed, and no commit message proposed.
|
||||||
|
|
||||||
|
|
||||||
Proposing new semantic patches
|
Proposing new semantic patches
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
New semantic patches can be proposed and submitted by kernel
|
New semantic patches can be proposed and submitted by kernel
|
||||||
developers. For sake of clarity, they should be organized in the
|
developers. For sake of clarity, they should be organized in the
|
||||||
subdirectories of 'scripts/coccinelle/'.
|
sub-directories of 'scripts/coccinelle/'.
|
||||||
|
|
||||||
|
|
||||||
Detailed description of the 'report' mode
|
Detailed description of the 'report' mode
|
||||||
|
@ -111,7 +139,7 @@ Example:
|
||||||
|
|
||||||
Running
|
Running
|
||||||
|
|
||||||
make coccicheck MODE=report COCCI=scripts/coccinelle/err_cast.cocci
|
make coccicheck MODE=report COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||||
|
|
||||||
will execute the following part of the SmPL script.
|
will execute the following part of the SmPL script.
|
||||||
|
|
||||||
|
@ -149,7 +177,7 @@ identified.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
Running
|
Running
|
||||||
make coccicheck MODE=patch COCCI=scripts/coccinelle/err_cast.cocci
|
make coccicheck MODE=patch COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||||
|
|
||||||
will execute the following part of the SmPL script.
|
will execute the following part of the SmPL script.
|
||||||
|
|
||||||
|
@ -193,7 +221,7 @@ NOTE: The diff-like output generated is NOT an applicable patch. The
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
Running
|
Running
|
||||||
make coccicheck MODE=context COCCI=scripts/coccinelle/err_cast.cocci
|
make coccicheck MODE=context COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||||
|
|
||||||
will execute the following part of the SmPL script.
|
will execute the following part of the SmPL script.
|
||||||
|
|
||||||
|
@ -228,7 +256,7 @@ diff -u -p /home/user/linux/crypto/ctr.c /tmp/nothing
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
Running
|
Running
|
||||||
make coccicheck MODE=org COCCI=scripts/coccinelle/err_cast.cocci
|
make coccicheck MODE=org COCCI=scripts/coccinelle/api/err_cast.cocci
|
||||||
|
|
||||||
will execute the following part of the SmPL script.
|
will execute the following part of the SmPL script.
|
||||||
|
|
||||||
|
|
|
@ -1,215 +1,185 @@
|
||||||
|
Building External Modules
|
||||||
|
|
||||||
In this document you will find information about:
|
This document describes how to build an out-of-tree kernel module.
|
||||||
- how to build external modules
|
|
||||||
- how to make your module use the kbuild infrastructure
|
|
||||||
- how kbuild will install a kernel
|
|
||||||
- how to install modules in a non-standard location
|
|
||||||
|
|
||||||
=== Table of Contents
|
=== Table of Contents
|
||||||
|
|
||||||
=== 1 Introduction
|
=== 1 Introduction
|
||||||
=== 2 How to build external modules
|
=== 2 How to Build External Modules
|
||||||
--- 2.1 Building external modules
|
--- 2.1 Command Syntax
|
||||||
--- 2.2 Available targets
|
--- 2.2 Options
|
||||||
--- 2.3 Available options
|
--- 2.3 Targets
|
||||||
--- 2.4 Preparing the kernel tree for module build
|
--- 2.4 Building Separate Files
|
||||||
--- 2.5 Building separate files for a module
|
=== 3. Creating a Kbuild File for an External Module
|
||||||
=== 3. Example commands
|
--- 3.1 Shared Makefile
|
||||||
=== 4. Creating a kbuild file for an external module
|
--- 3.2 Separate Kbuild file and Makefile
|
||||||
=== 5. Include files
|
--- 3.3 Binary Blobs
|
||||||
--- 5.1 How to include files from the kernel include dir
|
--- 3.4 Building Multiple Modules
|
||||||
--- 5.2 External modules using an include/ dir
|
=== 4. Include Files
|
||||||
--- 5.3 External modules using several directories
|
--- 4.1 Kernel Includes
|
||||||
=== 6. Module installation
|
--- 4.2 Single Subdirectory
|
||||||
--- 6.1 INSTALL_MOD_PATH
|
--- 4.3 Several Subdirectories
|
||||||
--- 6.2 INSTALL_MOD_DIR
|
=== 5. Module Installation
|
||||||
=== 7. Module versioning & Module.symvers
|
--- 5.1 INSTALL_MOD_PATH
|
||||||
--- 7.1 Symbols from the kernel (vmlinux + modules)
|
--- 5.2 INSTALL_MOD_DIR
|
||||||
--- 7.2 Symbols and external modules
|
=== 6. Module Versioning
|
||||||
--- 7.3 Symbols from another external module
|
--- 6.1 Symbols From the Kernel (vmlinux + modules)
|
||||||
=== 8. Tips & Tricks
|
--- 6.2 Symbols and External Modules
|
||||||
--- 8.1 Testing for CONFIG_FOO_BAR
|
--- 6.3 Symbols From Another External Module
|
||||||
|
=== 7. Tips & Tricks
|
||||||
|
--- 7.1 Testing for CONFIG_FOO_BAR
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
=== 1. Introduction
|
=== 1. Introduction
|
||||||
|
|
||||||
kbuild includes functionality for building modules both
|
"kbuild" is the build system used by the Linux kernel. Modules must use
|
||||||
within the kernel source tree and outside the kernel source tree.
|
kbuild to stay compatible with changes in the build infrastructure and
|
||||||
The latter is usually referred to as external or "out-of-tree"
|
to pick up the right flags to "gcc." Functionality for building modules
|
||||||
modules and is used both during development and for modules that
|
both in-tree and out-of-tree is provided. The method for building
|
||||||
are not planned to be included in the kernel tree.
|
either is similar, and all modules are initially developed and built
|
||||||
|
out-of-tree.
|
||||||
|
|
||||||
What is covered within this file is mainly information to authors
|
Covered in this document is information aimed at developers interested
|
||||||
of modules. The author of an external module should supply
|
in building out-of-tree (or "external") modules. The author of an
|
||||||
a makefile that hides most of the complexity, so one only has to type
|
external module should supply a makefile that hides most of the
|
||||||
'make' to build the module. A complete example will be presented in
|
complexity, so one only has to type "make" to build the module. This is
|
||||||
chapter 4, "Creating a kbuild file for an external module".
|
easily accomplished, and a complete example will be presented in
|
||||||
|
section 3.
|
||||||
|
|
||||||
|
|
||||||
=== 2. How to build external modules
|
=== 2. How to Build External Modules
|
||||||
|
|
||||||
kbuild offers functionality to build external modules, with the
|
To build external modules, you must have a prebuilt kernel available
|
||||||
prerequisite that there is a pre-built kernel available with full source.
|
that contains the configuration and header files used in the build.
|
||||||
A subset of the targets available when building the kernel is available
|
Also, the kernel must have been built with modules enabled. If you are
|
||||||
when building an external module.
|
using a distribution kernel, there will be a package for the kernel you
|
||||||
|
are running provided by your distribution.
|
||||||
|
|
||||||
--- 2.1 Building external modules
|
An alternative is to use the "make" target "modules_prepare." This will
|
||||||
|
make sure the kernel contains the information required. The target
|
||||||
|
exists solely as a simple way to prepare a kernel source tree for
|
||||||
|
building external modules.
|
||||||
|
|
||||||
Use the following command to build an external module:
|
NOTE: "modules_prepare" will not build Module.symvers even if
|
||||||
|
CONFIG_MODVERSIONS is set; therefore, a full kernel build needs to be
|
||||||
|
executed to make module versioning work.
|
||||||
|
|
||||||
make -C <path-to-kernel> M=`pwd`
|
--- 2.1 Command Syntax
|
||||||
|
|
||||||
For the running kernel use:
|
The command to build an external module is:
|
||||||
|
|
||||||
make -C /lib/modules/`uname -r`/build M=`pwd`
|
$ make -C <path_to_kernel_src> M=$PWD
|
||||||
|
|
||||||
For the above command to succeed, the kernel must have been
|
The kbuild system knows that an external module is being built
|
||||||
built with modules enabled.
|
due to the "M=<dir>" option given in the command.
|
||||||
|
|
||||||
To install the modules that were just built:
|
To build against the running kernel use:
|
||||||
|
|
||||||
make -C <path-to-kernel> M=`pwd` modules_install
|
$ make -C /lib/modules/`uname -r`/build M=$PWD
|
||||||
|
|
||||||
More complex examples will be shown later, the above should
|
Then to install the module(s) just built, add the target
|
||||||
be enough to get you started.
|
"modules_install" to the command:
|
||||||
|
|
||||||
--- 2.2 Available targets
|
$ make -C /lib/modules/`uname -r`/build M=$PWD modules_install
|
||||||
|
|
||||||
$KDIR refers to the path to the kernel source top-level directory
|
--- 2.2 Options
|
||||||
|
|
||||||
make -C $KDIR M=`pwd`
|
($KDIR refers to the path of the kernel source directory.)
|
||||||
Will build the module(s) located in current directory.
|
|
||||||
All output files will be located in the same directory
|
|
||||||
as the module source.
|
|
||||||
No attempts are made to update the kernel source, and it is
|
|
||||||
a precondition that a successful make has been executed
|
|
||||||
for the kernel.
|
|
||||||
|
|
||||||
make -C $KDIR M=`pwd` modules
|
make -C $KDIR M=$PWD
|
||||||
The modules target is implied when no target is given.
|
|
||||||
Same functionality as if no target was specified.
|
|
||||||
See description above.
|
|
||||||
|
|
||||||
make -C $KDIR M=`pwd` modules_install
|
-C $KDIR
|
||||||
Install the external module(s).
|
The directory where the kernel source is located.
|
||||||
Installation default is in /lib/modules/<kernel-version>/extra,
|
"make" will actually change to the specified directory
|
||||||
but may be prefixed with INSTALL_MOD_PATH - see separate
|
when executing and will change back when finished.
|
||||||
chapter.
|
|
||||||
|
|
||||||
make -C $KDIR M=`pwd` clean
|
M=$PWD
|
||||||
Remove all generated files for the module - the kernel
|
Informs kbuild that an external module is being built.
|
||||||
source directory is not modified.
|
The value given to "M" is the absolute path of the
|
||||||
|
directory where the external module (kbuild file) is
|
||||||
|
located.
|
||||||
|
|
||||||
make -C $KDIR M=`pwd` help
|
--- 2.3 Targets
|
||||||
help will list the available target when building external
|
|
||||||
modules.
|
|
||||||
|
|
||||||
--- 2.3 Available options:
|
When building an external module, only a subset of the "make"
|
||||||
|
targets are available.
|
||||||
|
|
||||||
$KDIR refers to the path to the kernel source top-level directory
|
make -C $KDIR M=$PWD [target]
|
||||||
|
|
||||||
make -C $KDIR
|
The default will build the module(s) located in the current
|
||||||
Used to specify where to find the kernel source.
|
directory, so a target does not need to be specified. All
|
||||||
'$KDIR' represent the directory where the kernel source is.
|
output files will also be generated in this directory. No
|
||||||
Make will actually change directory to the specified directory
|
attempts are made to update the kernel source, and it is a
|
||||||
when executed but change back when finished.
|
precondition that a successful "make" has been executed for the
|
||||||
|
kernel.
|
||||||
|
|
||||||
make -C $KDIR M=`pwd`
|
modules
|
||||||
M= is used to tell kbuild that an external module is
|
The default target for external modules. It has the
|
||||||
being built.
|
same functionality as if no target was specified. See
|
||||||
The option given to M= is the directory where the external
|
description above.
|
||||||
module (kbuild file) is located.
|
|
||||||
When an external module is being built only a subset of the
|
|
||||||
usual targets are available.
|
|
||||||
|
|
||||||
make -C $KDIR SUBDIRS=`pwd`
|
|
||||||
Same as M=. The SUBDIRS= syntax is kept for backwards
|
|
||||||
compatibility.
|
|
||||||
|
|
||||||
--- 2.4 Preparing the kernel tree for module build
|
|
||||||
|
|
||||||
To make sure the kernel contains the information required to
|
|
||||||
build external modules the target 'modules_prepare' must be used.
|
|
||||||
'modules_prepare' exists solely as a simple way to prepare
|
|
||||||
a kernel source tree for building external modules.
|
|
||||||
Note: modules_prepare will not build Module.symvers even if
|
|
||||||
CONFIG_MODVERSIONS is set. Therefore a full kernel build
|
|
||||||
needs to be executed to make module versioning work.
|
|
||||||
|
|
||||||
--- 2.5 Building separate files for a module
|
|
||||||
It is possible to build single files which are part of a module.
|
|
||||||
This works equally well for the kernel, a module and even for
|
|
||||||
external modules.
|
|
||||||
Examples (module foo.ko, consist of bar.o, baz.o):
|
|
||||||
make -C $KDIR M=`pwd` bar.lst
|
|
||||||
make -C $KDIR M=`pwd` bar.o
|
|
||||||
make -C $KDIR M=`pwd` foo.ko
|
|
||||||
make -C $KDIR M=`pwd` /
|
|
||||||
|
|
||||||
|
|
||||||
=== 3. Example commands
|
|
||||||
|
|
||||||
This example shows the actual commands to be executed when building
|
|
||||||
an external module for the currently running kernel.
|
|
||||||
In the example below, the distribution is supposed to use the
|
|
||||||
facility to locate output files for a kernel compile in a different
|
|
||||||
directory than the kernel source - but the examples will also work
|
|
||||||
when the source and the output files are mixed in the same directory.
|
|
||||||
|
|
||||||
# Kernel source
|
|
||||||
/lib/modules/<kernel-version>/source -> /usr/src/linux-<version>
|
|
||||||
|
|
||||||
# Output from kernel compile
|
|
||||||
/lib/modules/<kernel-version>/build -> /usr/src/linux-<version>-up
|
|
||||||
|
|
||||||
Change to the directory where the kbuild file is located and execute
|
|
||||||
the following commands to build the module:
|
|
||||||
|
|
||||||
cd /home/user/src/module
|
|
||||||
make -C /usr/src/`uname -r`/source \
|
|
||||||
O=/lib/modules/`uname-r`/build \
|
|
||||||
M=`pwd`
|
|
||||||
|
|
||||||
Then, to install the module use the following command:
|
|
||||||
|
|
||||||
make -C /usr/src/`uname -r`/source \
|
|
||||||
O=/lib/modules/`uname-r`/build \
|
|
||||||
M=`pwd` \
|
|
||||||
modules_install
|
modules_install
|
||||||
|
Install the external module(s). The default location is
|
||||||
|
/lib/modules/<kernel_release>/extra/, but a prefix may
|
||||||
|
be added with INSTALL_MOD_PATH (discussed in section 5).
|
||||||
|
|
||||||
If you look closely you will see that this is the same command as
|
clean
|
||||||
listed before - with the directories spelled out.
|
Remove all generated files in the module directory only.
|
||||||
|
|
||||||
The above are rather long commands, and the following chapter
|
help
|
||||||
lists a few tricks to make it all easier.
|
List the available targets for external modules.
|
||||||
|
|
||||||
|
--- 2.4 Building Separate Files
|
||||||
|
|
||||||
|
It is possible to build single files that are part of a module.
|
||||||
|
This works equally well for the kernel, a module, and even for
|
||||||
|
external modules.
|
||||||
|
|
||||||
|
Example (The module foo.ko, consist of bar.o and baz.o):
|
||||||
|
make -C $KDIR M=$PWD bar.lst
|
||||||
|
make -C $KDIR M=$PWD baz.o
|
||||||
|
make -C $KDIR M=$PWD foo.ko
|
||||||
|
make -C $KDIR M=$PWD /
|
||||||
|
|
||||||
|
|
||||||
=== 4. Creating a kbuild file for an external module
|
=== 3. Creating a Kbuild File for an External Module
|
||||||
|
|
||||||
kbuild is the build system for the kernel, and external modules
|
In the last section we saw the command to build a module for the
|
||||||
must use kbuild to stay compatible with changes in the build system
|
running kernel. The module is not actually built, however, because a
|
||||||
and to pick up the right flags to gcc etc.
|
build file is required. Contained in this file will be the name of
|
||||||
|
the module(s) being built, along with the list of requisite source
|
||||||
|
files. The file may be as simple as a single line:
|
||||||
|
|
||||||
The kbuild file used as input shall follow the syntax described
|
obj-m := <module_name>.o
|
||||||
in Documentation/kbuild/makefiles.txt. This chapter will introduce a few
|
|
||||||
more tricks to be used when dealing with external modules.
|
The kbuild system will build <module_name>.o from <module_name>.c,
|
||||||
|
and, after linking, will result in the kernel module <module_name>.ko.
|
||||||
|
The above line can be put in either a "Kbuild" file or a "Makefile."
|
||||||
|
When the module is built from multiple sources, an additional line is
|
||||||
|
needed listing the files:
|
||||||
|
|
||||||
|
<module_name>-y := <src1>.o <src2>.o ...
|
||||||
|
|
||||||
|
NOTE: Further documentation describing the syntax used by kbuild is
|
||||||
|
located in Documentation/kbuild/makefiles.txt.
|
||||||
|
|
||||||
|
The examples below demonstrate how to create a build file for the
|
||||||
|
module 8123.ko, which is built from the following files:
|
||||||
|
|
||||||
In the following a Makefile will be created for a module with the
|
|
||||||
following files:
|
|
||||||
8123_if.c
|
8123_if.c
|
||||||
8123_if.h
|
8123_if.h
|
||||||
8123_pci.c
|
8123_pci.c
|
||||||
8123_bin.o_shipped <= Binary blob
|
8123_bin.o_shipped <= Binary blob
|
||||||
|
|
||||||
--- 4.1 Shared Makefile for module and kernel
|
--- 3.1 Shared Makefile
|
||||||
|
|
||||||
An external module always includes a wrapper Makefile supporting
|
An external module always includes a wrapper makefile that
|
||||||
building the module using 'make' with no arguments.
|
supports building the module using "make" with no arguments.
|
||||||
The Makefile provided will most likely include additional
|
This target is not used by kbuild; it is only for convenience.
|
||||||
functionality such as test targets etc. and this part shall
|
Additional functionality, such as test targets, can be included
|
||||||
be filtered away from kbuild since it may impact kbuild if
|
but should be filtered out from kbuild due to possible name
|
||||||
name clashes occurs.
|
clashes.
|
||||||
|
|
||||||
Example 1:
|
Example 1:
|
||||||
--> filename: Makefile
|
--> filename: Makefile
|
||||||
|
@ -219,11 +189,11 @@ following files:
|
||||||
8123-y := 8123_if.o 8123_pci.o 8123_bin.o
|
8123-y := 8123_if.o 8123_pci.o 8123_bin.o
|
||||||
|
|
||||||
else
|
else
|
||||||
# Normal Makefile
|
# normal makefile
|
||||||
|
KDIR ?= /lib/modules/`uname -r`/build
|
||||||
|
|
||||||
KERNELDIR := /lib/modules/`uname -r`/build
|
default:
|
||||||
all::
|
$(MAKE) -C $(KDIR) M=$$PWD
|
||||||
$(MAKE) -C $(KERNELDIR) M=`pwd` $@
|
|
||||||
|
|
||||||
# Module specific targets
|
# Module specific targets
|
||||||
genbin:
|
genbin:
|
||||||
|
@ -231,15 +201,20 @@ following files:
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
In example 1, the check for KERNELRELEASE is used to separate
|
The check for KERNELRELEASE is used to separate the two parts
|
||||||
the two parts of the Makefile. kbuild will only see the two
|
of the makefile. In the example, kbuild will only see the two
|
||||||
assignments whereas make will see everything except the two
|
assignments, whereas "make" will see everything except these
|
||||||
kbuild assignments.
|
two assignments. This is due to two passes made on the file:
|
||||||
|
the first pass is by the "make" instance run on the command
|
||||||
|
line; the second pass is by the kbuild system, which is
|
||||||
|
initiated by the parameterized "make" in the default target.
|
||||||
|
|
||||||
In recent versions of the kernel, kbuild will look for a file named
|
--- 3.2 Separate Kbuild File and Makefile
|
||||||
Kbuild and as second option look for a file named Makefile.
|
|
||||||
Utilising the Kbuild file makes us split up the Makefile in example 1
|
In newer versions of the kernel, kbuild will first look for a
|
||||||
into two files as shown in example 2:
|
file named "Kbuild," and only if that is not found, will it
|
||||||
|
then look for a makefile. Utilizing a "Kbuild" file allows us
|
||||||
|
to split up the makefile from example 1 into two files:
|
||||||
|
|
||||||
Example 2:
|
Example 2:
|
||||||
--> filename: Kbuild
|
--> filename: Kbuild
|
||||||
|
@ -247,20 +222,21 @@ following files:
|
||||||
8123-y := 8123_if.o 8123_pci.o 8123_bin.o
|
8123-y := 8123_if.o 8123_pci.o 8123_bin.o
|
||||||
|
|
||||||
--> filename: Makefile
|
--> filename: Makefile
|
||||||
KERNELDIR := /lib/modules/`uname -r`/build
|
KDIR ?= /lib/modules/`uname -r`/build
|
||||||
all::
|
|
||||||
$(MAKE) -C $(KERNELDIR) M=`pwd` $@
|
default:
|
||||||
|
$(MAKE) -C $(KDIR) M=$$PWD
|
||||||
|
|
||||||
# Module specific targets
|
# Module specific targets
|
||||||
genbin:
|
genbin:
|
||||||
echo "X" > 8123_bin.o_shipped
|
echo "X" > 8123_bin.o_shipped
|
||||||
|
|
||||||
|
The split in example 2 is questionable due to the simplicity of
|
||||||
|
each file; however, some external modules use makefiles
|
||||||
|
consisting of several hundred lines, and here it really pays
|
||||||
|
off to separate the kbuild part from the rest.
|
||||||
|
|
||||||
In example 2, we are down to two fairly simple files and for simple
|
The next example shows a backward compatible version.
|
||||||
files as used in this example the split is questionable. But some
|
|
||||||
external modules use Makefiles of several hundred lines and here it
|
|
||||||
really pays off to separate the kbuild part from the rest.
|
|
||||||
Example 3 shows a backward compatible version.
|
|
||||||
|
|
||||||
Example 3:
|
Example 3:
|
||||||
--> filename: Kbuild
|
--> filename: Kbuild
|
||||||
|
@ -269,13 +245,15 @@ following files:
|
||||||
|
|
||||||
--> filename: Makefile
|
--> filename: Makefile
|
||||||
ifneq ($(KERNELRELEASE),)
|
ifneq ($(KERNELRELEASE),)
|
||||||
|
# kbuild part of makefile
|
||||||
include Kbuild
|
include Kbuild
|
||||||
else
|
|
||||||
# Normal Makefile
|
|
||||||
|
|
||||||
KERNELDIR := /lib/modules/`uname -r`/build
|
else
|
||||||
all::
|
# normal makefile
|
||||||
$(MAKE) -C $(KERNELDIR) M=`pwd` $@
|
KDIR ?= /lib/modules/`uname -r`/build
|
||||||
|
|
||||||
|
default:
|
||||||
|
$(MAKE) -C $(KDIR) M=$$PWD
|
||||||
|
|
||||||
# Module specific targets
|
# Module specific targets
|
||||||
genbin:
|
genbin:
|
||||||
|
@ -283,260 +261,271 @@ following files:
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
The trick here is to include the Kbuild file from Makefile, so
|
Here the "Kbuild" file is included from the makefile. This
|
||||||
if an older version of kbuild picks up the Makefile, the Kbuild
|
allows an older version of kbuild, which only knows of
|
||||||
file will be included.
|
makefiles, to be used when the "make" and kbuild parts are
|
||||||
|
split into separate files.
|
||||||
|
|
||||||
--- 4.2 Binary blobs included in a module
|
--- 3.3 Binary Blobs
|
||||||
|
|
||||||
Some external modules needs to include a .o as a blob. kbuild
|
Some external modules need to include an object file as a blob.
|
||||||
has support for this, but requires the blob file to be named
|
kbuild has support for this, but requires the blob file to be
|
||||||
<filename>_shipped. In our example the blob is named
|
named <filename>_shipped. When the kbuild rules kick in, a copy
|
||||||
8123_bin.o_shipped and when the kbuild rules kick in the file
|
of <filename>_shipped is created with _shipped stripped off,
|
||||||
8123_bin.o is created as a simple copy off the 8213_bin.o_shipped file
|
giving us <filename>. This shortened filename can be used in
|
||||||
with the _shipped part stripped of the filename.
|
the assignment to the module.
|
||||||
This allows the 8123_bin.o filename to be used in the assignment to
|
|
||||||
the module.
|
Throughout this section, 8123_bin.o_shipped has been used to
|
||||||
|
build the kernel module 8123.ko; it has been included as
|
||||||
|
8123_bin.o.
|
||||||
|
|
||||||
Example 4:
|
|
||||||
obj-m := 8123.o
|
|
||||||
8123-y := 8123_if.o 8123_pci.o 8123_bin.o
|
8123-y := 8123_if.o 8123_pci.o 8123_bin.o
|
||||||
|
|
||||||
In example 4, there is no distinction between the ordinary .c/.h files
|
Although there is no distinction between the ordinary source
|
||||||
and the binary file. But kbuild will pick up different rules to create
|
files and the binary file, kbuild will pick up different rules
|
||||||
the .o file.
|
when creating the object file for the module.
|
||||||
|
|
||||||
|
--- 3.4 Building Multiple Modules
|
||||||
|
|
||||||
|
kbuild supports building multiple modules with a single build
|
||||||
|
file. For example, if you wanted to build two modules, foo.ko
|
||||||
|
and bar.ko, the kbuild lines would be:
|
||||||
|
|
||||||
|
obj-m := foo.o bar.o
|
||||||
|
foo-y := <foo_srcs>
|
||||||
|
bar-y := <bar_srcs>
|
||||||
|
|
||||||
|
It is that simple!
|
||||||
|
|
||||||
|
|
||||||
=== 5. Include files
|
=== 4. Include Files
|
||||||
|
|
||||||
Include files are a necessity when a .c file uses something from other .c
|
Within the kernel, header files are kept in standard locations
|
||||||
files (not strictly in the sense of C, but if good programming practice is
|
according to the following rule:
|
||||||
used). Any module that consists of more than one .c file will have a .h file
|
|
||||||
for one of the .c files.
|
|
||||||
|
|
||||||
- If the .h file only describes a module internal interface, then the .h file
|
* If the header file only describes the internal interface of a
|
||||||
shall be placed in the same directory as the .c files.
|
module, then the file is placed in the same directory as the
|
||||||
- If the .h files describe an interface used by other parts of the kernel
|
source files.
|
||||||
located in different directories, the .h files shall be located in
|
* If the header file describes an interface used by other parts
|
||||||
include/linux/ or other include/ directories as appropriate.
|
of the kernel that are located in different directories, then
|
||||||
|
the file is placed in include/linux/.
|
||||||
|
|
||||||
One exception for this rule is larger subsystems that have their own directory
|
NOTE: There are two notable exceptions to this rule: larger
|
||||||
under include/ such as include/scsi. Another exception is arch-specific
|
subsystems have their own directory under include/, such as
|
||||||
.h files which are located under include/asm-$(ARCH)/*.
|
include/scsi; and architecture specific headers are located
|
||||||
|
under arch/$(ARCH)/include/.
|
||||||
|
|
||||||
External modules have a tendency to locate include files in a separate include/
|
--- 4.1 Kernel Includes
|
||||||
directory and therefore need to deal with this in their kbuild file.
|
|
||||||
|
|
||||||
--- 5.1 How to include files from the kernel include dir
|
To include a header file located under include/linux/, simply
|
||||||
|
use:
|
||||||
|
|
||||||
When a module needs to include a file from include/linux/, then one
|
#include <linux/module.h>
|
||||||
just uses:
|
|
||||||
|
|
||||||
#include <linux/modules.h>
|
kbuild will add options to "gcc" so the relevant directories
|
||||||
|
are searched.
|
||||||
|
|
||||||
kbuild will make sure to add options to gcc so the relevant
|
--- 4.2 Single Subdirectory
|
||||||
directories are searched.
|
|
||||||
Likewise for .h files placed in the same directory as the .c file.
|
|
||||||
|
|
||||||
#include "8123_if.h"
|
External modules tend to place header files in a separate
|
||||||
|
include/ directory where their source is located, although this
|
||||||
|
is not the usual kernel style. To inform kbuild of the
|
||||||
|
directory, use either ccflags-y or CFLAGS_<filename>.o.
|
||||||
|
|
||||||
will do the job.
|
Using the example from section 3, if we moved 8123_if.h to a
|
||||||
|
subdirectory named include, the resulting kbuild file would
|
||||||
--- 5.2 External modules using an include/ dir
|
look like:
|
||||||
|
|
||||||
External modules often locate their .h files in a separate include/
|
|
||||||
directory although this is not usual kernel style. When an external
|
|
||||||
module uses an include/ dir then kbuild needs to be told so.
|
|
||||||
The trick here is to use either EXTRA_CFLAGS (take effect for all .c
|
|
||||||
files) or CFLAGS_$F.o (take effect only for a single file).
|
|
||||||
|
|
||||||
In our example, if we move 8123_if.h to a subdirectory named include/
|
|
||||||
the resulting Kbuild file would look like:
|
|
||||||
|
|
||||||
--> filename: Kbuild
|
--> filename: Kbuild
|
||||||
obj-m := 8123.o
|
obj-m := 8123.o
|
||||||
|
|
||||||
EXTRA_CFLAGS := -Iinclude
|
ccflags-y := -Iinclude
|
||||||
8123-y := 8123_if.o 8123_pci.o 8123_bin.o
|
8123-y := 8123_if.o 8123_pci.o 8123_bin.o
|
||||||
|
|
||||||
Note that in the assignment there is no space between -I and the path.
|
Note that in the assignment there is no space between -I and
|
||||||
This is a kbuild limitation: there must be no space present.
|
the path. This is a limitation of kbuild: there must be no
|
||||||
|
space present.
|
||||||
|
|
||||||
--- 5.3 External modules using several directories
|
--- 4.3 Several Subdirectories
|
||||||
|
|
||||||
If an external module does not follow the usual kernel style, but
|
|
||||||
decides to spread files over several directories, then kbuild can
|
|
||||||
handle this too.
|
|
||||||
|
|
||||||
|
kbuild can handle files that are spread over several directories.
|
||||||
Consider the following example:
|
Consider the following example:
|
||||||
|
|
||||||
|
|
.
|
||||||
+- src/complex_main.c
|
|__ src
|
||||||
| +- hal/hardwareif.c
|
| |__ complex_main.c
|
||||||
| +- hal/include/hardwareif.h
|
| |__ hal
|
||||||
+- include/complex.h
|
| |__ hardwareif.c
|
||||||
|
| |__ include
|
||||||
|
| |__ hardwareif.h
|
||||||
|
|__ include
|
||||||
|
|__ complex.h
|
||||||
|
|
||||||
To build a single module named complex.ko, we then need the following
|
To build the module complex.ko, we then need the following
|
||||||
kbuild file:
|
kbuild file:
|
||||||
|
|
||||||
Kbuild:
|
--> filename: Kbuild
|
||||||
obj-m := complex.o
|
obj-m := complex.o
|
||||||
complex-y := src/complex_main.o
|
complex-y := src/complex_main.o
|
||||||
complex-y += src/hal/hardwareif.o
|
complex-y += src/hal/hardwareif.o
|
||||||
|
|
||||||
EXTRA_CFLAGS := -I$(src)/include
|
ccflags-y := -I$(src)/include
|
||||||
EXTRA_CFLAGS += -I$(src)src/hal/include
|
ccflags-y += -I$(src)/src/hal/include
|
||||||
|
|
||||||
|
As you can see, kbuild knows how to handle object files located
|
||||||
|
in other directories. The trick is to specify the directory
|
||||||
|
relative to the kbuild file's location. That being said, this
|
||||||
|
is NOT recommended practice.
|
||||||
|
|
||||||
|
For the header files, kbuild must be explicitly told where to
|
||||||
|
look. When kbuild executes, the current directory is always the
|
||||||
|
root of the kernel tree (the argument to "-C") and therefore an
|
||||||
|
absolute path is needed. $(src) provides the absolute path by
|
||||||
|
pointing to the directory where the currently executing kbuild
|
||||||
|
file is located.
|
||||||
|
|
||||||
|
|
||||||
kbuild knows how to handle .o files located in another directory -
|
=== 5. Module Installation
|
||||||
although this is NOT recommended practice. The syntax is to specify
|
|
||||||
the directory relative to the directory where the Kbuild file is
|
|
||||||
located.
|
|
||||||
|
|
||||||
To find the .h files, we have to explicitly tell kbuild where to look
|
Modules which are included in the kernel are installed in the
|
||||||
for the .h files. When kbuild executes, the current directory is always
|
directory:
|
||||||
the root of the kernel tree (argument to -C) and therefore we have to
|
|
||||||
tell kbuild how to find the .h files using absolute paths.
|
|
||||||
$(src) will specify the absolute path to the directory where the
|
|
||||||
Kbuild file are located when being build as an external module.
|
|
||||||
Therefore -I$(src)/ is used to point out the directory of the Kbuild
|
|
||||||
file and any additional path are just appended.
|
|
||||||
|
|
||||||
=== 6. Module installation
|
/lib/modules/$(KERNELRELEASE)/kernel/
|
||||||
|
|
||||||
Modules which are included in the kernel are installed in the directory:
|
And external modules are installed in:
|
||||||
|
|
||||||
/lib/modules/$(KERNELRELEASE)/kernel
|
/lib/modules/$(KERNELRELEASE)/extra/
|
||||||
|
|
||||||
External modules are installed in the directory:
|
--- 5.1 INSTALL_MOD_PATH
|
||||||
|
|
||||||
/lib/modules/$(KERNELRELEASE)/extra
|
Above are the default directories but as always some level of
|
||||||
|
customization is possible. A prefix can be added to the
|
||||||
--- 6.1 INSTALL_MOD_PATH
|
installation path using the variable INSTALL_MOD_PATH:
|
||||||
|
|
||||||
Above are the default directories, but as always, some level of
|
|
||||||
customization is possible. One can prefix the path using the variable
|
|
||||||
INSTALL_MOD_PATH:
|
|
||||||
|
|
||||||
$ make INSTALL_MOD_PATH=/frodo modules_install
|
$ make INSTALL_MOD_PATH=/frodo modules_install
|
||||||
=> Install dir: /frodo/lib/modules/$(KERNELRELEASE)/kernel
|
=> Install dir: /frodo/lib/modules/$(KERNELRELEASE)/kernel/
|
||||||
|
|
||||||
INSTALL_MOD_PATH may be set as an ordinary shell variable or as in the
|
INSTALL_MOD_PATH may be set as an ordinary shell variable or,
|
||||||
example above, can be specified on the command line when calling make.
|
as shown above, can be specified on the command line when
|
||||||
INSTALL_MOD_PATH has effect both when installing modules included in
|
calling "make." This has effect when installing both in-tree
|
||||||
the kernel as well as when installing external modules.
|
and out-of-tree modules.
|
||||||
|
|
||||||
--- 6.2 INSTALL_MOD_DIR
|
--- 5.2 INSTALL_MOD_DIR
|
||||||
|
|
||||||
When installing external modules they are by default installed to a
|
External modules are by default installed to a directory under
|
||||||
directory under /lib/modules/$(KERNELRELEASE)/extra, but one may wish
|
/lib/modules/$(KERNELRELEASE)/extra/, but you may wish to
|
||||||
to locate modules for a specific functionality in a separate
|
locate modules for a specific functionality in a separate
|
||||||
directory. For this purpose, one can use INSTALL_MOD_DIR to specify an
|
directory. For this purpose, use INSTALL_MOD_DIR to specify an
|
||||||
alternative name to 'extra'.
|
alternative name to "extra."
|
||||||
|
|
||||||
$ make INSTALL_MOD_DIR=gandalf -C KERNELDIR \
|
$ make INSTALL_MOD_DIR=gandalf -C $KDIR \
|
||||||
M=`pwd` modules_install
|
M=$PWD modules_install
|
||||||
=> Install dir: /lib/modules/$(KERNELRELEASE)/gandalf
|
=> Install dir: /lib/modules/$(KERNELRELEASE)/gandalf/
|
||||||
|
|
||||||
|
|
||||||
=== 7. Module versioning & Module.symvers
|
=== 6. Module Versioning
|
||||||
|
|
||||||
Module versioning is enabled by the CONFIG_MODVERSIONS tag.
|
Module versioning is enabled by the CONFIG_MODVERSIONS tag, and is used
|
||||||
|
as a simple ABI consistency check. A CRC value of the full prototype
|
||||||
|
for an exported symbol is created. When a module is loaded/used, the
|
||||||
|
CRC values contained in the kernel are compared with similar values in
|
||||||
|
the module; if they are not equal, the kernel refuses to load the
|
||||||
|
module.
|
||||||
|
|
||||||
Module versioning is used as a simple ABI consistency check. The Module
|
Module.symvers contains a list of all exported symbols from a kernel
|
||||||
versioning creates a CRC value of the full prototype for an exported symbol and
|
build.
|
||||||
when a module is loaded/used then the CRC values contained in the kernel are
|
|
||||||
compared with similar values in the module. If they are not equal, then the
|
|
||||||
kernel refuses to load the module.
|
|
||||||
|
|
||||||
Module.symvers contains a list of all exported symbols from a kernel build.
|
--- 6.1 Symbols From the Kernel (vmlinux + modules)
|
||||||
|
|
||||||
--- 7.1 Symbols from the kernel (vmlinux + modules)
|
During a kernel build, a file named Module.symvers will be
|
||||||
|
generated. Module.symvers contains all exported symbols from
|
||||||
During a kernel build, a file named Module.symvers will be generated.
|
the kernel and compiled modules. For each symbol, the
|
||||||
Module.symvers contains all exported symbols from the kernel and
|
corresponding CRC value is also stored.
|
||||||
compiled modules. For each symbols, the corresponding CRC value
|
|
||||||
is stored too.
|
|
||||||
|
|
||||||
The syntax of the Module.symvers file is:
|
The syntax of the Module.symvers file is:
|
||||||
<CRC> <Symbol> <module>
|
<CRC> <Symbol> <module>
|
||||||
Sample:
|
|
||||||
0x2d036834 scsi_remove_host drivers/scsi/scsi_mod
|
0x2d036834 scsi_remove_host drivers/scsi/scsi_mod
|
||||||
|
|
||||||
For a kernel build without CONFIG_MODVERSIONS enabled, the crc
|
For a kernel build without CONFIG_MODVERSIONS enabled, the CRC
|
||||||
would read: 0x00000000
|
would read 0x00000000.
|
||||||
|
|
||||||
Module.symvers serves two purposes:
|
Module.symvers serves two purposes:
|
||||||
1) It lists all exported symbols both from vmlinux and all modules
|
1) It lists all exported symbols from vmlinux and all modules.
|
||||||
2) It lists the CRC if CONFIG_MODVERSIONS is enabled
|
2) It lists the CRC if CONFIG_MODVERSIONS is enabled.
|
||||||
|
|
||||||
--- 7.2 Symbols and external modules
|
--- 6.2 Symbols and External Modules
|
||||||
|
|
||||||
When building an external module, the build system needs access to
|
When building an external module, the build system needs access
|
||||||
the symbols from the kernel to check if all external symbols are
|
to the symbols from the kernel to check if all external symbols
|
||||||
defined. This is done in the MODPOST step and to obtain all
|
are defined. This is done in the MODPOST step. modpost obtains
|
||||||
symbols, modpost reads Module.symvers from the kernel.
|
the symbols by reading Module.symvers from the kernel source
|
||||||
If a Module.symvers file is present in the directory where
|
tree. If a Module.symvers file is present in the directory
|
||||||
the external module is being built, this file will be read too.
|
where the external module is being built, this file will be
|
||||||
During the MODPOST step, a new Module.symvers file will be written
|
read too. During the MODPOST step, a new Module.symvers file
|
||||||
containing all exported symbols that were not defined in the kernel.
|
will be written containing all exported symbols that were not
|
||||||
|
defined in the kernel.
|
||||||
|
|
||||||
--- 7.3 Symbols from another external module
|
--- 6.3 Symbols From Another External Module
|
||||||
|
|
||||||
Sometimes, an external module uses exported symbols from another
|
Sometimes, an external module uses exported symbols from
|
||||||
external module. Kbuild needs to have full knowledge on all symbols
|
another external module. kbuild needs to have full knowledge of
|
||||||
to avoid spitting out warnings about undefined symbols.
|
all symbols to avoid spitting out warnings about undefined
|
||||||
Three solutions exist to let kbuild know all symbols of more than
|
symbols. Three solutions exist for this situation.
|
||||||
one external module.
|
|
||||||
The method with a top-level kbuild file is recommended but may be
|
|
||||||
impractical in certain situations.
|
|
||||||
|
|
||||||
Use a top-level Kbuild file
|
NOTE: The method with a top-level kbuild file is recommended
|
||||||
If you have two modules: 'foo' and 'bar', and 'foo' needs
|
but may be impractical in certain situations.
|
||||||
symbols from 'bar', then one can use a common top-level kbuild
|
|
||||||
file so both modules are compiled in same build.
|
|
||||||
|
|
||||||
Consider following directory layout:
|
Use a top-level kbuild file
|
||||||
./foo/ <= contains the foo module
|
If you have two modules, foo.ko and bar.ko, where
|
||||||
./bar/ <= contains the bar module
|
foo.ko needs symbols from bar.ko, you can use a
|
||||||
The top-level Kbuild file would then look like:
|
common top-level kbuild file so both modules are
|
||||||
|
compiled in the same build. Consider the following
|
||||||
|
directory layout:
|
||||||
|
|
||||||
#./Kbuild: (this file may also be named Makefile)
|
./foo/ <= contains foo.ko
|
||||||
|
./bar/ <= contains bar.ko
|
||||||
|
|
||||||
|
The top-level kbuild file would then look like:
|
||||||
|
|
||||||
|
#./Kbuild (or ./Makefile):
|
||||||
obj-y := foo/ bar/
|
obj-y := foo/ bar/
|
||||||
|
|
||||||
Executing:
|
And executing
|
||||||
make -C $KDIR M=`pwd`
|
|
||||||
|
|
||||||
will then do the expected and compile both modules with full
|
$ make -C $KDIR M=$PWD
|
||||||
knowledge on symbols from both modules.
|
|
||||||
|
will then do the expected and compile both modules with
|
||||||
|
full knowledge of symbols from either module.
|
||||||
|
|
||||||
Use an extra Module.symvers file
|
Use an extra Module.symvers file
|
||||||
When an external module is built, a Module.symvers file is
|
When an external module is built, a Module.symvers file
|
||||||
generated containing all exported symbols which are not
|
is generated containing all exported symbols which are
|
||||||
defined in the kernel.
|
not defined in the kernel. To get access to symbols
|
||||||
To get access to symbols from module 'bar', one can copy the
|
from bar.ko, copy the Module.symvers file from the
|
||||||
Module.symvers file from the compilation of the 'bar' module
|
compilation of bar.ko to the directory where foo.ko is
|
||||||
to the directory where the 'foo' module is built.
|
built. During the module build, kbuild will read the
|
||||||
During the module build, kbuild will read the Module.symvers
|
Module.symvers file in the directory of the external
|
||||||
file in the directory of the external module and when the
|
module, and when the build is finished, a new
|
||||||
build is finished, a new Module.symvers file is created
|
Module.symvers file is created containing the sum of
|
||||||
containing the sum of all symbols defined and not part of the
|
all symbols defined and not part of the kernel.
|
||||||
kernel.
|
|
||||||
|
|
||||||
Use make variable KBUILD_EXTRA_SYMBOLS in the Makefile
|
Use "make" variable KBUILD_EXTRA_SYMBOLS
|
||||||
If it is impractical to copy Module.symvers from another
|
If it is impractical to copy Module.symvers from
|
||||||
module, you can assign a space separated list of files to
|
another module, you can assign a space separated list
|
||||||
KBUILD_EXTRA_SYMBOLS in your Makfile. These files will be
|
of files to KBUILD_EXTRA_SYMBOLS in your build file.
|
||||||
loaded by modpost during the initialisation of its symbol
|
These files will be loaded by modpost during the
|
||||||
tables.
|
initialization of its symbol tables.
|
||||||
|
|
||||||
=== 8. Tips & Tricks
|
|
||||||
|
|
||||||
--- 8.1 Testing for CONFIG_FOO_BAR
|
=== 7. Tips & Tricks
|
||||||
|
|
||||||
Modules often need to check for certain CONFIG_ options to decide if
|
--- 7.1 Testing for CONFIG_FOO_BAR
|
||||||
a specific feature shall be included in the module. When kbuild is used
|
|
||||||
this is done by referencing the CONFIG_ variable directly.
|
Modules often need to check for certain CONFIG_ options to
|
||||||
|
decide if a specific feature is included in the module. In
|
||||||
|
kbuild this is done by referencing the CONFIG_ variable
|
||||||
|
directly.
|
||||||
|
|
||||||
#fs/ext2/Makefile
|
#fs/ext2/Makefile
|
||||||
obj-$(CONFIG_EXT2_FS) += ext2.o
|
obj-$(CONFIG_EXT2_FS) += ext2.o
|
||||||
|
@ -544,9 +533,9 @@ Module.symvers contains a list of all exported symbols from a kernel build.
|
||||||
ext2-y := balloc.o bitmap.o dir.o
|
ext2-y := balloc.o bitmap.o dir.o
|
||||||
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o
|
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o
|
||||||
|
|
||||||
External modules have traditionally used grep to check for specific
|
External modules have traditionally used "grep" to check for
|
||||||
CONFIG_ settings directly in .config. This usage is broken.
|
specific CONFIG_ settings directly in .config. This usage is
|
||||||
As introduced before, external modules shall use kbuild when building
|
broken. As introduced before, external modules should use
|
||||||
and therefore can use the same methods as in-kernel modules when
|
kbuild for building and can therefore use the same methods as
|
||||||
testing for CONFIG_ definitions.
|
in-tree modules when testing for CONFIG_ definitions.
|
||||||
|
|
||||||
|
|
|
@ -1613,7 +1613,7 @@ F: drivers/platform/x86/classmate-laptop.c
|
||||||
COCCINELLE/Semantic Patches (SmPL)
|
COCCINELLE/Semantic Patches (SmPL)
|
||||||
M: Julia Lawall <julia@diku.dk>
|
M: Julia Lawall <julia@diku.dk>
|
||||||
M: Gilles Muller <Gilles.Muller@lip6.fr>
|
M: Gilles Muller <Gilles.Muller@lip6.fr>
|
||||||
M: Nicolas Palix <npalix@diku.dk>
|
M: Nicolas Palix <npalix.work@gmail.com>
|
||||||
L: cocci@diku.dk (moderated for non-subscribers)
|
L: cocci@diku.dk (moderated for non-subscribers)
|
||||||
W: http://coccinelle.lip6.fr/
|
W: http://coccinelle.lip6.fr/
|
||||||
S: Supported
|
S: Supported
|
||||||
|
|
|
@ -333,7 +333,10 @@ static void docsect(char *filename, char *line)
|
||||||
if (*s == '\n')
|
if (*s == '\n')
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
|
|
||||||
asprintf(&s, "DOC: %s", line);
|
if (asprintf(&s, "DOC: %s", line) < 0) {
|
||||||
|
perror("asprintf");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
consume_symbol(s);
|
consume_symbol(s);
|
||||||
free(s);
|
free(s);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ if [ "$C" = "1" -o "$C" = "2" ]; then
|
||||||
else
|
else
|
||||||
ONLINE=0
|
ONLINE=0
|
||||||
FLAGS="-very_quiet"
|
FLAGS="-very_quiet"
|
||||||
|
OPTIONS="-dir $srctree"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -x "$SPATCH" ]; then
|
if [ ! -x "$SPATCH" ]; then
|
||||||
|
@ -25,11 +26,13 @@ fi
|
||||||
|
|
||||||
if [ "$MODE" = "" ] ; then
|
if [ "$MODE" = "" ] ; then
|
||||||
if [ "$ONLINE" = "0" ] ; then
|
if [ "$ONLINE" = "0" ] ; then
|
||||||
echo 'You have not explicitly specify the mode to use. Fallback to "report".'
|
echo 'You have not explicitly specified the mode to use. Using default "chain" mode.'
|
||||||
|
echo 'All available modes will be tried (in that order): patch, report, context, org'
|
||||||
echo 'You can specify the mode with "make coccicheck MODE=<mode>"'
|
echo 'You can specify the mode with "make coccicheck MODE=<mode>"'
|
||||||
echo 'Available modes are: report, patch, context, org'
|
|
||||||
fi
|
fi
|
||||||
MODE="report"
|
MODE="chain"
|
||||||
|
elif [ "$MODE" = "report" -o "$MODE" = "org" ] ; then
|
||||||
|
FLAGS="$FLAGS -no_show_diff"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$ONLINE" = "0" ] ; then
|
if [ "$ONLINE" = "0" ] ; then
|
||||||
|
@ -44,7 +47,7 @@ coccinelle () {
|
||||||
|
|
||||||
OPT=`grep "Option" $COCCI | cut -d':' -f2`
|
OPT=`grep "Option" $COCCI | cut -d':' -f2`
|
||||||
|
|
||||||
# The option '-parse_cocci' can be used to syntaxically check the SmPL files.
|
# The option '-parse_cocci' can be used to syntactically check the SmPL files.
|
||||||
#
|
#
|
||||||
# $SPATCH -D $MODE $FLAGS -parse_cocci $COCCI $OPT > /dev/null
|
# $SPATCH -D $MODE $FLAGS -parse_cocci $COCCI $OPT > /dev/null
|
||||||
|
|
||||||
|
@ -52,19 +55,42 @@ coccinelle () {
|
||||||
|
|
||||||
FILE=`echo $COCCI | sed "s|$srctree/||"`
|
FILE=`echo $COCCI | sed "s|$srctree/||"`
|
||||||
|
|
||||||
echo "Processing `basename $COCCI` with option(s) \"$OPT\""
|
echo "Processing `basename $COCCI`"
|
||||||
|
echo "with option(s) \"$OPT\""
|
||||||
|
echo ''
|
||||||
echo 'Message example to submit a patch:'
|
echo 'Message example to submit a patch:'
|
||||||
|
|
||||||
sed -e '/\/\/\//!d' -e 's|^///||' $COCCI
|
sed -ne 's|^///||p' $COCCI
|
||||||
|
|
||||||
|
if [ "$MODE" = "patch" ] ; then
|
||||||
echo ' The semantic patch that makes this change is available'
|
echo ' The semantic patch that makes this change is available'
|
||||||
|
elif [ "$MODE" = "report" ] ; then
|
||||||
|
echo ' The semantic patch that makes this report is available'
|
||||||
|
elif [ "$MODE" = "context" ] ; then
|
||||||
|
echo ' The semantic patch that spots this code is available'
|
||||||
|
elif [ "$MODE" = "org" ] ; then
|
||||||
|
echo ' The semantic patch that makes this Org report is available'
|
||||||
|
else
|
||||||
|
echo ' The semantic patch that makes this output is available'
|
||||||
|
fi
|
||||||
echo " in $FILE."
|
echo " in $FILE."
|
||||||
echo ''
|
echo ''
|
||||||
echo ' More information about semantic patching is available at'
|
echo ' More information about semantic patching is available at'
|
||||||
echo ' http://coccinelle.lip6.fr/'
|
echo ' http://coccinelle.lip6.fr/'
|
||||||
echo ''
|
echo ''
|
||||||
|
|
||||||
$SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT -dir $srctree || exit 1
|
if [ "`sed -ne 's|^//#||p' $COCCI`" ] ; then
|
||||||
|
echo 'Semantic patch information:'
|
||||||
|
sed -ne 's|^//#||p' $COCCI
|
||||||
|
echo ''
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$MODE" = "chain" ] ; then
|
||||||
|
$SPATCH -D patch $FLAGS -sp_file $COCCI $OPT $OPTIONS || \
|
||||||
|
$SPATCH -D report $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || \
|
||||||
|
$SPATCH -D context $FLAGS -sp_file $COCCI $OPT $OPTIONS || \
|
||||||
|
$SPATCH -D org $FLAGS -sp_file $COCCI $OPT $OPTIONS -no_show_diff || exit 1
|
||||||
else
|
else
|
||||||
$SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1
|
$SPATCH -D $MODE $FLAGS -sp_file $COCCI $OPT $OPTIONS || exit 1
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
///
|
///
|
||||||
/// kzalloc should be used rather than kmalloc followed by memset 0
|
/// Use kzalloc rather than kmalloc followed by memset with 0
|
||||||
|
///
|
||||||
|
/// This considers some simple cases that are common and easy to validate
|
||||||
|
/// Note in particular that there are no ...s in the rule, so all of the
|
||||||
|
/// matched code has to be contiguous
|
||||||
///
|
///
|
||||||
// Confidence: High
|
// Confidence: High
|
||||||
// Copyright: (C) 2009-2010 Julia Lawall, Nicolas Palix, DIKU. GPLv2.
|
// Copyright: (C) 2009-2010 Julia Lawall, Nicolas Palix, DIKU. GPLv2.
|
|
@ -0,0 +1,39 @@
|
||||||
|
/// Use kstrdup rather than duplicating its implementation
|
||||||
|
///
|
||||||
|
// Confidence: High
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual patch
|
||||||
|
|
||||||
|
@@
|
||||||
|
expression from,to;
|
||||||
|
expression flag,E1,E2;
|
||||||
|
statement S;
|
||||||
|
@@
|
||||||
|
|
||||||
|
- to = kmalloc(strlen(from) + 1,flag);
|
||||||
|
+ to = kstrdup(from, flag);
|
||||||
|
... when != \(from = E1 \| to = E1 \)
|
||||||
|
if (to==NULL || ...) S
|
||||||
|
... when != \(from = E2 \| to = E2 \)
|
||||||
|
- strcpy(to, from);
|
||||||
|
|
||||||
|
@@
|
||||||
|
expression x,from,to;
|
||||||
|
expression flag,E1,E2,E3;
|
||||||
|
statement S;
|
||||||
|
@@
|
||||||
|
|
||||||
|
- x = strlen(from) + 1;
|
||||||
|
... when != \( x = E1 \| from = E1 \)
|
||||||
|
- to = \(kmalloc\|kzalloc\)(x,flag);
|
||||||
|
+ to = kstrdup(from, flag);
|
||||||
|
... when != \(x = E2 \| from = E2 \| to = E2 \)
|
||||||
|
if (to==NULL || ...) S
|
||||||
|
... when != \(x = E3 \| from = E3 \| to = E3 \)
|
||||||
|
- memcpy(to, from, x);
|
|
@ -0,0 +1,40 @@
|
||||||
|
/// Use kmemdup rather than duplicating its implementation
|
||||||
|
///
|
||||||
|
// Confidence: High
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual patch
|
||||||
|
|
||||||
|
@r1@
|
||||||
|
expression from,to;
|
||||||
|
expression flag;
|
||||||
|
position p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
to = \(kmalloc@p\|kzalloc@p\)(strlen(from) + 1,flag);
|
||||||
|
|
||||||
|
@r2@
|
||||||
|
expression x,from,to;
|
||||||
|
expression flag,E1;
|
||||||
|
position p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
x = strlen(from) + 1;
|
||||||
|
... when != \( x = E1 \| from = E1 \)
|
||||||
|
to = \(kmalloc@p\|kzalloc@p\)(x,flag);
|
||||||
|
|
||||||
|
@@
|
||||||
|
expression from,to,size,flag;
|
||||||
|
position p != {r1.p,r2.p};
|
||||||
|
statement S;
|
||||||
|
@@
|
||||||
|
|
||||||
|
- to = \(kmalloc@p\|kzalloc@p\)(size,flag);
|
||||||
|
+ to = kmemdup(from,size,flag);
|
||||||
|
if (to==NULL || ...) S
|
||||||
|
- memcpy(to, from, size);
|
|
@ -0,0 +1,35 @@
|
||||||
|
/// Use kmemdup_user rather than duplicating its implementation
|
||||||
|
/// This is a little bit restricted to reduce false positives
|
||||||
|
///
|
||||||
|
// Confidence: High
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual patch
|
||||||
|
|
||||||
|
@@
|
||||||
|
expression from,to,size,flag;
|
||||||
|
position p;
|
||||||
|
identifier l1,l2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
- to = \(kmalloc@p\|kzalloc@p\)(size,flag);
|
||||||
|
+ to = memdup_user(from,size);
|
||||||
|
if (
|
||||||
|
- to==NULL
|
||||||
|
+ IS_ERR(to)
|
||||||
|
|| ...) {
|
||||||
|
<+... when != goto l1;
|
||||||
|
- -ENOMEM
|
||||||
|
+ PTR_ERR(to)
|
||||||
|
...+>
|
||||||
|
}
|
||||||
|
- if (copy_from_user(to, from, size) != 0) {
|
||||||
|
- <+... when != goto l2;
|
||||||
|
- -EFAULT
|
||||||
|
- ...+>
|
||||||
|
- }
|
|
@ -0,0 +1,117 @@
|
||||||
|
/// Find a use after free.
|
||||||
|
//# Values of variables may imply that some
|
||||||
|
//# execution paths are not possible, resulting in false positives.
|
||||||
|
//# Another source of false positives are macros such as
|
||||||
|
//# SCTP_DBG_OBJCNT_DEC that do not actually evaluate their argument
|
||||||
|
///
|
||||||
|
// Confidence: Moderate
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual org
|
||||||
|
virtual report
|
||||||
|
|
||||||
|
@free@
|
||||||
|
expression E;
|
||||||
|
position p1;
|
||||||
|
@@
|
||||||
|
|
||||||
|
kfree@p1(E)
|
||||||
|
|
||||||
|
@print expression@
|
||||||
|
constant char *c;
|
||||||
|
expression free.E,E2;
|
||||||
|
type T;
|
||||||
|
position p;
|
||||||
|
identifier f;
|
||||||
|
@@
|
||||||
|
|
||||||
|
(
|
||||||
|
f(...,c,...,(T)E@p,...)
|
||||||
|
|
|
||||||
|
E@p == E2
|
||||||
|
|
|
||||||
|
E@p != E2
|
||||||
|
|
|
||||||
|
!E@p
|
||||||
|
|
|
||||||
|
E@p || ...
|
||||||
|
)
|
||||||
|
|
||||||
|
@sz@
|
||||||
|
expression free.E;
|
||||||
|
position p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
sizeof(<+...E@p...+>)
|
||||||
|
|
||||||
|
@loop exists@
|
||||||
|
expression E;
|
||||||
|
identifier l;
|
||||||
|
position ok;
|
||||||
|
@@
|
||||||
|
|
||||||
|
while (1) { ...
|
||||||
|
kfree@ok(E)
|
||||||
|
... when != break;
|
||||||
|
when != goto l;
|
||||||
|
when forall
|
||||||
|
}
|
||||||
|
|
||||||
|
@r exists@
|
||||||
|
expression free.E, subE<=free.E, E2;
|
||||||
|
expression E1;
|
||||||
|
iterator iter;
|
||||||
|
statement S;
|
||||||
|
position free.p1!=loop.ok,p2!={print.p,sz.p};
|
||||||
|
@@
|
||||||
|
|
||||||
|
kfree@p1(E,...)
|
||||||
|
...
|
||||||
|
(
|
||||||
|
iter(...,subE,...) S // no use
|
||||||
|
|
|
||||||
|
list_remove_head(E1,subE,...)
|
||||||
|
|
|
||||||
|
subE = E2
|
||||||
|
|
|
||||||
|
subE++
|
||||||
|
|
|
||||||
|
++subE
|
||||||
|
|
|
||||||
|
--subE
|
||||||
|
|
|
||||||
|
subE--
|
||||||
|
|
|
||||||
|
&subE
|
||||||
|
|
|
||||||
|
BUG(...)
|
||||||
|
|
|
||||||
|
BUG_ON(...)
|
||||||
|
|
|
||||||
|
return_VALUE(...)
|
||||||
|
|
|
||||||
|
return_ACPI_STATUS(...)
|
||||||
|
|
|
||||||
|
E@p2 // bad use
|
||||||
|
)
|
||||||
|
|
||||||
|
@script:python depends on org@
|
||||||
|
p1 << free.p1;
|
||||||
|
p2 << r.p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
cocci.print_main("kfree",p1)
|
||||||
|
cocci.print_secs("ref",p2)
|
||||||
|
|
||||||
|
@script:python depends on report@
|
||||||
|
p1 << free.p1;
|
||||||
|
p2 << r.p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
msg = "reference preceded by free on line %s" % (p1[0].line)
|
||||||
|
coccilib.report.print_report(p2[0],msg)
|
|
@ -0,0 +1,64 @@
|
||||||
|
/// These iterators only exit normally when the loop cursor is NULL, so there
|
||||||
|
/// is no point to call of_node_put on the final value.
|
||||||
|
///
|
||||||
|
// Confidence: High
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual patch
|
||||||
|
|
||||||
|
@@
|
||||||
|
iterator name for_each_node_by_name;
|
||||||
|
expression np,E;
|
||||||
|
identifier l;
|
||||||
|
@@
|
||||||
|
|
||||||
|
for_each_node_by_name(np,...) {
|
||||||
|
... when != break;
|
||||||
|
when != goto l;
|
||||||
|
}
|
||||||
|
... when != np = E
|
||||||
|
- of_node_put(np);
|
||||||
|
|
||||||
|
@@
|
||||||
|
iterator name for_each_node_by_type;
|
||||||
|
expression np,E;
|
||||||
|
identifier l;
|
||||||
|
@@
|
||||||
|
|
||||||
|
for_each_node_by_type(np,...) {
|
||||||
|
... when != break;
|
||||||
|
when != goto l;
|
||||||
|
}
|
||||||
|
... when != np = E
|
||||||
|
- of_node_put(np);
|
||||||
|
|
||||||
|
@@
|
||||||
|
iterator name for_each_compatible_node;
|
||||||
|
expression np,E;
|
||||||
|
identifier l;
|
||||||
|
@@
|
||||||
|
|
||||||
|
for_each_compatible_node(np,...) {
|
||||||
|
... when != break;
|
||||||
|
when != goto l;
|
||||||
|
}
|
||||||
|
... when != np = E
|
||||||
|
- of_node_put(np);
|
||||||
|
|
||||||
|
@@
|
||||||
|
iterator name for_each_matching_node;
|
||||||
|
expression np,E;
|
||||||
|
identifier l;
|
||||||
|
@@
|
||||||
|
|
||||||
|
for_each_matching_node(np,...) {
|
||||||
|
... when != break;
|
||||||
|
when != goto l;
|
||||||
|
}
|
||||||
|
... when != np = E
|
||||||
|
- of_node_put(np);
|
|
@ -0,0 +1,58 @@
|
||||||
|
/// Many iterators have the property that the first argument is always bound
|
||||||
|
/// to a real list element, never NULL. False positives arise for some
|
||||||
|
/// iterators that do not have this property, or in cases when the loop
|
||||||
|
/// cursor is reassigned. The latter should only happen when the matched
|
||||||
|
/// code is on the way to a loop exit (break, goto, or return).
|
||||||
|
///
|
||||||
|
// Confidence: Moderate
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual patch
|
||||||
|
|
||||||
|
@@
|
||||||
|
iterator I;
|
||||||
|
expression x,E,E1,E2;
|
||||||
|
statement S,S1,S2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
I(x,...) { <...
|
||||||
|
(
|
||||||
|
- if (x == NULL && ...) S
|
||||||
|
|
|
||||||
|
- if (x != NULL || ...)
|
||||||
|
S
|
||||||
|
|
|
||||||
|
- (x == NULL) ||
|
||||||
|
E
|
||||||
|
|
|
||||||
|
- (x != NULL) &&
|
||||||
|
E
|
||||||
|
|
|
||||||
|
- (x == NULL && ...) ? E1 :
|
||||||
|
E2
|
||||||
|
|
|
||||||
|
- (x != NULL || ...) ?
|
||||||
|
E1
|
||||||
|
- : E2
|
||||||
|
|
|
||||||
|
- if (x == NULL && ...) S1 else
|
||||||
|
S2
|
||||||
|
|
|
||||||
|
- if (x != NULL || ...)
|
||||||
|
S1
|
||||||
|
- else S2
|
||||||
|
|
|
||||||
|
+ BAD(
|
||||||
|
x == NULL
|
||||||
|
+ )
|
||||||
|
|
|
||||||
|
+ BAD(
|
||||||
|
x != NULL
|
||||||
|
+ )
|
||||||
|
)
|
||||||
|
...> }
|
|
@ -0,0 +1,62 @@
|
||||||
|
/// list_for_each_entry uses its first argument to get from one element of
|
||||||
|
/// the list to the next, so it is usually not a good idea to reassign it.
|
||||||
|
/// The first rule finds such a reassignment and the second rule checks
|
||||||
|
/// that there is a path from the reassignment back to the top of the loop.
|
||||||
|
///
|
||||||
|
// Confidence: High
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual context
|
||||||
|
virtual org
|
||||||
|
virtual report
|
||||||
|
|
||||||
|
@r@
|
||||||
|
iterator name list_for_each_entry;
|
||||||
|
expression x,E;
|
||||||
|
position p1,p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
list_for_each_entry@p1(x,...) { <... x =@p2 E ...> }
|
||||||
|
|
||||||
|
@depends on context && !org && !report@
|
||||||
|
expression x,E;
|
||||||
|
position r.p1,r.p2;
|
||||||
|
statement S;
|
||||||
|
@@
|
||||||
|
|
||||||
|
*x =@p2 E
|
||||||
|
...
|
||||||
|
list_for_each_entry@p1(x,...) S
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@back depends on (org || report) && !context exists@
|
||||||
|
expression x,E;
|
||||||
|
position r.p1,r.p2;
|
||||||
|
statement S;
|
||||||
|
@@
|
||||||
|
|
||||||
|
x =@p2 E
|
||||||
|
...
|
||||||
|
list_for_each_entry@p1(x,...) S
|
||||||
|
|
||||||
|
@script:python depends on back && org@
|
||||||
|
p1 << r.p1;
|
||||||
|
p2 << r.p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
cocci.print_main("iterator",p1)
|
||||||
|
cocci.print_secs("update",p2)
|
||||||
|
|
||||||
|
@script:python depends on back && report@
|
||||||
|
p1 << r.p1;
|
||||||
|
p2 << r.p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
msg = "iterator with update on line %s" % (p2[0].line)
|
||||||
|
coccilib.report.print_report(p1[0],msg)
|
|
@ -0,0 +1,74 @@
|
||||||
|
/// Find functions that refer to GFP_KERNEL but are called with locks held.
|
||||||
|
/// The proposed change of converting the GFP_KERNEL is not necessarily the
|
||||||
|
/// correct one. It may be desired to unlock the lock, or to not call the
|
||||||
|
/// function under the lock in the first place.
|
||||||
|
///
|
||||||
|
// Confidence: Moderate
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual patch
|
||||||
|
|
||||||
|
@gfp exists@
|
||||||
|
identifier fn;
|
||||||
|
position p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
fn(...) {
|
||||||
|
... when != read_unlock_irq(...)
|
||||||
|
when != write_unlock_irq(...)
|
||||||
|
when != read_unlock_irqrestore(...)
|
||||||
|
when != write_unlock_irqrestore(...)
|
||||||
|
when != spin_unlock(...)
|
||||||
|
when != spin_unlock_irq(...)
|
||||||
|
when != spin_unlock_irqrestore(...)
|
||||||
|
when != local_irq_enable(...)
|
||||||
|
when any
|
||||||
|
GFP_KERNEL@p
|
||||||
|
... when any
|
||||||
|
}
|
||||||
|
|
||||||
|
@locked@
|
||||||
|
identifier gfp.fn;
|
||||||
|
@@
|
||||||
|
|
||||||
|
(
|
||||||
|
read_lock_irq
|
||||||
|
|
|
||||||
|
write_lock_irq
|
||||||
|
|
|
||||||
|
read_lock_irqsave
|
||||||
|
|
|
||||||
|
write_lock_irqsave
|
||||||
|
|
|
||||||
|
spin_lock
|
||||||
|
|
|
||||||
|
spin_trylock
|
||||||
|
|
|
||||||
|
spin_lock_irq
|
||||||
|
|
|
||||||
|
spin_lock_irqsave
|
||||||
|
|
|
||||||
|
local_irq_disable
|
||||||
|
)
|
||||||
|
(...)
|
||||||
|
... when != read_unlock_irq(...)
|
||||||
|
when != write_unlock_irq(...)
|
||||||
|
when != read_unlock_irqrestore(...)
|
||||||
|
when != write_unlock_irqrestore(...)
|
||||||
|
when != spin_unlock(...)
|
||||||
|
when != spin_unlock_irq(...)
|
||||||
|
when != spin_unlock_irqrestore(...)
|
||||||
|
when != local_irq_enable(...)
|
||||||
|
fn(...)
|
||||||
|
|
||||||
|
@depends on locked@
|
||||||
|
position gfp.p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
- GFP_KERNEL@p
|
||||||
|
+ GFP_ATOMIC
|
|
@ -0,0 +1,92 @@
|
||||||
|
/// Find double locks. False positives may occur when some paths cannot
|
||||||
|
/// occur at execution, due to the values of variables, and when there is
|
||||||
|
/// an intervening function call that releases the lock.
|
||||||
|
///
|
||||||
|
// Confidence: Moderate
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual org
|
||||||
|
virtual report
|
||||||
|
|
||||||
|
@locked@
|
||||||
|
position p1;
|
||||||
|
expression E1;
|
||||||
|
position p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
(
|
||||||
|
mutex_lock@p1
|
||||||
|
|
|
||||||
|
mutex_trylock@p1
|
||||||
|
|
|
||||||
|
spin_lock@p1
|
||||||
|
|
|
||||||
|
spin_trylock@p1
|
||||||
|
|
|
||||||
|
read_lock@p1
|
||||||
|
|
|
||||||
|
read_trylock@p1
|
||||||
|
|
|
||||||
|
write_lock@p1
|
||||||
|
|
|
||||||
|
write_trylock@p1
|
||||||
|
) (E1@p,...);
|
||||||
|
|
||||||
|
@balanced@
|
||||||
|
position p1 != locked.p1;
|
||||||
|
position locked.p;
|
||||||
|
identifier lock,unlock;
|
||||||
|
expression x <= locked.E1;
|
||||||
|
expression E,locked.E1;
|
||||||
|
expression E2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
if (E) {
|
||||||
|
<+... when != E1
|
||||||
|
lock(E1@p,...)
|
||||||
|
...+>
|
||||||
|
}
|
||||||
|
... when != E1
|
||||||
|
when != \(x = E2\|&x\)
|
||||||
|
when forall
|
||||||
|
if (E) {
|
||||||
|
<+... when != E1
|
||||||
|
unlock@p1(E1,...)
|
||||||
|
...+>
|
||||||
|
}
|
||||||
|
|
||||||
|
@r depends on !balanced exists@
|
||||||
|
expression x <= locked.E1;
|
||||||
|
expression locked.E1;
|
||||||
|
expression E2;
|
||||||
|
identifier lock;
|
||||||
|
position locked.p,p1,p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
lock@p1 (E1@p,...);
|
||||||
|
... when != E1
|
||||||
|
when != \(x = E2\|&x\)
|
||||||
|
lock@p2 (E1,...);
|
||||||
|
|
||||||
|
@script:python depends on org@
|
||||||
|
p1 << r.p1;
|
||||||
|
p2 << r.p2;
|
||||||
|
lock << r.lock;
|
||||||
|
@@
|
||||||
|
|
||||||
|
cocci.print_main(lock,p1)
|
||||||
|
cocci.print_secs("second lock",p2)
|
||||||
|
|
||||||
|
@script:python depends on report@
|
||||||
|
p1 << r.p1;
|
||||||
|
p2 << r.p2;
|
||||||
|
lock << r.lock;
|
||||||
|
@@
|
||||||
|
|
||||||
|
msg = "second lock on line %s" % (p2[0].line)
|
||||||
|
coccilib.report.print_report(p1[0],msg)
|
|
@ -0,0 +1,80 @@
|
||||||
|
/// Find nested lock+irqsave functions that use the same flags variables
|
||||||
|
///
|
||||||
|
// Confidence: High
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual context
|
||||||
|
virtual org
|
||||||
|
virtual report
|
||||||
|
|
||||||
|
@r@
|
||||||
|
expression lock1,lock2,flags;
|
||||||
|
position p1,p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
(
|
||||||
|
spin_lock_irqsave@p1(lock1,flags)
|
||||||
|
|
|
||||||
|
read_lock_irqsave@p1(lock1,flags)
|
||||||
|
|
|
||||||
|
write_lock_irqsave@p1(lock1,flags)
|
||||||
|
)
|
||||||
|
... when != flags
|
||||||
|
(
|
||||||
|
spin_lock_irqsave(lock1,flags)
|
||||||
|
|
|
||||||
|
read_lock_irqsave(lock1,flags)
|
||||||
|
|
|
||||||
|
write_lock_irqsave(lock1,flags)
|
||||||
|
|
|
||||||
|
spin_lock_irqsave@p2(lock2,flags)
|
||||||
|
|
|
||||||
|
read_lock_irqsave@p2(lock2,flags)
|
||||||
|
|
|
||||||
|
write_lock_irqsave@p2(lock2,flags)
|
||||||
|
)
|
||||||
|
|
||||||
|
@d@
|
||||||
|
expression f <= r.flags;
|
||||||
|
expression lock1,lock2,flags;
|
||||||
|
position r.p1, r.p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
(
|
||||||
|
*spin_lock_irqsave@p1(lock1,flags)
|
||||||
|
|
|
||||||
|
*read_lock_irqsave@p1(lock1,flags)
|
||||||
|
|
|
||||||
|
*write_lock_irqsave@p1(lock1,flags)
|
||||||
|
)
|
||||||
|
... when != f
|
||||||
|
(
|
||||||
|
*spin_lock_irqsave@p2(lock2,flags)
|
||||||
|
|
|
||||||
|
*read_lock_irqsave@p2(lock2,flags)
|
||||||
|
|
|
||||||
|
*write_lock_irqsave@p2(lock2,flags)
|
||||||
|
)
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@script:python depends on d && org@
|
||||||
|
p1 << r.p1;
|
||||||
|
p2 << r.p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
cocci.print_main("original lock",p1)
|
||||||
|
cocci.print_secs("nested lock+irqsave that reuses flags",p2)
|
||||||
|
|
||||||
|
@script:python depends on d && report@
|
||||||
|
p1 << r.p1;
|
||||||
|
p2 << r.p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
msg="ERROR: nested lock+irqsave that reuses flags from %s." % (p1[0].line)
|
||||||
|
coccilib.report.print_report(p2[0], msg)
|
|
@ -0,0 +1,95 @@
|
||||||
|
/// Find missing unlocks. This semantic match considers the specific case
|
||||||
|
/// where the unlock is missing from an if branch, and there is a lock
|
||||||
|
/// before the if and an unlock after the if. False positives are due to
|
||||||
|
/// cases where the if branch represents a case where the function is
|
||||||
|
/// supposed to exit with the lock held, or where there is some preceding
|
||||||
|
/// function call that releases the lock.
|
||||||
|
///
|
||||||
|
// Confidence: Moderate
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual org
|
||||||
|
virtual report
|
||||||
|
|
||||||
|
@prelocked@
|
||||||
|
position p1,p;
|
||||||
|
expression E1;
|
||||||
|
@@
|
||||||
|
|
||||||
|
(
|
||||||
|
mutex_lock@p1
|
||||||
|
|
|
||||||
|
mutex_trylock@p1
|
||||||
|
|
|
||||||
|
spin_lock@p1
|
||||||
|
|
|
||||||
|
spin_trylock@p1
|
||||||
|
|
|
||||||
|
read_lock@p1
|
||||||
|
|
|
||||||
|
read_trylock@p1
|
||||||
|
|
|
||||||
|
write_lock@p1
|
||||||
|
|
|
||||||
|
write_trylock@p1
|
||||||
|
|
|
||||||
|
read_lock_irq@p1
|
||||||
|
|
|
||||||
|
write_lock_irq@p1
|
||||||
|
|
|
||||||
|
read_lock_irqsave@p1
|
||||||
|
|
|
||||||
|
write_lock_irqsave@p1
|
||||||
|
|
|
||||||
|
spin_lock_irq@p1
|
||||||
|
|
|
||||||
|
spin_lock_irqsave@p1
|
||||||
|
) (E1@p,...);
|
||||||
|
|
||||||
|
@looped@
|
||||||
|
position r;
|
||||||
|
@@
|
||||||
|
|
||||||
|
for(...;...;...) { <+... return@r ...; ...+> }
|
||||||
|
|
||||||
|
@err@
|
||||||
|
expression E1;
|
||||||
|
position prelocked.p;
|
||||||
|
position up != prelocked.p1;
|
||||||
|
position r!=looped.r;
|
||||||
|
identifier lock,unlock;
|
||||||
|
@@
|
||||||
|
|
||||||
|
lock(E1@p,...);
|
||||||
|
<+... when != E1
|
||||||
|
if (...) {
|
||||||
|
... when != E1
|
||||||
|
return@r ...;
|
||||||
|
}
|
||||||
|
...+>
|
||||||
|
unlock@up(E1,...);
|
||||||
|
|
||||||
|
@script:python depends on org@
|
||||||
|
p << prelocked.p1;
|
||||||
|
lock << err.lock;
|
||||||
|
unlock << err.unlock;
|
||||||
|
p2 << err.r;
|
||||||
|
@@
|
||||||
|
|
||||||
|
cocci.print_main(lock,p)
|
||||||
|
cocci.print_secs(unlock,p2)
|
||||||
|
|
||||||
|
@script:python depends on report@
|
||||||
|
p << prelocked.p1;
|
||||||
|
lock << err.lock;
|
||||||
|
unlock << err.unlock;
|
||||||
|
p2 << err.r;
|
||||||
|
@@
|
||||||
|
|
||||||
|
msg = "preceding lock on line %s" % (p[0].line)
|
||||||
|
coccilib.report.print_report(p2[0],msg)
|
|
@ -0,0 +1,53 @@
|
||||||
|
/// Find duplicate field initializations. This has a high rate of false
|
||||||
|
/// positives due to #ifdefs, which Coccinelle is not aware of in a structure
|
||||||
|
/// initialization.
|
||||||
|
///
|
||||||
|
// Confidence: Low
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual org
|
||||||
|
virtual report
|
||||||
|
|
||||||
|
@r@
|
||||||
|
identifier I, s, fld;
|
||||||
|
position p0,p;
|
||||||
|
expression E;
|
||||||
|
@@
|
||||||
|
|
||||||
|
struct I s =@p0 { ... .fld@p = E, ...};
|
||||||
|
|
||||||
|
@s@
|
||||||
|
identifier I, s, r.fld;
|
||||||
|
position r.p0,p;
|
||||||
|
expression E;
|
||||||
|
@@
|
||||||
|
|
||||||
|
struct I s =@p0 { ... .fld@p = E, ...};
|
||||||
|
|
||||||
|
@script:python depends on org@
|
||||||
|
p0 << r.p0;
|
||||||
|
fld << r.fld;
|
||||||
|
ps << s.p;
|
||||||
|
pr << r.p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)):
|
||||||
|
cocci.print_main(fld,p0)
|
||||||
|
cocci.print_secs("s",ps)
|
||||||
|
cocci.print_secs("r",pr)
|
||||||
|
|
||||||
|
@script:python depends on report@
|
||||||
|
p0 << r.p0;
|
||||||
|
fld << r.fld;
|
||||||
|
ps << s.p;
|
||||||
|
pr << r.p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
if int(ps[0].line) < int(pr[0].line) or (int(ps[0].line) == int(pr[0].line) and int(ps[0].column) < int(pr[0].column)):
|
||||||
|
msg = "%s: first occurrence %s, second occurrence %s" % (fld,ps[0].line,pr[0].line)
|
||||||
|
coccilib.report.print_report(p0[0],msg)
|
|
@ -0,0 +1,48 @@
|
||||||
|
/// Find confusingly indented code in or after an if. An if branch should
|
||||||
|
/// be indented. The code following an if should not be indented.
|
||||||
|
/// Sometimes, code after an if that is indented is actually intended to be
|
||||||
|
/// part of the if branch.
|
||||||
|
///
|
||||||
|
/// This has a high rate of false positives, because Coccinelle's column
|
||||||
|
/// calculation does not distinguish between spaces and tabs, so code that
|
||||||
|
/// is not visually aligned may be considered to be in the same column.
|
||||||
|
///
|
||||||
|
// Confidence: Low
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual org
|
||||||
|
virtual report
|
||||||
|
|
||||||
|
@r disable braces4@
|
||||||
|
position p1,p2;
|
||||||
|
statement S1,S2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
(
|
||||||
|
if (...) { ... }
|
||||||
|
|
|
||||||
|
if (...) S1@p1 S2@p2
|
||||||
|
)
|
||||||
|
|
||||||
|
@script:python depends on org@
|
||||||
|
p1 << r.p1;
|
||||||
|
p2 << r.p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
if (p1[0].column == p2[0].column):
|
||||||
|
cocci.print_main("branch",p1)
|
||||||
|
cocci.print_secs("after",p2)
|
||||||
|
|
||||||
|
@script:python depends on report@
|
||||||
|
p1 << r.p1;
|
||||||
|
p2 << r.p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
if (p1[0].column == p2[0].column):
|
||||||
|
msg = "code aligned with following code on line %s" % (p2[0].line)
|
||||||
|
coccilib.report.print_report(p1[0],msg)
|
|
@ -0,0 +1,20 @@
|
||||||
|
/// The various basic memory allocation functions don't return ERR_PTR
|
||||||
|
///
|
||||||
|
// Confidence: High
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual patch
|
||||||
|
|
||||||
|
@@
|
||||||
|
expression x,E;
|
||||||
|
@@
|
||||||
|
|
||||||
|
x = \(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\|kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\)(...)
|
||||||
|
... when != x = E
|
||||||
|
- IS_ERR(x)
|
||||||
|
+ !x
|
|
@ -0,0 +1,72 @@
|
||||||
|
/// This semantic patch looks for kmalloc etc that are not followed by a
|
||||||
|
/// NULL check. It only gives a report in the case where there is some
|
||||||
|
/// error handling code later in the function, which may be helpful
|
||||||
|
/// in determining what the error handling code for the call to kmalloc etc
|
||||||
|
/// should be.
|
||||||
|
///
|
||||||
|
// Confidence: High
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual context
|
||||||
|
virtual org
|
||||||
|
virtual report
|
||||||
|
|
||||||
|
@withtest@
|
||||||
|
expression x;
|
||||||
|
position p;
|
||||||
|
identifier f,fld;
|
||||||
|
@@
|
||||||
|
|
||||||
|
x@p = f(...);
|
||||||
|
... when != x->fld
|
||||||
|
\(x == NULL \| x != NULL\)
|
||||||
|
|
||||||
|
@fixed depends on context && !org && !report@
|
||||||
|
expression x,x1;
|
||||||
|
position p1 != withtest.p;
|
||||||
|
statement S;
|
||||||
|
position any withtest.p;
|
||||||
|
identifier f;
|
||||||
|
@@
|
||||||
|
|
||||||
|
*x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...);
|
||||||
|
...
|
||||||
|
*x1@p = f(...);
|
||||||
|
if (!x1) S
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@rfixed depends on (org || report) && !context exists@
|
||||||
|
expression x,x1;
|
||||||
|
position p1 != withtest.p;
|
||||||
|
position p2;
|
||||||
|
statement S;
|
||||||
|
position any withtest.p;
|
||||||
|
identifier f;
|
||||||
|
@@
|
||||||
|
|
||||||
|
x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...);
|
||||||
|
...
|
||||||
|
x1@p = f@p2(...);
|
||||||
|
if (!x1) S
|
||||||
|
|
||||||
|
@script:python depends on org@
|
||||||
|
p1 << rfixed.p1;
|
||||||
|
p2 << rfixed.p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
cocci.print_main("alloc call",p1)
|
||||||
|
cocci.print_secs("possible model",p2)
|
||||||
|
|
||||||
|
@script:python depends on report@
|
||||||
|
p1 << rfixed.p1;
|
||||||
|
p2 << rfixed.p2;
|
||||||
|
@@
|
||||||
|
|
||||||
|
msg = "alloc with no test, possible model on line %s" % (p2[0].line)
|
||||||
|
coccilib.report.print_report(p1[0],msg)
|
|
@ -0,0 +1,54 @@
|
||||||
|
/// Find bit operations that include the same argument more than once
|
||||||
|
//# One source of false positives is when the argument performs a side
|
||||||
|
//# effect. Another source of false positives is when a neutral value
|
||||||
|
//# such as 0 for | is used to indicate no information, to maintain the
|
||||||
|
//# same structure as other similar expressions
|
||||||
|
///
|
||||||
|
// Confidence: Moderate
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual context
|
||||||
|
virtual org
|
||||||
|
virtual report
|
||||||
|
|
||||||
|
@r expression@
|
||||||
|
expression E;
|
||||||
|
position p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
(
|
||||||
|
* E@p
|
||||||
|
& ... & E
|
||||||
|
|
|
||||||
|
* E@p
|
||||||
|
| ... | E
|
||||||
|
|
|
||||||
|
* E@p
|
||||||
|
& ... & !E
|
||||||
|
|
|
||||||
|
* E@p
|
||||||
|
| ... | !E
|
||||||
|
|
|
||||||
|
* !E@p
|
||||||
|
& ... & E
|
||||||
|
|
|
||||||
|
* !E@p
|
||||||
|
| ... | E
|
||||||
|
)
|
||||||
|
|
||||||
|
@script:python depends on org@
|
||||||
|
p << r.p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
cocci.print_main("duplicated argument to & or |",p)
|
||||||
|
|
||||||
|
@script:python depends on report@
|
||||||
|
p << r.p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
coccilib.report.print_report(p[0],"duplicated argument to & or |")
|
|
@ -0,0 +1,40 @@
|
||||||
|
/// Find &&/|| operations that include the same argument more than once
|
||||||
|
//# A common source of false positives is when the argument performs a side
|
||||||
|
//# effect.
|
||||||
|
///
|
||||||
|
// Confidence: Moderate
|
||||||
|
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||||
|
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||||
|
// URL: http://coccinelle.lip6.fr/
|
||||||
|
// Comments:
|
||||||
|
// Options: -no_includes -include_headers
|
||||||
|
|
||||||
|
virtual context
|
||||||
|
virtual org
|
||||||
|
virtual report
|
||||||
|
|
||||||
|
@r expression@
|
||||||
|
expression E;
|
||||||
|
position p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
(
|
||||||
|
* E@p
|
||||||
|
|| ... || E
|
||||||
|
|
|
||||||
|
* E@p
|
||||||
|
&& ... && E
|
||||||
|
)
|
||||||
|
|
||||||
|
@script:python depends on org@
|
||||||
|
p << r.p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
cocci.print_main("duplicated argument to && or ||",p)
|
||||||
|
|
||||||
|
@script:python depends on report@
|
||||||
|
p << r.p;
|
||||||
|
@@
|
||||||
|
|
||||||
|
coccilib.report.print_report(p[0],"duplicated argument to && or ||")
|
|
@ -7,12 +7,10 @@
|
||||||
# The obscure use of the "tr" filter is to work around older versions of
|
# The obscure use of the "tr" filter is to work around older versions of
|
||||||
# "grep" that report the byte offset of the line instead of the pattern.
|
# "grep" that report the byte offset of the line instead of the pattern.
|
||||||
#
|
#
|
||||||
# (c) 2009, Dick Streefland <dick@streefland.net>
|
# (c) 2009,2010 Dick Streefland <dick@streefland.net>
|
||||||
# Licensed under the terms of the GNU General Public License.
|
# Licensed under the terms of the GNU General Public License.
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
gz1='\037\213\010'
|
|
||||||
gz2='01'
|
|
||||||
cf1='IKCFG_ST\037\213\010'
|
cf1='IKCFG_ST\037\213\010'
|
||||||
cf2='0123456789'
|
cf2='0123456789'
|
||||||
|
|
||||||
|
@ -21,9 +19,23 @@ dump_config()
|
||||||
if pos=`tr "$cf1\n$cf2" "\n$cf2=" < "$1" | grep -abo "^$cf2"`
|
if pos=`tr "$cf1\n$cf2" "\n$cf2=" < "$1" | grep -abo "^$cf2"`
|
||||||
then
|
then
|
||||||
pos=${pos%%:*}
|
pos=${pos%%:*}
|
||||||
tail -c+$(($pos+8)) "$1" | zcat -q
|
tail -c+$(($pos+8)) "$1" | zcat > $tmp1 2> /dev/null
|
||||||
|
if [ $? != 1 ]
|
||||||
|
then # exit status must be 0 or 2 (trailing garbage warning)
|
||||||
|
cat $tmp1
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
try_decompress()
|
||||||
|
{
|
||||||
|
for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"`
|
||||||
|
do
|
||||||
|
pos=${pos%%:*}
|
||||||
|
tail -c+$pos "$img" | $3 > $tmp2 2> /dev/null
|
||||||
|
dump_config $tmp2
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check invocation:
|
# Check invocation:
|
||||||
|
@ -35,18 +47,19 @@ then
|
||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Prepare temp files:
|
||||||
|
tmp1=/tmp/ikconfig$$.1
|
||||||
|
tmp2=/tmp/ikconfig$$.2
|
||||||
|
trap "rm -f $tmp1 $tmp2" 0
|
||||||
|
|
||||||
# Initial attempt for uncompressed images or objects:
|
# Initial attempt for uncompressed images or objects:
|
||||||
dump_config "$img"
|
dump_config "$img"
|
||||||
|
|
||||||
# That didn't work, so decompress and try again:
|
# That didn't work, so retry after decompression.
|
||||||
tmp=/tmp/ikconfig$$
|
try_decompress '\037\213\010' xy gunzip
|
||||||
trap "rm -f $tmp" 0
|
try_decompress 'BZh' xy bunzip2
|
||||||
for pos in `tr "$gz1\n$gz2" "\n$gz2=" < "$img" | grep -abo "^$gz2"`
|
try_decompress '\135\0\0\0' xxx unlzma
|
||||||
do
|
try_decompress '\211\114\132' xy 'lzop -d'
|
||||||
pos=${pos%%:*}
|
|
||||||
tail -c+$pos "$img" | zcat 2> /dev/null > $tmp
|
|
||||||
dump_config $tmp
|
|
||||||
done
|
|
||||||
|
|
||||||
# Bail out:
|
# Bail out:
|
||||||
echo "$me: Cannot find kernel config." >&2
|
echo "$me: Cannot find kernel config." >&2
|
||||||
|
|
|
@ -84,6 +84,64 @@ my %ksymtab = (); # names that appear in __ksymtab_
|
||||||
my %ref = (); # $ref{$name} exists if there is a true external reference to $name
|
my %ref = (); # $ref{$name} exists if there is a true external reference to $name
|
||||||
my %export = (); # $export{$name} exists if there is an EXPORT_... of $name
|
my %export = (); # $export{$name} exists if there is an EXPORT_... of $name
|
||||||
|
|
||||||
|
my %nmexception = (
|
||||||
|
'fs/ext3/bitmap' => 1,
|
||||||
|
'fs/ext4/bitmap' => 1,
|
||||||
|
'arch/x86/lib/thunk_32' => 1,
|
||||||
|
'arch/x86/lib/cmpxchg' => 1,
|
||||||
|
'arch/x86/vdso/vdso32/note' => 1,
|
||||||
|
'lib/irq_regs' => 1,
|
||||||
|
'usr/initramfs_data' => 1,
|
||||||
|
'drivers/scsi/aic94xx/aic94xx_dump' => 1,
|
||||||
|
'drivers/scsi/libsas/sas_dump' => 1,
|
||||||
|
'lib/dec_and_lock' => 1,
|
||||||
|
'drivers/ide/ide-probe-mini' => 1,
|
||||||
|
'usr/initramfs_data' => 1,
|
||||||
|
'drivers/acpi/acpia/exdump' => 1,
|
||||||
|
'drivers/acpi/acpia/rsdump' => 1,
|
||||||
|
'drivers/acpi/acpia/nsdumpdv' => 1,
|
||||||
|
'drivers/acpi/acpia/nsdump' => 1,
|
||||||
|
'arch/ia64/sn/kernel/sn2/io' => 1,
|
||||||
|
'arch/ia64/kernel/gate-data' => 1,
|
||||||
|
'security/capability' => 1,
|
||||||
|
'fs/ntfs/sysctl' => 1,
|
||||||
|
'fs/jfs/jfs_debug' => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
my %nameexception = (
|
||||||
|
'mod_use_count_' => 1,
|
||||||
|
'__initramfs_end' => 1,
|
||||||
|
'__initramfs_start' => 1,
|
||||||
|
'_einittext' => 1,
|
||||||
|
'_sinittext' => 1,
|
||||||
|
'kallsyms_names' => 1,
|
||||||
|
'kallsyms_num_syms' => 1,
|
||||||
|
'kallsyms_addresses'=> 1,
|
||||||
|
'__this_module' => 1,
|
||||||
|
'_etext' => 1,
|
||||||
|
'_edata' => 1,
|
||||||
|
'_end' => 1,
|
||||||
|
'__bss_start' => 1,
|
||||||
|
'_text' => 1,
|
||||||
|
'_stext' => 1,
|
||||||
|
'__gp' => 1,
|
||||||
|
'ia64_unw_start' => 1,
|
||||||
|
'ia64_unw_end' => 1,
|
||||||
|
'__init_begin' => 1,
|
||||||
|
'__init_end' => 1,
|
||||||
|
'__bss_stop' => 1,
|
||||||
|
'__nosave_begin' => 1,
|
||||||
|
'__nosave_end' => 1,
|
||||||
|
'pg0' => 1,
|
||||||
|
'vdso_enabled' => 1,
|
||||||
|
'__stack_chk_fail' => 1,
|
||||||
|
'VDSO32_PRELINK' => 1,
|
||||||
|
'VDSO32_vsyscall' => 1,
|
||||||
|
'VDSO32_rt_sigreturn'=>1,
|
||||||
|
'VDSO32_sigreturn' => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
&find(\&linux_objects, '.'); # find the objects and do_nm on them
|
&find(\&linux_objects, '.'); # find the objects and do_nm on them
|
||||||
&list_multiply_defined();
|
&list_multiply_defined();
|
||||||
&resolve_external_references();
|
&resolve_external_references();
|
||||||
|
@ -105,7 +163,8 @@ sub linux_objects
|
||||||
if (/.*\.o$/ &&
|
if (/.*\.o$/ &&
|
||||||
! (
|
! (
|
||||||
m:/built-in.o$:
|
m:/built-in.o$:
|
||||||
|| m:arch/x86/kernel/vsyscall-syms.o$:
|
|| m:arch/x86/vdso/:
|
||||||
|
|| m:arch/x86/boot/:
|
||||||
|| m:arch/ia64/ia32/ia32.o$:
|
|| m:arch/ia64/ia32/ia32.o$:
|
||||||
|| m:arch/ia64/kernel/gate-syms.o$:
|
|| m:arch/ia64/kernel/gate-syms.o$:
|
||||||
|| m:arch/ia64/lib/__divdi3.o$:
|
|| m:arch/ia64/lib/__divdi3.o$:
|
||||||
|
@ -148,6 +207,7 @@ sub linux_objects
|
||||||
|| m:^.*/\.tmp_:
|
|| m:^.*/\.tmp_:
|
||||||
|| m:^\.tmp_:
|
|| m:^\.tmp_:
|
||||||
|| m:/vmlinux-obj.o$:
|
|| m:/vmlinux-obj.o$:
|
||||||
|
|| m:^tools/:
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
do_nm($basename, $_);
|
do_nm($basename, $_);
|
||||||
|
@ -167,11 +227,11 @@ sub do_nm
|
||||||
printf STDERR "$fullname is not an object file\n";
|
printf STDERR "$fullname is not an object file\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
($source = $fullname) =~ s/\.o$//;
|
($source = $basename) =~ s/\.o$//;
|
||||||
if (-e "$objtree$source.c" || -e "$objtree$source.S") {
|
if (-e "$source.c" || -e "$source.S") {
|
||||||
$source = "$objtree$source";
|
$source = "$objtree$File::Find::dir/$source";
|
||||||
} else {
|
} else {
|
||||||
$source = "$srctree$source";
|
$source = "$srctree$File::Find::dir/$source";
|
||||||
}
|
}
|
||||||
if (! -e "$source.c" && ! -e "$source.S") {
|
if (! -e "$source.c" && ! -e "$source.S") {
|
||||||
# No obvious source, exclude the object if it is conglomerate
|
# No obvious source, exclude the object if it is conglomerate
|
||||||
|
@ -214,6 +274,7 @@ sub do_nm
|
||||||
# T global label/procedure
|
# T global label/procedure
|
||||||
# U external reference
|
# U external reference
|
||||||
# W weak external reference to text that has been resolved
|
# W weak external reference to text that has been resolved
|
||||||
|
# V similar to W, but the value of the weak symbol becomes zero with no error.
|
||||||
# a assembler equate
|
# a assembler equate
|
||||||
# b static variable, uninitialised
|
# b static variable, uninitialised
|
||||||
# d static variable, initialised
|
# d static variable, initialised
|
||||||
|
@ -222,8 +283,9 @@ sub do_nm
|
||||||
# s static variable, uninitialised, small bss
|
# s static variable, uninitialised, small bss
|
||||||
# t static label/procedures
|
# t static label/procedures
|
||||||
# w weak external reference to text that has not been resolved
|
# w weak external reference to text that has not been resolved
|
||||||
|
# v similar to w
|
||||||
# ? undefined type, used a lot by modules
|
# ? undefined type, used a lot by modules
|
||||||
if ($type !~ /^[ABCDGRSTUWabdgrstw?]$/) {
|
if ($type !~ /^[ABCDGRSTUWVabdgrstwv?]$/) {
|
||||||
printf STDERR "nm output for $fullname contains unknown type '$_'\n";
|
printf STDERR "nm output for $fullname contains unknown type '$_'\n";
|
||||||
}
|
}
|
||||||
elsif ($name =~ /\./) {
|
elsif ($name =~ /\./) {
|
||||||
|
@ -234,7 +296,7 @@ sub do_nm
|
||||||
# binutils keeps changing the type for exported symbols, force it to R
|
# binutils keeps changing the type for exported symbols, force it to R
|
||||||
$type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/);
|
$type = 'R' if ($name =~ /^__ksymtab/ || $name =~ /^__kstrtab/);
|
||||||
$name =~ s/_R[a-f0-9]{8}$//; # module versions adds this
|
$name =~ s/_R[a-f0-9]{8}$//; # module versions adds this
|
||||||
if ($type =~ /[ABCDGRSTW]/ &&
|
if ($type =~ /[ABCDGRSTWV]/ &&
|
||||||
$name ne 'init_module' &&
|
$name ne 'init_module' &&
|
||||||
$name ne 'cleanup_module' &&
|
$name ne 'cleanup_module' &&
|
||||||
$name ne 'Using_Versions' &&
|
$name ne 'Using_Versions' &&
|
||||||
|
@ -270,26 +332,8 @@ sub do_nm
|
||||||
close($nmdata);
|
close($nmdata);
|
||||||
|
|
||||||
if ($#nmdata < 0) {
|
if ($#nmdata < 0) {
|
||||||
if (
|
printf "No nm data for $fullname\n"
|
||||||
$fullname ne "lib/brlock.o"
|
unless $nmexception{$fullname};
|
||||||
&& $fullname ne "lib/dec_and_lock.o"
|
|
||||||
&& $fullname ne "fs/xfs/xfs_macros.o"
|
|
||||||
&& $fullname ne "drivers/ide/ide-probe-mini.o"
|
|
||||||
&& $fullname ne "usr/initramfs_data.o"
|
|
||||||
&& $fullname ne "drivers/acpi/executer/exdump.o"
|
|
||||||
&& $fullname ne "drivers/acpi/resources/rsdump.o"
|
|
||||||
&& $fullname ne "drivers/acpi/namespace/nsdumpdv.o"
|
|
||||||
&& $fullname ne "drivers/acpi/namespace/nsdump.o"
|
|
||||||
&& $fullname ne "arch/ia64/sn/kernel/sn2/io.o"
|
|
||||||
&& $fullname ne "arch/ia64/kernel/gate-data.o"
|
|
||||||
&& $fullname ne "drivers/ieee1394/oui.o"
|
|
||||||
&& $fullname ne "security/capability.o"
|
|
||||||
&& $fullname ne "sound/core/wrappers.o"
|
|
||||||
&& $fullname ne "fs/ntfs/sysctl.o"
|
|
||||||
&& $fullname ne "fs/jfs/jfs_debug.o"
|
|
||||||
) {
|
|
||||||
printf "No nm data for $fullname\n";
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$nmdata{$fullname} = \@nmdata;
|
$nmdata{$fullname} = \@nmdata;
|
||||||
|
@ -319,18 +363,14 @@ sub list_multiply_defined
|
||||||
foreach my $name (keys(%def)) {
|
foreach my $name (keys(%def)) {
|
||||||
if ($#{$def{$name}} > 0) {
|
if ($#{$def{$name}} > 0) {
|
||||||
# Special case for cond_syscall
|
# Special case for cond_syscall
|
||||||
if ($#{$def{$name}} == 1 && $name =~ /^sys_/ &&
|
if ($#{$def{$name}} == 1 &&
|
||||||
($def{$name}[0] eq "kernel/sys.o" ||
|
($name =~ /^sys_/ || $name =~ /^compat_sys_/ ||
|
||||||
$def{$name}[1] eq "kernel/sys.o")) {
|
$name =~ /^sys32_/)) {
|
||||||
&drop_def("kernel/sys.o", $name);
|
if($def{$name}[0] eq "kernel/sys_ni.o" ||
|
||||||
|
$def{$name}[1] eq "kernel/sys_ni.o") {
|
||||||
|
&drop_def("kernel/sys_ni.o", $name);
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
# Special case for i386 entry code
|
|
||||||
if ($#{$def{$name}} == 1 && $name =~ /^__kernel_/ &&
|
|
||||||
$def{$name}[0] eq "arch/x86/kernel/vsyscall-int80_32.o" &&
|
|
||||||
$def{$name}[1] eq "arch/x86/kernel/vsyscall-sysenter_32.o") {
|
|
||||||
&drop_def("arch/x86/kernel/vsyscall-sysenter_32.o", $name);
|
|
||||||
next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf "$name is multiply defined in :-\n";
|
printf "$name is multiply defined in :-\n";
|
||||||
|
@ -372,31 +412,7 @@ sub resolve_external_references
|
||||||
$ref{$name} = ""
|
$ref{$name} = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elsif ( $name ne "mod_use_count_"
|
elsif ( ! $nameexception{$name}
|
||||||
&& $name ne "__initramfs_end"
|
|
||||||
&& $name ne "__initramfs_start"
|
|
||||||
&& $name ne "_einittext"
|
|
||||||
&& $name ne "_sinittext"
|
|
||||||
&& $name ne "kallsyms_names"
|
|
||||||
&& $name ne "kallsyms_num_syms"
|
|
||||||
&& $name ne "kallsyms_addresses"
|
|
||||||
&& $name ne "__this_module"
|
|
||||||
&& $name ne "_etext"
|
|
||||||
&& $name ne "_edata"
|
|
||||||
&& $name ne "_end"
|
|
||||||
&& $name ne "__bss_start"
|
|
||||||
&& $name ne "_text"
|
|
||||||
&& $name ne "_stext"
|
|
||||||
&& $name ne "__gp"
|
|
||||||
&& $name ne "ia64_unw_start"
|
|
||||||
&& $name ne "ia64_unw_end"
|
|
||||||
&& $name ne "__init_begin"
|
|
||||||
&& $name ne "__init_end"
|
|
||||||
&& $name ne "__bss_stop"
|
|
||||||
&& $name ne "__nosave_begin"
|
|
||||||
&& $name ne "__nosave_end"
|
|
||||||
&& $name ne "pg0"
|
|
||||||
&& $name ne "__module_text_address"
|
|
||||||
&& $name !~ /^__sched_text_/
|
&& $name !~ /^__sched_text_/
|
||||||
&& $name !~ /^__start_/
|
&& $name !~ /^__start_/
|
||||||
&& $name !~ /^__end_/
|
&& $name !~ /^__end_/
|
||||||
|
@ -407,7 +423,6 @@ sub resolve_external_references
|
||||||
&& $name !~ /^__.*per_cpu_end/
|
&& $name !~ /^__.*per_cpu_end/
|
||||||
&& $name !~ /^__alt_instructions/
|
&& $name !~ /^__alt_instructions/
|
||||||
&& $name !~ /^__setup_/
|
&& $name !~ /^__setup_/
|
||||||
&& $name !~ /^jiffies/
|
|
||||||
&& $name !~ /^__mod_timer/
|
&& $name !~ /^__mod_timer/
|
||||||
&& $name !~ /^__mod_page_state/
|
&& $name !~ /^__mod_page_state/
|
||||||
&& $name !~ /^init_module/
|
&& $name !~ /^init_module/
|
||||||
|
|
Загрузка…
Ссылка в новой задаче