3 # Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>,
4 # Jeffrey Brian Arnold <jbarnold@mit.edu>,
5 # Tim Abbott <tabbott@mit.edu>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License, version 2.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 use lib
'KSPLICE_DATA_DIR';
29 my ($obj) = $out =~ /^(.*)\.KSPLICE$/ or die;
30 unlink "$obj.KSPLICE_primary" if (-e
"$obj.KSPLICE_primary");
31 unlink "$obj.KSPLICE_helper" if (-e
"$obj.KSPLICE_helper");
32 open OUT
, '>', "$out.tmp";
34 rename "$out.tmp", $out;
39 my ($obj) = $out =~ /^(.*)\.KSPLICE$/ or die;
41 unlink "$obj.KSPLICE_pre" if (-e
"$obj.KSPLICE_pre");
50 my ($obj) = $out =~ /^(.*)\.KSPLICE$/ or die;
51 my $obj_old = "$obj.KSPLICE_pre";
52 return do_snap
($out) if (!-e
$obj_old);
54 if (system('cmp', '-s', '--', $obj_old, $obj) == 0) {
56 return empty_diff
($out);
59 my ($bits, $sections, $entrysyms) = split("\n", runsuc
("objdiff", $obj_old, $obj));
60 die if ($bits ne '32' && $bits ne '64');
61 return empty_diff
($out) if ($sections eq '' && $entrysyms eq '');
63 $word = ($bits == 64 ?
"quad" : "long");
65 copy
($obj, "$obj.KSPLICE_primary");
66 copy
($obj_old, "$obj.KSPLICE_helper");
68 open OBJ
, '<', $obj or die;
69 open OBJ_OLD
, '<', $obj_old or die;
70 my $tag = Digest
::MD5
->new->addfile(*OBJ
)->addfile(*OBJ_OLD
)->hexdigest;
76 runsuc
("objmanip", "$obj.KSPLICE_primary", "keep-primary", "____${tag}", "_post", split(/\s/, $sections));
77 runsuc
("objmanip", "$obj.KSPLICE_primary", "globalize", "____${tag}_post");
79 runsuc
("objmanip", "$obj.KSPLICE_helper", "keep-helper", "____${tag}", "_pre");
80 runsuc
("objmanip", "$obj.KSPLICE_helper", "globalize", "____${tag}_pre");
82 my $sizelist_primary = runsuc
("objmanip", "$obj.KSPLICE_primary", "sizelist");
83 parse_and_save
(\
&parse_sizelist
, $sizelist_primary, "$obj.KSPLICE_primary", "ksplice_sizes");
84 my $sizelist_helper = runsuc
("objmanip", "$obj.KSPLICE_helper", "sizelist");
85 parse_and_save
(\
&parse_sizelist
, $sizelist_helper, "$obj.KSPLICE_helper", "ksplice_sizes");
88 foreach my $sym (split(/\s/, $entrysyms)) {
89 $patchlist .= "${sym}____${tag}_pre ${sym}____${tag}_post\n";
91 parse_and_save
(\
&parse_patchlist
, $patchlist, "$obj.KSPLICE_primary", "ksplice_patches");
93 open OUT
, '>', "$out.tmp";
96 rename "$out.tmp", $out;
100 my ($out, @ins) = @_;
103 foreach my $in (@ins) {
105 my ($obj) = $in =~ /^(.*)\.KSPLICE$/ or die;
110 chomp(my $bits = <IN
>);
111 die if (defined $outbits && $outbits ne $bits);
117 return empty_diff
($out) unless (defined $outbits);
119 my ($obj) = $out =~ /^(.*)\.KSPLICE$/ or die;
121 copy
"$objs[0].KSPLICE_primary", "$obj.KSPLICE_primary";
122 copy
"$objs[0].KSPLICE_helper", "$obj.KSPLICE_helper";
124 system("ld", "-r", "-o",
125 map { "$_.KSPLICE_primary" } ($obj, @objs));
126 system("ld", "-r", "-o",
127 map { "$_.KSPLICE_helper" } ($obj, @objs));
130 open OUT
, '>', "$out.tmp";
131 print OUT
"$outbits\n";
133 rename "$out.tmp", $out;
137 my ($obj, @rmsyms) = @_;
138 my $relocs = runsuc
("objmanip", $obj, "rmsyms", @rmsyms);
141 sub do_system_map_lookup
{
144 print ((find_sym_system_map
($sym))[0]);
150 'combine' => \
&do_combine
,
151 'rmsyms' => \
&do_rmsyms
,
152 'system_map_lookup' => \
&do_system_map_lookup
,
155 my ($cmd, @args) = @ARGV;
156 if (exists $handlers{$cmd}) {
157 my $handler = $handlers{$cmd};
160 print "Usage: ksplice.pl ", join('|', keys %handlers), " ...\n";
165 sub load_system_map
{
166 open(SYMS
, "<", "$ENV{KSPLICE_CONFIG_DIR}/System.map") or die;
168 while(defined($line = <SYMS
>)) {
169 my ($addr, $type, $sym, $mod) = split(/\s+/, $line);
170 next if($sym =~ /init_module/ ||
171 $sym =~ /cleanup_module/ ||
172 $sym =~ /this_module/);
174 $syms{$sym}{$addr} = 1;
179 sub find_sym_system_map
{
181 $sym =~ s/[.]text[.]//g;
182 $sym =~ s/[.]bss[.]//g;
183 $sym =~ s/[.]data[.]//g;
185 if(defined $syms{$sym}) {
186 return keys(%{$syms{$sym}});
192 my ($funcref, $entries, $objfile, $suffix, @other) = @_;
193 my @entries = split(/\n/, $entries);
196 foreach my $entry (@entries) {
197 print $entry, "\n" if($verbose);
198 &$funcref(\
@tosave, $entry, @other);
200 save_using_asm
(\
@tosave, $objfile, $suffix);
204 my ($tosaveref, $objfile, $suffix) = @_;
206 my $asm_base = "$objfile.$suffix";
208 open(ASM
, ">", "$asm_base.s");
209 print ASM
".section .${suffix}, \"a\"\n";
211 foreach my $entryref (@
$tosaveref) {
212 my @entry = @
{$entryref};
214 if($entry[0] eq "str") {
215 print ASM
".section .ksplice_str, \"a\"\n";
216 print ASM
"0: .string \"", $entry[1], "\"\n";
217 print ASM
".section .${suffix}, \"a\"\n";
218 print ASM
".$word 0b\n";
220 elsif($entry[0] eq "array" && scalar(@entry) == 1) {
221 print ASM
".section .${suffix}, \"a\"\n";
222 print ASM
".$word 0x0\n";
224 elsif($entry[0] eq "array") {
225 print ASM
".section .ksplice_array, \"a\"\n";
227 for(my $i = 1; $i < scalar(@entry); $i++) {
228 print ASM
".$word 0x", $entry[$i], "\n";
230 print ASM
".section .${suffix}, \"a\"\n";
231 print ASM
".$word 0b\n";
233 elsif($entry[0] eq "word") {
234 print ASM
".section .${suffix}, \"a\"\n";
235 print ASM
".$word 0x", $entry[1], "\n";
237 elsif($entry[0] eq "ptr") {
238 print ASM
".section .${suffix}, \"a\"\n";
239 print ASM
".$word ", $entry[1], "\n";
245 runval
("gcc", "-mcmodel=kernel", "-c", "$asm_base.s", "-o", "$asm_base.o");
246 runval
("mv", $objfile, "$objfile.pre$suffix");
247 runval
("ld", "-r", "-o", "$objfile", "$objfile.pre$suffix", "$asm_base.o");
251 my ($tosaveref, $entry) = @_;
252 # grab the size and the symbol name from the end of the line
253 my ($size, $sym) = ($entry =~ /\s([a-z0-9]+)\s+(\S+)$/);
255 my @vals = find_sym_system_map
($sym);
257 push @
$tosaveref, (["str", $sym], ["word", $size],
258 ["ptr", "${sym}_global"], ["word", scalar(@vals)],
262 sub parse_patchlist
{
263 my ($tosaveref, $entry) = @_;
264 my ($oldsym, $replsym) = split(/\s/, $entry);
266 push @
$tosaveref, (["str", $oldsym], ["str", $replsym],
267 ["word", 0], ["ptr", "${replsym}_global"],