#!/usr/bin/env python
#
# splicer.py: splice the kernel symbol table into the kernel ELF
#  image. Replaces the data pointed to by the symbol symtable with a
#  representation of the symbol table (assuming enough space is
#  available).
#
# Dan R. K. Ports <drkp@mit.edu>
# Inspired by a (probably essentially identical) tool by Austin
# Clements.

import sys, os, string, struct

class Symbol:
    def __init__(self, name, addr):
        self.name = name
        self.addr = addr

def buildsymtab(symfile):
    symtab = []
    symtableloc = 0
    for line in symfile:
        (addr, type, symname) = line.split()
        if (type == "t" or type == "T"):
            sym = Symbol(symname, int(addr,16))
            symtab.append(sym)
        if symname == "symtable":
            # Find the address of the symtable so we'll know where to
            # splice into.
            symtableloc = int(addr,16)

    if symtableloc == 0:
        raise RuntimeException("Couldn't find symtable symbol")
    
    return (symtab, symtableloc)


def va2offset(kernfilename, va):
    readelf = os.popen("readelf -S %s" % kernfilename)
    sections = readelf.readlines()
    for line in sections:
        s = line.lstrip()
        if len(s) == 0:
            continue
        if s[0] != '[':
            continue
        fields = s.lstrip(" []").split()
        if fields[0] == "Nr]":
            continue
        (name, type, addr, off, size) = fields[1:6]
        if (va > int(addr,16) and va < (int(addr,16) + int(size,16))):
            print "va %08lx was found in section %s" % (va, name)
            return va - (int(addr,16)) + int(off,16)
    

def splice(kernfilename, symfilename):
    symfile = file(symfilename, "r")
    symtab, symtableloc = buildsymtab(symfile)
    print "Kernel symbol table location is %08lx" % symtableloc

    # Find the location of the symtable in the kernel
    symtableoff = va2offset(kernfilename, symtableloc)
    print "Kernel symtable offset is %08lx" % symtableoff
    kernfile = file(kernfilename, "r+")

    # Drop a big amorphous blob of strings into the kernel
    strloc = symtableloc + (len(symtab)+1)*struct.calcsize("<LL")
    kernfile.seek(symtableoff + (strloc - symtableloc))
    for sym in symtab:
        kernfile.write(sym.name)
        kernfile.write("\000")
        sym.strloc = strloc
        strloc += len(sym.name) + 1

    # Write in the sym_table_entrys, with pointers into the string blob 
    kernfile.seek(symtableoff)
    for sym in symtab:
        kernfile.write(struct.pack("<LL",
                                   sym.addr,
                                   sym.strloc))
    kernfile.write(struct.pack("<LL", 0, 0)) # terminator
    print "Spliced in %ld bytes of symbol table" % (strloc - symtableloc)


if __name__ == "__main__":
    splice(sys.argv[1], sys.argv[2])
