#!/usr/bin/env python3
import json
import sys
from collections import defaultdict
from typing import Tuple, Dict, Any

def parse_line(line: str) -> Tuple[str, Dict[str, Any]]:
    """
    Parse a line of output from the pintool, returning the name of the
    executed action along with its parameters.
    """
    # Example line: strcmp; n=0 taint=34 cmp_val=65
    action, rest = line.split('; ')
    parameters = {}
    for kvpair in rest.split():
        key, val = kvpair.split('=')

        parameters[key] = val
    return (action, parameters)


def main():
    call_targets = defaultdict(list)
    ret_targets = defaultdict(list)

    # Handle the operations that are logged by the pintool.
    for line in sys.stdin.readlines():
        line = line.strip()

        if not ';' in line:
            continue

        action, parameters = parse_line(line)

        if action == 'icall':
            inst, target = parameters['inst_addr'], parameters['target_addr']
            if not target.startswith('40'):
                continue
            if target not in call_targets[inst]:
                call_targets[inst].append(target)
        elif action == 'unexpected_ret':
            call_addr, expected, real = parameters['call_addr'], parameters['expected_addr'], parameters['actual_addr']
            delta = int(real, 16) - int(expected, 16)
            if delta > 32:
                continue
            if (expected, real, delta) not in ret_targets[call_addr]:
                ret_targets[call_addr].append((expected, real, delta))

    with open('dyn_results.json', 'w') as f:
        json.dump({"call": call_targets, "ret": ret_targets}, f)

main()
