1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
Introduction
This file describes the use of automake and libtool to build the test suite.
Overview
The following list summarizes the steps needed to create a new test case from
scratch (i.e. without reusing anything from other test cases):
* Add a new target library;
* Add a new test program;
* Add a new live patch;
* Add a new test suite driver.
Detailed description
A test case is composed of the several pieces listed above, each of which
requires new files in this directory (the contents of each of these files is
out of the scope of this tutorial), as well as new build rules.
Makefile.am uses both automake and libtool, thus all rules are derived from
make macros, such as check_PROGRAMS and check_LTLIBRARIES. In automake and
libtool, macros that start with 'check_' create rules that are only executed
during 'make check'.
Target library
To add a new target library to the build, simply append the library name to the
list of libraries created with 'make check'. In other others, append to the
check_LTLIBRARIES macro, such as the following example:
check_LTLIBRARIES += libaddress.la
In libtool, libraries have the .la suffix, which are text files that describe
how the actual libraries should be created (the typical .a and .so files found
in GNU systems can be found under the .libs directory). Libtool derives the
rules to build them from macros such as *_SOURCES and *_CFLAGS. Each of these
macros start with the name of the target library, so, for the example above,
the following macros are used:
libaddress_la_SOURCES = libaddress.c
libaddress_la_CFLAGS = $(TARGET_CFLAGS)
libaddress_la_LDFLAGS = $(TARGET_LDFLAGS) $(CONVENIENCE_LDFLAGS)
The first rule controls what files compose the target library, and that's what
libtool passes to the compiler as input files. The second and third rules set
compiler and linker flags, respectively, which libtool also passes to the
compiler.
The contents of TARGET_CFLAGS, TARGET_LDFLAGS and CONVENIENCE_LDFLAGS can be
found in Makefile.commom (in the root dir). The first and second add compiler
options that Libpulp requires, such as Build-IDs in Elf files and patchable
function entries. The last forces libtool to create shared libraries, even if
they are not going to be installed, as explained in Makefile.common:
# In libtool, convenience libraries are not installed, so they do not
# need -rpath, which causes them to be statically linked. However,
# libpulp can only live patch dynamically linked libraries, so pass
# -rpath to libtool, which causes the linking to become dynamic.
CONVENIENCE_LDFLAGS = -rpath $(libdir) $(AM_LDFLAGS)
Finally, the target library must be post-processed so that single-byte nops
become multi-byte nops. Adding the library to the POST_PROCESS macro, as
exemplified below, does the trick:
POST_PROCESS += .libs/libaddress.post
Main program:
An application is needed to run the library. In automake, adding items to the
'check_PROGRAM' macro creates a test application that gets built during 'make
check', like so:
check_PROGRAMS += memory_protection
Just like check_LTLIBRARIES, each item in check_PROGRAMS requires its own set
of macros, which tell automake how to build them. For the example at hand, the
following lines achieve this:
memory_protection_SOURCES = memory_protection.c
memory_protection_LDADD = libaddress.la
memory_protection_DEPENDENCIES = $(POST_PROCESS) $(METADATA)
The first line tells automake what source files compose the program; they are
passed as input files to the compiler. The second line tells automake that the
test program depends on libaddress, the library we want to live patch. The last
line adds dependencies to the test program, which are not are related to the
process of building the program itself, but are required to run the test, such
as the metadata file.
The live patch:
Since live patches contain a shared library, new live patches must be added to
check_LTLIBRARIES, so that the shared library gets built during `make check'.
For instance:
check_LTLIBRARIES += libaddress_livepatch1.la
libaddress_livepatch1_la_SOURCES = libaddress_livepatch1.c
libaddress_livepatch1_la_LDFLAGS = $(CONVENIENCE_LDFLAGS)
However, live patches are composed not just of shared libraries, but also of
metadata files. Makefile.common contains the rules to create them, so simply
add their names to the METADATA macro, such as in the following example:
METADATA += libaddress_livepatch1.dsc
METADATA += libaddress_livepatch1.ulp
METADATA += libaddress_livepatch1.rev
All of these files are generated from a template file with the same name but
with the .in suffix. The template must be added to EXTRA_DIST, so that it gets
added to the tarball generated by 'make dist':
EXTRA_DIST += libaddress_livepatch1.in
Test driver:
All previous steps create the rules required to build the test objects. Then,
in order to use them, a test driver must be added to automake's TESTS variable:
TESTS += memory_protection.py
|