From c40ba55837657217edf26e5022f3e9400282675e Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Wed, 2 Jul 2008 01:35:58 -0400 Subject: [PATCH] Move objmanip invocations to ksplice.pl and apply them more locally. Signed-off-by: Anders Kaseorg --- Makefile.in | 1 + kmodsrc/Makefile | 28 +++++++- kmodsrc/ksplice.lds | 7 ++ kmodsrc/ld-script | 17 ++++- ksplice-create.in | 183 +--------------------------------------------------- ksplice.pl.in | 172 ++++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 219 insertions(+), 189 deletions(-) create mode 100644 kmodsrc/ksplice.lds diff --git a/Makefile.in b/Makefile.in index 0bc68c8..b1281ca 100644 --- a/Makefile.in +++ b/Makefile.in @@ -71,6 +71,7 @@ install: default install-objmanip install-objdiff install -m644 -D $(srcdir)/kmodsrc/primary.c $(DESTDIR)$(datadir)/ksplice/kmodsrc/primary.c install -m644 -D $(srcdir)/kmodsrc/Makefile $(DESTDIR)$(datadir)/ksplice/kmodsrc/Makefile install -m644 -D $(srcdir)/kmodsrc/ld-script $(DESTDIR)$(datadir)/ksplice/kmodsrc/ld-script + install -m644 -D $(srcdir)/kmodsrc/ksplice.lds $(DESTDIR)$(datadir)/ksplice/kmodsrc/ksplice.lds clean: rm -f $(perl_primary) diff --git a/kmodsrc/Makefile b/kmodsrc/Makefile index ed36203..ba58270 100644 --- a/kmodsrc/Makefile +++ b/kmodsrc/Makefile @@ -1,3 +1,5 @@ +ksplice-script = /usr/local/share/ksplice/ksplice.pl + ifneq ($(KERNELRELEASE),) CFLAGS_ksplice.o += -DKSPLICE_STANDALONE @@ -19,7 +21,31 @@ KSPLICE = ksplice-$(KSPLICE_ID) obj-m = $(KSPLICE)-helper.o $(KSPLICE).o $(KSPLICE)-helper-objs = helper.o collection.o.helper -$(KSPLICE)-objs = primary.o ksplice.o collection.o.primary +$(KSPLICE)-objs = primary.o ksplice-rmsyms.o collection.o.primary +extra-y = ksplice.o + +RMSYMS = \ + thread_return \ + bust_spinlocks \ + task_curr \ + __kernel_text_address \ + tasklist_lock \ + stop_machine_run \ + module_mutex \ + modules \ + init_mm \ + kallsyms_addresses \ + kallsyms_num_syms \ + kallsyms_names \ + kallsyms_token_table \ + kallsyms_token_index + +quiet_cmd_ksplice-rmsyms = RMSYMS $@ +cmd_ksplice-rmsyms = \ + $(ksplice-script) rmsyms $< $(RMSYMS); \ + ld -r -o $@ $< $(src)/ksplice.lds +$(obj)/ksplice-rmsyms.o: $(obj)/ksplice.o FORCE + $(call if_changed,ksplice-rmsyms) else diff --git a/kmodsrc/ksplice.lds b/kmodsrc/ksplice.lds new file mode 100644 index 0000000..6a3ce1a --- /dev/null +++ b/kmodsrc/ksplice.lds @@ -0,0 +1,7 @@ +SECTIONS { + .ksplice_init_relocs : { + ksplice_init_relocs = .; + KEEP(*(.ksplice_init_relocs)) + ksplice_init_relocs_end = .; + } +} diff --git a/kmodsrc/ld-script b/kmodsrc/ld-script index 63e495b..cde4865 100644 --- a/kmodsrc/ld-script +++ b/kmodsrc/ld-script @@ -1,3 +1,18 @@ SECTIONS { - .text : { *(.text*) } + .text : { *(.text .text.*) } + .ksplice_relocs : { + ksplice_relocs = .; + KEEP(*(.ksplice_relocs)) + ksplice_relocs_end = .; + } + .ksplice_sizes : { + ksplice_sizes = .; + KEEP(*(.ksplice_sizes)) + ksplice_sizes_end = .; + } + .ksplice_patches : { + ksplice_patches = .; + KEEP(*(.ksplice_patches)) + ksplice_patches_end = .; + } } diff --git a/ksplice-create.in b/ksplice-create.in index 82626b6..a622702 100755 --- a/ksplice-create.in +++ b/ksplice-create.in @@ -75,6 +75,8 @@ if(! -e "$orig_config_dir/System.map") { die "Failed to find System.map file in ORIG_CONFIG directory"; } +$ENV{KSPLICE_CONFIG_DIR} = $orig_config_dir; + if(!defined $postdir) { $postdir = "$orig_config_dir/post"; } @@ -91,33 +93,13 @@ for(my $z = 0; $z < 8; $z++) { } my $ksplice = "ksplice-$kid"; -my %syms; -load_system_map(); - # Some versions of Fedora have System.map files whose symbol addresses disagree # with the running kernel by a constant address offset. Here, Ksplice notes the # System.map address for printk so that it can later compare this address against # the kernel's address for printk. This comparison helps Ksplice work around # this Fedora problem, and this comparison also helps Ksplice detect whether # the user has provided an incorrect System.map file. -my $map_printk = (find_sym_system_map("printk"))[0]; - -my @rmsyms = qw( - thread_return - bust_spinlocks - task_curr - __kernel_text_address - tasklist_lock - stop_machine_run - module_mutex - modules - init_mm - kallsyms_addresses - kallsyms_num_syms - kallsyms_names - kallsyms_token_table - kallsyms_token_index -); +my $map_printk = runstr("$datadir/ksplice.pl", "system_map_lookup", "printk"); print "Starting kernel builds (this process might take a long time)...\n"; if(!$verbose) { @@ -186,20 +168,8 @@ if(!@modules) { revert_orig(); -my $word; for my $module (@modules) { runcd("$tmpdir/collect"); - open IN, '<', "$module.o.KSPLICE"; - chomp(my $bits = ); - die if($bits != 32 && $bits != 64); - $word = ($bits == 64 ? "quad" : "long"); - - my ($patchlist, $relocs_primary, $relocs_helper) = ('', '', ''); - $patchlist .= $_ while (($_ = ) ne "\n"); - $relocs_primary .= $_ while (($_ = ) ne "\n"); - $relocs_helper .= $_ while (($_ = ) ne "\n"); - - close IN; ################################################################################ # PHASE 3: Combine the target object files and prepare for kernel module build # @@ -210,29 +180,17 @@ for my $module (@modules) { # - saves the list of target entry syms in ELF sect .ksplice.ksplice_patches # ################################################################################ - parse_and_save(\&parse_relocs, $relocs_primary, "$module.o.KSPLICE_primary", - "ksplice_relocs", "_global"); - parse_and_save(\&parse_relocs, $relocs_helper, "$module.o.KSPLICE_helper", - "ksplice_relocs", "_global"); - runcd($tmpdir); runval("cp", "-a", "--", "$datadir/kmodsrc", "kmodsrc-$module"); runval("mv", "collect/$module.o.KSPLICE_primary", "kmodsrc-$module/collection.o.primary"); runval("mv", "collect/$module.o.KSPLICE_helper", "kmodsrc-$module/collection.o.helper"); runcd("kmodsrc-$module"); - my $sizelist_primary = runsuc("objmanip", "collection.o.primary", "sizelist"); - parse_and_save(\&parse_sizelist, $sizelist_primary, "collection.o.primary", "ksplice_sizes"); - my $sizelist_helper = runsuc("objmanip", "collection.o.helper", "sizelist"); - parse_and_save(\&parse_sizelist, $sizelist_helper, "collection.o.helper", "ksplice_sizes"); - runval("ld", "--script=ld-script", "-r", "-o", "collection.o.primary.postld", "collection.o.primary"); runval("cp", "collection.o.primary.postld", "collection.o.primary"); runval("ld", "--script=ld-script", "-r", "-o", "collection.o.helper.postld", "collection.o.helper"); runval("cp", "collection.o.helper.postld", "collection.o.helper"); - parse_and_save(\&parse_patchlist, $patchlist, "collection.o.primary", "ksplice_patches"); - ############################################################################### # PHASE 4: Build the kernel modules and create the update tarball # # - builds primary and helper kernel modules # @@ -244,9 +202,6 @@ for my $module (@modules) { $kid_m =~ s/-/_/g; my $ksplice_m = "ksplice-$kid_m"; runval("make", @jlevel, "modules", "KSPLICE_ID=$kid_m", "map_printk=$map_printk", "KERNELSRC=$linuxtree"); - - my $relocs = runsuc("objmanip", "$ksplice_m.ko", "rmsyms", @rmsyms); - parse_and_save(\&parse_relocs, $relocs, "$ksplice_m.ko", "ksplice_init_relocs", ""); } runcd($tmpdir); @@ -277,138 +232,6 @@ if($apply) { exit(0); -sub load_system_map { - open(SYMS, "<", "$orig_config_dir/System.map") or die; - my $line; - while(defined($line = )) { - my ($addr, $type, $sym, $mod) = split(/\s+/, $line); - next if($sym =~ /init_module/ || - $sym =~ /cleanup_module/ || - $sym =~ /this_module/); - - $syms{$sym}{$addr} = 1; - } - close(SYMS); -} - -sub find_sym_system_map { - my ($sym) = @_; - $sym =~ s/[.]text[.]//g; - $sym =~ s/[.]bss[.]//g; - $sym =~ s/[.]data[.]//g; - $sym =~ s/____.*//g; - if(defined $syms{$sym}) { - return keys(%{$syms{$sym}}); - } - return (); -} - -sub parse_and_save { - my ($funcref, $entries, $objfile, $suffix, @other) = @_; - my @entries = split(/\n/, $entries); - - my @tosave; - foreach my $entry (@entries) { - print $entry, "\n" if($verbose); - &$funcref(\@tosave, $entry, @other); - } - save_using_asm(\@tosave, $objfile, $suffix); -} - -BEGIN { # to make asm_id a static local variable -my ${asm_id} = "0"; -sub save_using_asm { - my ($tosaveref, $objfile, $suffix) = @_; - - open(ASM, ">", "asm${asm_id}.s"); - print ASM ".section .${suffix}, \"a\"\n"; - print ASM "${suffix}:\n"; - - foreach my $entryref (@$tosaveref) { - my @entry = @{$entryref}; - - if($entry[0] eq "str") { - print ASM ".section .ksplice_str, \"a\"\n"; - print ASM "0: .string \"", $entry[1], "\"\n"; - print ASM ".section .${suffix}, \"a\"\n"; - print ASM ".$word 0b\n"; - } - elsif($entry[0] eq "array" && scalar(@entry) == 1) { - print ASM ".section .${suffix}, \"a\"\n"; - print ASM ".$word 0x0\n"; - } - elsif($entry[0] eq "array") { - print ASM ".section .ksplice_array, \"a\"\n"; - print ASM "0:\n"; - for(my $i = 1; $i < scalar(@entry); $i++) { - print ASM ".$word 0x", $entry[$i], "\n"; - } - print ASM ".section .${suffix}, \"a\"\n"; - print ASM ".$word 0b\n"; - } - elsif($entry[0] eq "word") { - print ASM ".section .${suffix}, \"a\"\n"; - print ASM ".$word 0x", $entry[1], "\n"; - } - elsif($entry[0] eq "ptr") { - print ASM ".section .${suffix}, \"a\"\n"; - print ASM ".$word ", $entry[1], "\n"; - } - else { die; } - } - print ASM ".section .${suffix}, \"a\"\n"; - print ASM "${suffix}_end:\n"; - print ASM ".globl ${suffix}\n"; - print ASM ".globl ${suffix}_end\n"; - close(ASM); - - runval("gcc", "-mcmodel=kernel", "-c", "asm${asm_id}.s", "-o", "asm${asm_id}.o"); - runval("ld", "-r", "-o", "$objfile.new", $objfile, "asm${asm_id}.o"); - runval("mv", "$objfile.new", $objfile); - ${asm_id}++; -} -} # close BEGIN - -sub parse_relocs { - my ($tosaveref, $entry, $globalizer) = @_; - my ($sym, $sect, $addr, $pcrel, $addend, $size) = split(/\s/, $entry); - - my ($func) = ($sect =~ /(.*)____/); - $sym =~ s/([.]data[.]__func__[.])\d+/$1${func}/g; - - my @symvals = find_sym_system_map($sym); - - push @$tosaveref, (["str", $sym], ["str", $sect], - ["ptr", "${sect}${globalizer}"], - ["word", $addr], - ["word", scalar(@symvals)], - ["array", @symvals], - ["word", $pcrel], - ["word", $addend], - ["word", $size]); -} - -sub parse_sizelist { - my ($tosaveref, $entry) = @_; - # grab the size and the symbol name from the end of the line - my ($size, $sym) = ($entry =~ /\s([a-z0-9]+)\s+(\S+)$/); - - my @vals = find_sym_system_map($sym); - - push @$tosaveref, (["str", $sym], ["word", $size], - ["ptr", "${sym}_global"], ["word", scalar(@vals)], - ["array", @vals]); -} - -sub parse_patchlist { - my ($tosaveref, $entry) = @_; - my ($oldsym, $replsym) = split(/\s/, $entry); - - push @$tosaveref, (["str", $oldsym], ["str", $replsym], - ["word", 0], ["ptr", "${replsym}_global"], - ["word", 0]); -} - =head1 NAME ksplice-create - Create a set of kernel modules for a rebootless kernel update diff --git a/ksplice.pl.in b/ksplice.pl.in index d3629f3..19f79a1 100755 --- a/ksplice.pl.in +++ b/ksplice.pl.in @@ -42,6 +42,9 @@ sub do_snap { empty_diff($out); } +my %syms; +my $word; + sub do_diff { my ($out) = @_; my ($obj) = $out =~ /^(.*)\.KSPLICE$/ or die; @@ -57,6 +60,8 @@ sub do_diff { die if ($bits ne '32' && $bits ne '64'); return empty_diff($out) if ($sections eq '' && $entrysyms eq ''); + $word = ($bits == 64 ? "quad" : "long"); + copy($obj, "$obj.KSPLICE_primary"); copy($obj_old, "$obj.KSPLICE_helper"); @@ -66,19 +71,31 @@ sub do_diff { close OBJ; close OBJ_OLD; + load_system_map(); + my $relocs_primary = runsuc("objmanip", "$obj.KSPLICE_primary", "keep-primary", "____${tag}", "_post", split(/\s/, $sections)); runsuc("objmanip", "$obj.KSPLICE_primary", "globalize", "____${tag}_post"); + parse_and_save(\&parse_relocs, $relocs_primary, "$obj.KSPLICE_primary", + "ksplice_relocs", "_global"); my $relocs_helper = runsuc("objmanip", "$obj.KSPLICE_helper", "keep-helper", "____${tag}", "_pre"); runsuc("objmanip", "$obj.KSPLICE_helper", "globalize", "____${tag}_pre"); + parse_and_save(\&parse_relocs, $relocs_helper, "$obj.KSPLICE_helper", + "ksplice_relocs", "_global"); + + my $sizelist_primary = runsuc("objmanip", "$obj.KSPLICE_primary", "sizelist"); + parse_and_save(\&parse_sizelist, $sizelist_primary, "$obj.KSPLICE_primary", "ksplice_sizes"); + my $sizelist_helper = runsuc("objmanip", "$obj.KSPLICE_helper", "sizelist"); + parse_and_save(\&parse_sizelist, $sizelist_helper, "$obj.KSPLICE_helper", "ksplice_sizes"); my $patchlist = ""; foreach my $sym (split(/\s/, $entrysyms)) { $patchlist .= "${sym}____${tag}_pre ${sym}____${tag}_post\n"; } + parse_and_save(\&parse_patchlist, $patchlist, "$obj.KSPLICE_primary", "ksplice_patches"); open OUT, '>', "$out.tmp"; - print OUT "$bits\n$patchlist\n$relocs_primary\n$relocs_helper\n"; + print OUT "$bits\n"; close OUT; rename "$out.tmp", $out; } @@ -86,7 +103,7 @@ sub do_diff { sub do_combine { my ($out, @ins) = @_; my @objs; - my ($outbits, $patchlist, $relocs_primary, $relocs_helper) = (undef, '', '', ''); + my $outbits = undef; foreach my $in (@ins) { next if (!-s $in); my ($obj) = $in =~ /^(.*)\.KSPLICE$/ or die; @@ -98,10 +115,6 @@ sub do_combine { die if (defined $outbits && $outbits ne $bits); $outbits = $bits; - $patchlist .= $_ while (($_ = ) ne "\n"); - $relocs_primary .= $_ while (($_ = ) ne "\n"); - $relocs_helper .= $_ while (($_ = ) ne "\n"); - close IN; } @@ -119,15 +132,33 @@ sub do_combine { } open OUT, '>', "$out.tmp"; - print OUT "$outbits\n$patchlist\n$relocs_primary\n$relocs_helper\n"; + print OUT "$outbits\n"; close OUT; rename "$out.tmp", $out; } +sub do_rmsyms { + my ($obj, @rmsyms) = @_; + load_system_map(); + my ($bits) = split("\n", runsuc("objdiff", $obj, $obj)); + die if ($bits ne '32' && $bits ne '64'); + $word = ($bits == 64 ? "quad" : "long"); + my $relocs = runsuc("objmanip", $obj, "rmsyms", @rmsyms); + parse_and_save(\&parse_relocs, $relocs, $obj, "ksplice_init_relocs", ""); +} + +sub do_system_map_lookup { + my ($sym) = @_; + load_system_map(); + print ((find_sym_system_map($sym))[0]); +} + my %handlers = ( 'snap' => \&do_snap, 'diff' => \&do_diff, 'combine' => \&do_combine, + 'rmsyms' => \&do_rmsyms, + 'system_map_lookup' => \&do_system_map_lookup, ); my ($cmd, @args) = @ARGV; @@ -137,3 +168,130 @@ if (exists $handlers{$cmd}) { } else { print "Usage: ksplice.pl ", join('|', keys %handlers), " ...\n"; }; + +exit 0; + +sub load_system_map { + open(SYMS, "<", "$ENV{KSPLICE_CONFIG_DIR}/System.map") or die; + my $line; + while(defined($line = )) { + my ($addr, $type, $sym, $mod) = split(/\s+/, $line); + next if($sym =~ /init_module/ || + $sym =~ /cleanup_module/ || + $sym =~ /this_module/); + + $syms{$sym}{$addr} = 1; + } + close(SYMS); +} + +sub find_sym_system_map { + my ($sym) = @_; + $sym =~ s/[.]text[.]//g; + $sym =~ s/[.]bss[.]//g; + $sym =~ s/[.]data[.]//g; + $sym =~ s/____.*//g; + if(defined $syms{$sym}) { + return keys(%{$syms{$sym}}); + } + return (); +} + +sub parse_and_save { + my ($funcref, $entries, $objfile, $suffix, @other) = @_; + my @entries = split(/\n/, $entries); + + my @tosave; + foreach my $entry (@entries) { + print $entry, "\n" if($verbose); + &$funcref(\@tosave, $entry, @other); + } + save_using_asm(\@tosave, $objfile, $suffix); +} + +sub save_using_asm { + my ($tosaveref, $objfile, $suffix) = @_; + + my $asm_base = "$objfile.$suffix"; + + open(ASM, ">", "$asm_base.s"); + print ASM ".section .${suffix}, \"a\"\n"; + + foreach my $entryref (@$tosaveref) { + my @entry = @{$entryref}; + + if($entry[0] eq "str") { + print ASM ".section .ksplice_str, \"a\"\n"; + print ASM "0: .string \"", $entry[1], "\"\n"; + print ASM ".section .${suffix}, \"a\"\n"; + print ASM ".$word 0b\n"; + } + elsif($entry[0] eq "array" && scalar(@entry) == 1) { + print ASM ".section .${suffix}, \"a\"\n"; + print ASM ".$word 0x0\n"; + } + elsif($entry[0] eq "array") { + print ASM ".section .ksplice_array, \"a\"\n"; + print ASM "0:\n"; + for(my $i = 1; $i < scalar(@entry); $i++) { + print ASM ".$word 0x", $entry[$i], "\n"; + } + print ASM ".section .${suffix}, \"a\"\n"; + print ASM ".$word 0b\n"; + } + elsif($entry[0] eq "word") { + print ASM ".section .${suffix}, \"a\"\n"; + print ASM ".$word 0x", $entry[1], "\n"; + } + elsif($entry[0] eq "ptr") { + print ASM ".section .${suffix}, \"a\"\n"; + print ASM ".$word ", $entry[1], "\n"; + } + else { die; } + } + close(ASM); + + runval("gcc", "-mcmodel=kernel", "-c", "$asm_base.s", "-o", "$asm_base.o"); + runval("mv", $objfile, "$objfile.pre$suffix"); + runval("ld", "-r", "-o", "$objfile", "$objfile.pre$suffix", "$asm_base.o"); +} + +sub parse_relocs { + my ($tosaveref, $entry, $globalizer) = @_; + my ($sym, $sect, $addr, $pcrel, $addend, $size) = split(/\s/, $entry); + + my ($func) = ($sect =~ /(.*)____/); + $sym =~ s/([.]data[.]__func__[.])\d+/$1${func}/g; + + my @symvals = find_sym_system_map($sym); + + push @$tosaveref, (["str", $sym], ["str", $sect], + ["ptr", "${sect}${globalizer}"], + ["word", $addr], + ["word", scalar(@symvals)], + ["array", @symvals], + ["word", $pcrel], + ["word", $addend], + ["word", $size]); +} + +sub parse_sizelist { + my ($tosaveref, $entry) = @_; + # grab the size and the symbol name from the end of the line + my ($size, $sym) = ($entry =~ /\s([a-z0-9]+)\s+(\S+)$/); + + my @vals = find_sym_system_map($sym); + + push @$tosaveref, (["str", $sym], ["word", $size], + ["ptr", "${sym}_global"], ["word", scalar(@vals)], + ["array", @vals]); +} + +sub parse_patchlist { + my ($tosaveref, $entry) = @_; + my ($oldsym, $replsym) = split(/\s/, $entry); + + push @$tosaveref, (["str", $oldsym], ["str", $replsym], + ["word", 0], ["ptr", "${replsym}_global"], + ["word", 0]); +} -- 2.11.4.GIT