#!/usr/bin/perl
use strict;
use warnings;
use File::Path qw(rmtree);

my $module = shift or die("Usage: $0 patch.ko");

$< and die("Error: must be root to use.");

my $tmpdir = ".patch_module";

eval {rmtree($tmpdir)};
mkdir($tmpdir);

open(SYMS, "<", "/proc/kallsyms")
  or die("Unable to open /proc/kallsyms: $!");

open(ASM, ">", "$tmpdir/kallsyms.s")
  or die("Unable to write to kallsyms.s: $!");

my $line;

while(defined($line = <SYMS>)) {
    my ($addr, $type, $sym) = split /\s+/, $line;
    if(lc $type eq 't') {
        print ASM ".globl $sym\n";
        print ASM ".set $sym,0x$addr\n";
    }
}

close(SYMS);
close(ASM);

system("gcc", "$tmpdir/kallsyms.s", "-c", "-o", "$tmpdir/kallsyms.o") == 0
  or die("gcc kallsysm.s failed: $!");

system("ld","-r","-m","elf_i386","-o","$tmpdir/patch.ko",$module,"-R","$tmpdir/kallsyms.o") == 0
 or die("ld of module failed: $!");

system("insmod", "$tmpdir/patch.ko") == 0
 or die("Unable to insmod patch.ko: $!");

END {
    my $tmpdir = ".patch_module";
    rmtree($tmpdir) if -w $tmpdir;
}

