Merge copy_section and write_new_section into write_section.
[ksplice.git] / ksplice-create.in
blob90718b7bee101cc8d07c4d315ec3b14df0ba1d56
1 #!/usr/bin/perl
3 # Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License, version 2.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
16 # 02110-1301, USA.
18 use Getopt::Long;
19 use Cwd 'abs_path', 'getcwd';
20 use Pod::Usage;
21 use strict;
22 use warnings;
23 use lib 'KSPLICE_DATA_DIR';
24 use ksplice;
26 my ($patchfile, $diffext, $orig_config_dir, $jobs, $kid);
27 my ($help, $wantversion, $prebuild, $skip_prebuild, $apply, $patch_opt) = (0, 0, 0, 0, 0, "-p1");
28 Getopt::Long::Configure("bundling");
29 GetOptions("help|?" => \$help,
30 "version" => \$wantversion,
31 "verbose|v!" => \$verbose,
32 "id=s" => \$kid,
33 "patch=s" => \$patchfile,
34 "diffext=s" => \$diffext,
35 "prebuild" => \$prebuild,
36 "skip-prebuild" => \$skip_prebuild,
37 "jobs|j:i" => \$jobs,
38 "config=s" => \$orig_config_dir,
39 "apply" => \$apply,
40 "patch-opt=s@" => \$patch_opt) or pod2usage(1);
42 if($wantversion) {
43 print $version_str;
44 exit(0);
46 pod2usage(1) if($help || scalar(@ARGV) != 1);
47 my $actions = (defined $patchfile) + (defined $diffext) + ($prebuild);
48 pod2usage(1) if($actions != 1);
50 my ($linuxtree) = (abs_path($ARGV[0]));
52 my $tmpdir = init_tmpdir();
53 runval("cp", "--", $patchfile, "$tmpdir/patch") if(defined $patchfile);
54 $patchfile = "$tmpdir/patch";
56 $patch_opt = "-p0" if(defined $diffext);
57 $patch_opt = join(" ", @$patch_opt) if(ref $patch_opt);
59 if(!defined $orig_config_dir) {
60 $orig_config_dir = "$linuxtree/ksplice";
62 else {
63 $orig_config_dir = abs_path($orig_config_dir);
64 if($orig_config_dir =~ $linuxtree) {
65 die "Aborting: User-specified ORIG_CONFIG cannot be KERNEL_SOURCE or a subdirectory";
68 if(!defined $orig_config_dir || ! -d $orig_config_dir) {
69 die "Failed to find ORIG_CONFIG directory ($orig_config_dir)";
71 if(! -e "$orig_config_dir/.config") {
72 die "Failed to find .config file in ORIG_CONFIG directory";
74 if(! -e "$orig_config_dir/System.map") {
75 die "Failed to find System.map file in ORIG_CONFIG directory";
78 $ENV{KSPLICE_CONFIG_DIR} = $orig_config_dir;
80 runval("cp", "--", "$orig_config_dir/.config", $linuxtree);
82 my @chars = ('a'..'z', 0..9);
83 $kid = join '', map { $chars[int(rand(36))] } 0..7 if(!defined $kid);
84 my $ksplice = "ksplice-$kid";
86 # Some versions of Fedora have System.map files whose symbol addresses disagree
87 # with the running kernel by a constant address offset. Here, Ksplice notes the
88 # System.map address for printk so that it can later compare this address against
89 # the kernel's address for printk. This comparison helps Ksplice work around
90 # this Fedora problem, and this comparison also helps Ksplice detect whether
91 # the user has provided an incorrect System.map file.
92 my $map_printk = runstr("$datadir/ksplice.pl", "system_map_lookup", "printk");
94 print "Starting kernel builds (this process might take a long time)...\n";
95 if(!$verbose) {
96 print "For output during this process, run ksplice-create with the option -v\n";
99 ###################################################################
100 # PHASE 1: Determine which object files are modified by the patch #
101 # - performs the pre and post kernel builds #
102 # - uses objdiff to identify which ELF sections have changed and #
103 # which ELF symbols are entry points to those sections #
104 ###################################################################
106 # We will refer to the object files modified by the patch as the "target object
107 # files", the ELF sections changed by the patch as the "target sections", and
108 # the entry points of those sections as the "target entry points".
110 my $origdir = getcwd();
111 runcd($linuxtree);
112 if(defined $diffext) {
113 runval("$libexecdir/ksplice-gendiff-reversed >$patchfile . $diffext");
116 my @jlevel = (defined $ENV{CONCURRENCY_LEVEL} ? ("-j$ENV{CONCURRENCY_LEVEL}") : ());
117 @jlevel = ("-j$jobs") if(defined $jobs);
118 my @make_ksplice = ("make", "-f", "$datadir/Makefile.ksplice", @jlevel);
120 sub revert_orig() {
121 for (split(/\0/, runstr(qw(find -name *.KSPLICE_pre -print0)))) {
122 s/\.KSPLICE_pre$//;
123 rename("$_.KSPLICE_pre", $_);
124 unlink("$_.KSPLICE") if(-e "$_.KSPLICE");
127 revert_orig();
129 if(!$skip_prebuild &&
130 runval_raw(@make_ksplice, "KSPLICE_MODE=snap") != 0) {
131 die "Aborting: Prebuild failed";
133 exit(0) if($prebuild);
134 runval("patch $patch_opt -bz .KSPLICE_pre < $patchfile");
135 if(runval_raw(@make_ksplice, "KSPLICE_MODE=diff") != 0) {
136 revert_orig();
137 die "Aborting: Applying the patch appears to break the kernel build";
140 runval("mkdir", "-p", "--", "$tmpdir/collect");
142 my @modules = ();
143 foreach(glob(".tmp_versions/*.mod.KSPLICE")) {
144 open MOD, '<', $_;
145 chomp(my $module = <MOD>);
146 close MOD;
147 runval("cp", "$module.o.KSPLICE", "$tmpdir/collect/");
148 runval("cp", "$module.o.KSPLICE_primary", "$tmpdir/collect/");
149 runval("cp", "$module.o.KSPLICE_helper", "$tmpdir/collect/");
150 $module =~ s/^.*\///;
151 push @modules, $module;
154 if(!@modules) {
155 revert_orig();
156 die "Aborting: No changes detected";
159 revert_orig();
161 for my $module (@modules) {
162 runcd("$tmpdir/collect");
164 ################################################################################
165 # PHASE 3: Combine the target object files and prepare for kernel module build #
166 # - links the many target object files into two "collection" object files #
167 # - saves the reloc info extracted earlier in ELF sect .ksplice.ksplice_relocs #
168 # - uses objmanip's sizelist mode to save the names and sizes of target funcs #
169 # - uses ld-script to aggregate all ELF text sections into .text #
170 # - saves the list of target entry syms in ELF sect .ksplice.ksplice_patches #
171 ################################################################################
173 runcd($tmpdir);
174 runval("cp", "-a", "--", "$datadir/kmodsrc", "kmodsrc-$module");
175 runval("mv", "collect/$module.o.KSPLICE_primary", "kmodsrc-$module/collection.o.primary");
176 runval("mv", "collect/$module.o.KSPLICE_helper", "kmodsrc-$module/collection.o.helper");
177 runcd("kmodsrc-$module");
179 runval("ld", "--script=ld-script", "-r", "-o", "collection.o.primary.postld", "collection.o.primary");
180 runval("cp", "collection.o.primary.postld", "collection.o.primary");
181 runval("ld", "--script=ld-script", "-r", "-o", "collection.o.helper.postld", "collection.o.helper");
182 runval("cp", "collection.o.helper.postld", "collection.o.helper");
184 ###############################################################################
185 # PHASE 4: Build the kernel modules and create the update tarball #
186 # - builds primary and helper kernel modules #
187 # - uses objmanip's rmsyms mode to remove relocations to non-exported symbols #
188 # - creates a tarball of the primary module and the helper module #
189 ###############################################################################
191 my $kid_m = "${kid}_$module";
192 $kid_m =~ s/-/_/g;
193 my $ksplice_m = "ksplice-$kid_m";
194 runval("make", @jlevel, "modules", "KSPLICE_ID=$kid_m", "KSPLICE_TARGET=$module", "map_printk=$map_printk", "KERNELSRC=$linuxtree");
197 runcd($tmpdir);
198 runval("mkdir", $ksplice);
199 runval("mv", "--", $patchfile, $ksplice);
200 for my $module (@modules) {
201 my $kid_m = "${kid}_$module";
202 $kid_m =~ s/-/_/g;
203 my $ksplice_m = "ksplice-$kid_m";
204 runval("mv", "--", "kmodsrc-$module/$ksplice_m.ko", "kmodsrc-$module/$ksplice_m-helper.ko", $ksplice);
206 runval("mkdir", "$ksplice/debug");
207 runval("mv", "collect", "$ksplice/debug");
208 for my $module (@modules) {
209 runval("mv", "kmodsrc-$module", "$ksplice/debug");
211 runval("tar", "czf", "$ksplice.tar.gz", "--", $ksplice);
212 runval("cp", "--", "$ksplice.tar.gz", $origdir);
213 runcd($origdir);
214 runval("rm", "-rf", "--", "$tmpdir");
216 print "Ksplice update tarball written to $ksplice.tar.gz\n";
218 if($apply) {
219 print "Now running ksplice-apply to apply update...\n";
220 exec("ksplice-apply", $ksplice) || die;
223 exit(0);
225 =head1 NAME
227 ksplice-create - Create a set of kernel modules for a rebootless kernel update
229 =head1 SYNOPSIS
231 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--patch=>I<PATCH_FILE> I<KERNEL_SOURCE>
233 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--diffext=>I<EXTENSION> I<KERNEL_SOURCE>
235 B<ksplice-create> [B<--config=>I<ORIG_CONFIG>] B<--prebuild> I<KERNEL_SOURCE>
237 =head1 DESCRIPTION
239 B<ksplice-create> creates a set of Ksplice kernel modules that, when loaded,
240 will apply a user-specified source code patch to the running binary kernel.
242 Before you use B<ksplice-create> on a patch, you should confirm that the
243 desired source code change does not make any semantic changes to kernel data
244 structures--that is, changes that would require existing instances of kernel
245 data structures to be transformed (e.g., a patch that adds a field to a global
246 data structure would require the existing data structures to change). If you
247 use Ksplice on a patch that changes data structure semantics, Ksplice will not
248 detect the problem and you could experience kernel problems as a result.
250 The to-be-applied source code patch can be specified by providing a L<patch(1)>
251 file (B<--patch=>I<PATCH_FILE>) or by providing a file extension
252 (B<--diffext=>I<EXTENSION>).
254 If a file extension is specified, then the desired source code patch will be
255 determined by comparing all of the files in the I<KERNEL_SOURCE> directory tree
256 whose names end with the extra extension I<EXTENSION> against the corresponding
257 files without the extra extension. Only the new files containing the extra
258 extension in their filenames should be modified.
260 Here is an example of using a file extension to specify a patch:
262 $ cp KERNEL_SOURCE/kernel/sys.c KERNEL_SOURCE/kernel/sys.c.prctl_fixed
263 [edit sys.c.prctl_fixed to include the desired changes]
264 $ ksplice-create --diffext=.prctl_fixed KERNEL_SOURCE
266 KERNEL_SOURCE must be a directory containing the to-be-updated kernel's
267 original source code. If your Linux distribution applies patches to the Linux
268 kernel during the kernel build process, then those patches must be applied to
269 the I<KERNEL_SOURCE> directory before invoking B<ksplice-create> on that
270 directory. B<ksplice-create> will not modify the source code in the
271 I<KERNEL_SOURCE> directory tree, but it will perform a kernel build in that
272 directory tree.
274 I<ORIG_CONFIG> can be used to specify the directory containing the
275 to-be-updated kernel's original F<.config> file and original F<System.map> file
276 (the files should have exactly those names). I<ORIG_CONFIG> defaults to
277 I<KERNEL_SOURCE>B</ksplice>.
279 The default L<gcc(1)> compiler and L<as(1)> assembler on the system should be as
280 close to the compiler and assembler originally used to build the running kernel
281 as possible. If the current compiler and linker are too different from the
282 original compiler and linker, B<ksplice-apply> will abort when applying the
283 update.
285 B<ksplice-create> outputs a L<tar(1)> file, compressed with L<gzip(1)>,
286 containing the desired Ksplice update modules. This tarball will be created in
287 the current directory, and it can be manipulated using the other Ksplice
288 utilities, such as B<ksplice-apply>.
290 The first time that B<ksplice-create> is invoked on a I<KERNEL_SOURCE>
291 directory, it must build that kernel from scratch, which is much slower than
292 the rest of the update-creation process. B<--prebuild> can be used to perform
293 this initial kernel build without providing a source code patch.
295 In order to patch a function that has previously been patched by Ksplice, the
296 user needs to ensure that the I<KERNEL_SOURCE> directory provided to Ksplice
297 contains the source for the currently running kernel, including any patches
298 that have previously been applied by Ksplice.
300 =head1 OPTIONS
302 =over 8
304 =item B<-v>, B<--verbose>
306 Prints the commands being executed, the output of the commands being executed,
307 and various other pieces of information.
309 =item B<-j> I<JOBS>, B<--jobs=>I<JOBS>
311 Specifies the number of jobs to run simultaneously while performing kernel
312 builds. B<ksplice-create> also honors the environment variable
313 CONCURRENCY_LEVEL.
315 =item B<--apply>
317 Immediately applies the generated update to the running kernel by invoking
318 B<ksplice-apply>.
320 =item B<--patch-opt=>I<OPTIONS>
322 Can be used to pass options to L<patch(1)>. If this option is NOT specified, then
323 B<-p1> is passed to B<patch>. If this option is specified, then only the
324 specified options will be passed to B<patch>. This option can be repeated in
325 order to pass multiple options to B<patch>. This option is ignored when the
326 to-be-applied source code patch is specified using B<--diffext>.
328 =item B<--id=>I<ID>
330 Specifies the unique value that will be used as the identifier of the
331 Ksplice update. This identifier will, for example, appear in the name
332 of the update tarball. By default, a random 8-character ID will be
333 generated.
335 =back
337 =head1 BUGS
339 Please report bugs to <PACKAGE_BUGREPORT>.
341 =head1 SEE ALSO
343 L<ksplice-apply(8)>, L<ksplice-view(8)>, L<ksplice-undo(8)>
345 =head1 COPYRIGHT
347 Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>.
349 This is free software and documentation. You can redistribute and/or modify it
350 under the terms of the GNU General Public License, version 2.
352 =cut