Move objmanip invocations to ksplice.pl and apply them more locally.
[ksplice.git] / ksplice.pl.in
blob19f79a1f3d5a020f69f09deaf992404090e62273
1 #!/usr/bin/perl
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
18 # 02110-1301, USA.
20 use strict;
21 use warnings;
22 use lib 'KSPLICE_DATA_DIR';
23 use ksplice;
24 use File::Copy;
25 use Digest::MD5;
27 sub empty_diff {
28 my ($out) = @_;
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";
33 close OUT;
34 rename "$out.tmp", $out;
37 sub do_snap {
38 my ($out) = @_;
39 my ($obj) = $out =~ /^(.*)\.KSPLICE$/ or die;
40 die if (!-e $obj);
41 unlink "$obj.KSPLICE_pre" if (-e "$obj.KSPLICE_pre");
42 empty_diff($out);
45 my %syms;
46 my $word;
48 sub do_diff {
49 my ($out) = @_;
50 my ($obj) = $out =~ /^(.*)\.KSPLICE$/ or die;
51 my $obj_old = "$obj.KSPLICE_pre";
52 return do_snap($out) if (!-e $obj_old);
53 die if (!-e $obj);
54 if (system('cmp', '-s', '--', $obj_old, $obj) == 0) {
55 unlink $obj_old;
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;
71 close OBJ;
72 close OBJ_OLD;
74 load_system_map();
76 my $relocs_primary = runsuc("objmanip", "$obj.KSPLICE_primary", "keep-primary", "____${tag}", "_post", split(/\s/, $sections));
77 runsuc("objmanip", "$obj.KSPLICE_primary", "globalize", "____${tag}_post");
78 parse_and_save(\&parse_relocs, $relocs_primary, "$obj.KSPLICE_primary",
79 "ksplice_relocs", "_global");
81 my $relocs_helper = runsuc("objmanip", "$obj.KSPLICE_helper", "keep-helper", "____${tag}", "_pre");
82 runsuc("objmanip", "$obj.KSPLICE_helper", "globalize", "____${tag}_pre");
83 parse_and_save(\&parse_relocs, $relocs_helper, "$obj.KSPLICE_helper",
84 "ksplice_relocs", "_global");
86 my $sizelist_primary = runsuc("objmanip", "$obj.KSPLICE_primary", "sizelist");
87 parse_and_save(\&parse_sizelist, $sizelist_primary, "$obj.KSPLICE_primary", "ksplice_sizes");
88 my $sizelist_helper = runsuc("objmanip", "$obj.KSPLICE_helper", "sizelist");
89 parse_and_save(\&parse_sizelist, $sizelist_helper, "$obj.KSPLICE_helper", "ksplice_sizes");
91 my $patchlist = "";
92 foreach my $sym (split(/\s/, $entrysyms)) {
93 $patchlist .= "${sym}____${tag}_pre ${sym}____${tag}_post\n";
95 parse_and_save(\&parse_patchlist, $patchlist, "$obj.KSPLICE_primary", "ksplice_patches");
97 open OUT, '>', "$out.tmp";
98 print OUT "$bits\n";
99 close OUT;
100 rename "$out.tmp", $out;
103 sub do_combine {
104 my ($out, @ins) = @_;
105 my @objs;
106 my $outbits = undef;
107 foreach my $in (@ins) {
108 next if (!-s $in);
109 my ($obj) = $in =~ /^(.*)\.KSPLICE$/ or die;
110 push @objs, $obj;
112 open IN, '<', $in;
114 chomp(my $bits = <IN>);
115 die if (defined $outbits && $outbits ne $bits);
116 $outbits = $bits;
118 close IN;
121 return empty_diff($out) unless (defined $outbits);
123 my ($obj) = $out =~ /^(.*)\.KSPLICE$/ or die;
124 if (@objs == 1) {
125 copy "$objs[0].KSPLICE_primary", "$obj.KSPLICE_primary";
126 copy "$objs[0].KSPLICE_helper", "$obj.KSPLICE_helper";
127 } else {
128 system("ld", "-r", "-o",
129 map { "$_.KSPLICE_primary" } ($obj, @objs));
130 system("ld", "-r", "-o",
131 map { "$_.KSPLICE_helper" } ($obj, @objs));
134 open OUT, '>', "$out.tmp";
135 print OUT "$outbits\n";
136 close OUT;
137 rename "$out.tmp", $out;
140 sub do_rmsyms {
141 my ($obj, @rmsyms) = @_;
142 load_system_map();
143 my ($bits) = split("\n", runsuc("objdiff", $obj, $obj));
144 die if ($bits ne '32' && $bits ne '64');
145 $word = ($bits == 64 ? "quad" : "long");
146 my $relocs = runsuc("objmanip", $obj, "rmsyms", @rmsyms);
147 parse_and_save(\&parse_relocs, $relocs, $obj, "ksplice_init_relocs", "");
150 sub do_system_map_lookup {
151 my ($sym) = @_;
152 load_system_map();
153 print ((find_sym_system_map($sym))[0]);
156 my %handlers = (
157 'snap' => \&do_snap,
158 'diff' => \&do_diff,
159 'combine' => \&do_combine,
160 'rmsyms' => \&do_rmsyms,
161 'system_map_lookup' => \&do_system_map_lookup,
164 my ($cmd, @args) = @ARGV;
165 if (exists $handlers{$cmd}) {
166 my $handler = $handlers{$cmd};
167 &$handler(@args);
168 } else {
169 print "Usage: ksplice.pl ", join('|', keys %handlers), " ...\n";
172 exit 0;
174 sub load_system_map {
175 open(SYMS, "<", "$ENV{KSPLICE_CONFIG_DIR}/System.map") or die;
176 my $line;
177 while(defined($line = <SYMS>)) {
178 my ($addr, $type, $sym, $mod) = split(/\s+/, $line);
179 next if($sym =~ /init_module/ ||
180 $sym =~ /cleanup_module/ ||
181 $sym =~ /this_module/);
183 $syms{$sym}{$addr} = 1;
185 close(SYMS);
188 sub find_sym_system_map {
189 my ($sym) = @_;
190 $sym =~ s/[.]text[.]//g;
191 $sym =~ s/[.]bss[.]//g;
192 $sym =~ s/[.]data[.]//g;
193 $sym =~ s/____.*//g;
194 if(defined $syms{$sym}) {
195 return keys(%{$syms{$sym}});
197 return ();
200 sub parse_and_save {
201 my ($funcref, $entries, $objfile, $suffix, @other) = @_;
202 my @entries = split(/\n/, $entries);
204 my @tosave;
205 foreach my $entry (@entries) {
206 print $entry, "\n" if($verbose);
207 &$funcref(\@tosave, $entry, @other);
209 save_using_asm(\@tosave, $objfile, $suffix);
212 sub save_using_asm {
213 my ($tosaveref, $objfile, $suffix) = @_;
215 my $asm_base = "$objfile.$suffix";
217 open(ASM, ">", "$asm_base.s");
218 print ASM ".section .${suffix}, \"a\"\n";
220 foreach my $entryref (@$tosaveref) {
221 my @entry = @{$entryref};
223 if($entry[0] eq "str") {
224 print ASM ".section .ksplice_str, \"a\"\n";
225 print ASM "0: .string \"", $entry[1], "\"\n";
226 print ASM ".section .${suffix}, \"a\"\n";
227 print ASM ".$word 0b\n";
229 elsif($entry[0] eq "array" && scalar(@entry) == 1) {
230 print ASM ".section .${suffix}, \"a\"\n";
231 print ASM ".$word 0x0\n";
233 elsif($entry[0] eq "array") {
234 print ASM ".section .ksplice_array, \"a\"\n";
235 print ASM "0:\n";
236 for(my $i = 1; $i < scalar(@entry); $i++) {
237 print ASM ".$word 0x", $entry[$i], "\n";
239 print ASM ".section .${suffix}, \"a\"\n";
240 print ASM ".$word 0b\n";
242 elsif($entry[0] eq "word") {
243 print ASM ".section .${suffix}, \"a\"\n";
244 print ASM ".$word 0x", $entry[1], "\n";
246 elsif($entry[0] eq "ptr") {
247 print ASM ".section .${suffix}, \"a\"\n";
248 print ASM ".$word ", $entry[1], "\n";
250 else { die; }
252 close(ASM);
254 runval("gcc", "-mcmodel=kernel", "-c", "$asm_base.s", "-o", "$asm_base.o");
255 runval("mv", $objfile, "$objfile.pre$suffix");
256 runval("ld", "-r", "-o", "$objfile", "$objfile.pre$suffix", "$asm_base.o");
259 sub parse_relocs {
260 my ($tosaveref, $entry, $globalizer) = @_;
261 my ($sym, $sect, $addr, $pcrel, $addend, $size) = split(/\s/, $entry);
263 my ($func) = ($sect =~ /(.*)____/);
264 $sym =~ s/([.]data[.]__func__[.])\d+/$1${func}/g;
266 my @symvals = find_sym_system_map($sym);
268 push @$tosaveref, (["str", $sym], ["str", $sect],
269 ["ptr", "${sect}${globalizer}"],
270 ["word", $addr],
271 ["word", scalar(@symvals)],
272 ["array", @symvals],
273 ["word", $pcrel],
274 ["word", $addend],
275 ["word", $size]);
278 sub parse_sizelist {
279 my ($tosaveref, $entry) = @_;
280 # grab the size and the symbol name from the end of the line
281 my ($size, $sym) = ($entry =~ /\s([a-z0-9]+)\s+(\S+)$/);
283 my @vals = find_sym_system_map($sym);
285 push @$tosaveref, (["str", $sym], ["word", $size],
286 ["ptr", "${sym}_global"], ["word", scalar(@vals)],
287 ["array", @vals]);
290 sub parse_patchlist {
291 my ($tosaveref, $entry) = @_;
292 my ($oldsym, $replsym) = split(/\s/, $entry);
294 push @$tosaveref, (["str", $oldsym], ["str", $replsym],
295 ["word", 0], ["ptr", "${replsym}_global"],
296 ["word", 0]);