HOOK_FUNCTION_STR = """probe kernel.function("{0}"){{
    if (execname() == "{1}"){{ printf("{2} %s -> {0} (%s)\\n", thread_indent(2), $$parms)
    }}
}}
probe kernel.function("{0}").return{{
    if (execname() == "{1}"){{
        printf("{2} %s <- {0} (%s)\\n", thread_indent(-2), $$return)
    }}
}}

"""

HOOK_SYSCALL_STR = """probe syscall.{0}{{
    if (execname() == "{1}"){{
        printf("{2} %s -> {0} (%s)\\n", thread_indent(2), $$parms)
    }}
}}
probe syscall.{0}.return{{
    if (execname() == "{1}"){{
        printf("{2} %s <- {0} (%s)\\n", thread_indent(-2), $$return)
    }}
}}

"""



class HookException(Exception):
    pass

class Probe(object):
    def __init__(self, name, target, line = -1):
        self._name = name 
        self._line = line 
        self._target = target

class SyscallProbe(Probe):
    def __init__(self, name, target, line = -1):
        Probe.__init__(self, name, target, line)
    
    def __str__(self):
        if self._line == -1:
            linestr = ''
        else:
            linestr = 'line {0}:'.format(str(self._line))
        return HOOK_SYSCALL_STR.format(self._name, self._target, linestr)

class FunctionProbe(Probe):
    def __init__(self, name, target, line = -1):
        Probe.__init__(self, name, target, line)
    
    def __str__(self):
        if self._line == -1:
            linestr = ''
        else:
            linestr = 'line {0}:'.format(str(self._line))
        return HOOK_FUNCTION_STR.format(self._name, self._target, linestr)

def parseone(content):
    content = content.split(',')
    if len(content) == 4:
        name = content[0].strip()
        type = content[1].strip()
        target = content[2].strip()
        line = content[3].strip()
    elif len(content) == 3:
        name = content[0].strip()
        type = content[1].strip()
        target = content[2].strip()
        line = -1
    else:
        raise HookException('Usage: [Name/SyscallName],[Type:function,syscall],[Target],[(LineNumber)]')
    
    if type == 'syscall':
        return SyscallProbe(name, target, line)
    elif type == 'function':
        return FunctionProbe(name, target, line)
    else:
        raise HookException('Type: function/syscall')

def parseconfig(path = './hook.config'):
    with open(path, encoding='utf-8') as f:
        content = f.read()
    contentlist = content.split('\n')
    while contentlist[-1] == '':
        contentlist = contentlist[:-1]
    res = ''
    for it in contentlist:
        if it.strip().startswith('#'):
            continue
        res += parseone(it).__str__()
    return res
    

if __name__ == '__main__':
    with open('mq_notify.c', 'w', encoding='utf-8') as f:
        f.write(parseconfig())
