Example #1
0
def read_closure(settings, interps, heaps, pointer):
    try:
        if isinstance(pointer, Argument) or isinstance(pointer, CaseArgument) or isinstance(pointer, Offset) and isinstance(pointer.base, CasePointer):
            return

        if settings.opts.verbose:
            print("Found closure:")
            print("    Pointer:", show.show_pretty_pointer(settings, pointer))

        if isinstance(pointer, StaticValue) and show.name_is_library(show.get_name_for_address(settings, pointer.value)):
            if settings.opts.verbose:
                print("    Library defined!")
                print()
            return

        info_pointer = ptrutil.dereference(settings, pointer, heaps, []).untagged
        assert isinstance(info_pointer, StaticValue)
        info_address = info_pointer.value

        info_type = info.read_closure_type(settings, info_address)
        if info_type[:11] == 'constructor':
            num_ptrs = ptrutil.read_half_word(settings, settings.text_offset + info_address - settings.rt.halfword.size*4)
            num_non_ptrs = ptrutil.read_half_word(settings, settings.text_offset + info_address - settings.rt.halfword.size*3)

            args = []
            arg_pointer = ptrutil.make_tagged(settings, pointer)._replace(tag = 0)
            for i in range(num_ptrs + num_non_ptrs):
                arg_pointer = ptrutil.pointer_offset(settings, arg_pointer, settings.rt.word.size);
                args.append(ptrutil.dereference(settings, arg_pointer.untagged, heaps, []))

            arg_pattern = 'p' * num_ptrs + 'n' * num_non_ptrs

            interps[pointer] = Apply(func = Pointer(info_pointer), func_type = 'constructor', args = interp_args(args, arg_pattern), pattern = arg_pattern)
            if settings.opts.verbose:
                print()

            for arg in args[:num_ptrs]:
                read_closure(settings, interps, arg.untagged)

            return
        elif info_type[:8] == 'function':
            arg_pattern = info.read_arg_pattern(settings, info_address)
        else:
            arg_pattern = ''

        if settings.opts.verbose:
            print()

        interps[pointer] = Pointer(info_pointer)

        read_function_thunk(settings, interps, heaps, info_address, ptrutil.make_tagged(settings, pointer)._replace(tag = len(arg_pattern)), arg_pattern)
    except:
        e_type, e_obj, e_tb = sys.exc_info()
        print("Error when processing closure at", show.show_pretty_pointer(settings, pointer))
        print("    Error:", e_obj)
        print("    Error Location:", e_tb.tb_lineno)
        print("    No Disassembly Available")
        print()
Example #2
0
def read_case(settings, interps, heaps, pointer, stack, scrutinee):
    try:
        if settings.opts.verbose:
            print("Found case inspection!")

        info_name = show.get_name_for_address(settings, pointer.value)
        if settings.opts.verbose:
            print("    Name:", show.demangle(info_name))

        arms, tags, stacks, registers = gather_case_arms(settings, heaps, pointer.value, 1, settings.rt.word.size - 1, stack, {
            settings.rt.main_register: ptrutil.make_tagged(settings, Offset(base = CasePointer(inspection = pointer, matched_tag = DefaultTag()), index = 0)),
            settings.rt.stack_register: ptrutil.make_tagged(settings, Offset(base = StackPointer(), index = -len(stack)))
        }, stack, pointer, [])

        interp_arms = []
        for arm, tag, stack, regs in zip(arms, tags, stacks, registers):
            if settings.opts.verbose:
                print()
                print("Found case arm:")
                print("    From case:", info_name)
                print("    Pattern:", tag)
            interp_arms.append(read_code(settings, interps, heaps, arm, stack, regs))

        return Case(scrutinee = scrutinee, bound_ptr = pointer, arms = interp_arms, tags = tags)
    except:
        e_type, e_obj, e_tb = sys.exc_info()
        print("Error in processing case at", show.show_pretty_pointer(settings, pointer))
        print("    Error:", e_obj)
        print("    Error Location:", e_tb.tb_lineno)
        print("    Disassembly:")
        for insn in disasm.disasm_from(settings, pointer.value):
            print("        " + show.show_instruction(insn))
        print()
Example #3
0
def read_case(settings, worklist, heaps, pointer, stack, scrutinee):
    try:
        if settings.opts.verbose:
            print("Found case inspection!")

        info_name = show.get_name_for_address(settings, pointer.value)
        if settings.opts.verbose:
            print("    Name:", show.demangle(info_name))

        arms, tags, stacks, registers = gather_case_arms(settings, heaps, pointer.value, 1, settings.rt.word.size - 1, stack, {
            settings.rt.main_register: ptrutil.make_tagged(settings, Offset(base = CasePointer(inspection = pointer, matched_tag = DefaultTag()), index = 0)),
            settings.rt.stack_register: ptrutil.make_tagged(settings, Offset(base = StackPointer(), index = -len(stack)))
        }, stack, pointer, [])

        interp_arms = []
        for arm, tag, stack, regs in zip(arms, tags, stacks, registers):
            if settings.opts.verbose:
                print()
                print("Found case arm:")
                print("    From case:", info_name)
                print("    Pattern:", tag)
            interp_arms.append(read_code(settings, worklist, heaps, arm, stack, regs))

        return Case(scrutinee = scrutinee, bound_ptr = pointer, arms = interp_arms, tags = tags)
    except:
        e_type, e_obj, e_tb = sys.exc_info()
        print("Error in processing case at", show.show_pretty_pointer(settings, pointer))
        print("    Error:", e_obj)
        print("    Error Location:", e_tb.tb_lineno)
        print("    Disassembly:")
        for insn in disasm.disasm_from(settings, pointer.value):
            print("        " + show.show_instruction(insn))
        print()
        return UnknownInterpretation()
Example #4
0
def run_worklist(settings, interps, worklist):
    while len(worklist) > 0:
        work = worklist.pop()
        if isinstance(work, ClosureWork):
            if settings.opts.verbose:
                print("Found closure:")
                print("    Pointer:",
                      show.show_pretty_pointer(settings, work.pointer))

            if isinstance(work.pointer, Argument) or isinstance(
                    work.pointer, CaseArgument) or isinstance(
                        work.pointer, Offset) and isinstance(
                            work.pointer.base, CasePointer):
                if settings.opts.verbose:
                    print("    Simple closure!")
                    print()
                continue

            if isinstance(work.pointer, StaticValue) and show.name_is_library(
                    show.get_name_for_address(settings, work.pointer.value)):
                if settings.opts.verbose:
                    print("    Library defined!")
                    print()
                continue

            interps[work.pointer] = parse.read_closure(settings, worklist,
                                                       work.heaps,
                                                       work.pointer)
        elif isinstance(work, FunctionThunkWork):
            if settings.opts.verbose:
                print("Found function/thunk!")
                print(
                    "    Name:",
                    show.demangle(
                        show.get_name_for_address(settings, work.address)))
                print("    Arg pattern:", work.arg_pattern)

            if StaticValue(value=work.address) in interps:
                if settings.opts.verbose:
                    print("    Seen before!")
                    print()
                continue

            if show.name_is_library(
                    show.get_name_for_address(settings, work.address)):
                if settings.opts.verbose:
                    print("    Library defined!")
                    print()
                continue

            interps[StaticValue(
                value=work.address)] = parse.read_function_thunk(
                    settings, worklist, work.heaps, work.address,
                    work.main_register, work.arg_pattern)
        else:
            assert False, "bad work in worklist"

        if settings.opts.verbose:
            print()
Example #5
0
def run_worklist(settings, interps, worklist):
    while len(worklist) > 0:
        work = worklist.pop()
        if isinstance(work, ClosureWork):
            if settings.opts.verbose:
                print("Found closure:")
                print("    Pointer:", show.show_pretty_pointer(settings, work.pointer))

            if (
                isinstance(work.pointer, Argument)
                or isinstance(work.pointer, CaseArgument)
                or isinstance(work.pointer, Offset)
                and isinstance(work.pointer.base, CasePointer)
            ):
                if settings.opts.verbose:
                    print("    Simple closure!")
                    print()
                continue

            if isinstance(work.pointer, StaticValue) and show.name_is_library(
                show.get_name_for_address(settings, work.pointer.value)
            ):
                if settings.opts.verbose:
                    print("    Library defined!")
                    print()
                continue

            interps[work.pointer] = parse.read_closure(settings, worklist, work.heaps, work.pointer)
        elif isinstance(work, FunctionThunkWork):
            if settings.opts.verbose:
                print("Found function/thunk!")
                print("    Name:", show.demangle(show.get_name_for_address(settings, work.address)))
                print("    Arg pattern:", work.arg_pattern)

            if StaticValue(value=work.address) in interps:
                if settings.opts.verbose:
                    print("    Seen before!")
                    print()
                continue

            if show.name_is_library(show.get_name_for_address(settings, work.address)):
                if settings.opts.verbose:
                    print("    Library defined!")
                    print()
                continue

            interps[StaticValue(value=work.address)] = parse.read_function_thunk(
                settings, worklist, work.heaps, work.address, work.main_register, work.arg_pattern
            )
        else:
            assert False, "bad work in worklist"

        if settings.opts.verbose:
            print()
Example #6
0
def read_closure(settings, worklist, heaps, pointer):
    try:
        info_pointer = ptrutil.dereference(settings, pointer, heaps, []).untagged
        assert isinstance(info_pointer, StaticValue)
        info_address = info_pointer.value

        info_type = info.read_closure_type(settings, info_address)
        if settings.opts.verbose:
            print("    Type:", info_type)

        if info_type[:11] == 'constructor':
            num_ptrs = ptrutil.read_half_word(settings, settings.text_offset + info_address - settings.rt.halfword.size*4)
            num_non_ptrs = ptrutil.read_half_word(settings, settings.text_offset + info_address - settings.rt.halfword.size*3)

            args = []
            arg_pointer = ptrutil.make_tagged(settings, pointer)._replace(tag = 0)
            for i in range(num_ptrs + num_non_ptrs):
                arg_pointer = ptrutil.pointer_offset(settings, arg_pointer, settings.rt.word.size);
                args.append(ptrutil.dereference(settings, arg_pointer.untagged, heaps, []))

            arg_pattern = 'p' * num_ptrs + 'n' * num_non_ptrs

            for arg in args[:num_ptrs]:
                worklist.append(ClosureWork(heaps = heaps, pointer = arg.untagged))

            return Apply(func = Pointer(info_pointer), func_type = 'constructor', args = interp_args(args, arg_pattern), pattern = arg_pattern)
        elif info_type[:11] == 'indirection':
            tagged = ptrutil.make_tagged(settings, pointer)._replace(tag = 0)
            offset = ptrutil.pointer_offset(settings, tagged, settings.rt.word.size)
            new_ptr = ptrutil.dereference(settings, offset.untagged, heaps, [])

            if settings.opts.verbose:
                print()

            worklist.append(ClosureWork(heaps = heaps, pointer = new_ptr.untagged))
            return Pointer(new_ptr.untagged)
        elif info_type[:8] == 'function':
            arg_pattern = info.read_arg_pattern(settings, info_address)
        else:
            arg_pattern = ''

        worklist.append(FunctionThunkWork(heaps = heaps, address = info_address, main_register = ptrutil.make_tagged(settings, pointer)._replace(tag = len(arg_pattern)), arg_pattern = arg_pattern))
        return Pointer(info_pointer)

    except:
        e_type, e_obj, e_tb = sys.exc_info()
        print("Error when processing closure at", show.show_pretty_pointer(settings, pointer))
        print("    Error:", e_obj)
        print("    Error Location:", e_tb.tb_lineno)
        print("    No Disassembly Available")
        print()
        return UnknownInterpretation()
Example #7
0
def read_code(settings, interps, heaps, address, extra_stack, registers):
    try:
        instructions = disasm.disasm_from(settings, address)

        registers[settings.rt.heap_register] = ptrutil.make_tagged(settings, Offset(base = HeapPointer(id = len(heaps), owner = address), index = -1))
        registers[settings.rt.stack_register] = ptrutil.make_tagged(settings, Offset(base = StackPointer(), index = -len(extra_stack)))
        mach = machine.Machine(settings, heaps, extra_stack, registers)
        mach.simulate(instructions)

        registers = mach.registers
        stack = mach.stack[registers[settings.rt.stack_register].untagged.index+len(mach.stack):]

        new_heaps = heaps + [mach.heap]

        if settings.opts.verbose:
            print("    Heap:", list(map(lambda h: show.show_pretty_value(settings, h), mach.heap)))
            print("    Stack:", list(map(lambda s: show.show_pretty_value(settings, s), stack)))

        if instructions[-1].operands[0].type == capstone.x86.X86_OP_MEM and machine.base_register(instructions[-1].operands[0].mem.base) == settings.rt.stack_register:
            if settings.opts.verbose:
                print("    Interpretation: return", show.show_pretty_value(settings, registers[settings.rt.main_register]))
                print()

            returned = registers[settings.rt.main_register].untagged

            interpretation = Pointer(returned)
            read_closure(settings, interps, new_heaps, returned)
        else:
            worklist = []
            uses = []

            if instructions[-1].operands[0].type == capstone.x86.X86_OP_MEM:
                assert machine.base_register(instructions[-1].operands[0].mem.base) == settings.rt.main_register
                assert instructions[-1].operands[0].mem.disp == 0

                if settings.opts.verbose:
                    print("    Interpretation: evaluate", show.show_pretty_value(settings, registers[settings.rt.main_register]))

                evaled = registers[settings.rt.main_register].untagged

                stack_index = 0
                interpretation = Pointer(evaled)
                worklist.append({'type': 'closure', 'pointer': evaled})
            elif instructions[-1].operands[0].type == capstone.x86.X86_OP_IMM:
                jmp_address = instructions[-1].operands[0].imm
                if jmp_address in settings.address_to_name and settings.address_to_name[jmp_address][:7] == 'stg_ap_':
                    func = settings.address_to_name[jmp_address]
                    if func.split('_')[2] == '0':
                        arg_pattern = ''
                    else:
                        arg_pattern = func.split('_')[2]
                    called = registers[settings.rt.main_register].untagged
                    worklist.append({'type': 'closure', 'pointer': called})
                    func_type = 'closure'
                else:
                    arg_pattern = info.read_arg_pattern(settings, jmp_address)
                    called = StaticValue(value = jmp_address)
                    worklist.append({'type': 'function/thunk', 'address': jmp_address, 'main-register': registers[settings.rt.main_register], 'arg-pattern': arg_pattern})
                    func_type = 'info'

                num_args = sum(1 for e in filter(lambda pat: pat != 'v', arg_pattern))

                if settings.opts.verbose:
                    print("    Number of non-void args:", num_args)
                    print("    Called:", show.show_pretty_pointer(settings, called))
                    print("    Arg pattern:", arg_pattern)

                args = []
                stack_index = num_args
                for reg, i in zip(settings.rt.arg_registers, range(num_args)):
                    args.append(registers[reg])
                    stack_index -= 1
                args += stack[:stack_index]

                if settings.opts.verbose:
                    print("    Interpretation: call", show.show_pretty_pointer(settings, called), "on", list(map(lambda s: show.show_pretty_value(settings, s), args)))
                interpretation = Apply(func_type = func_type, func = Pointer(called), args = interp_args(args, arg_pattern), pattern = arg_pattern)

                for arg, pat in zip(args, arg_pattern):
                    if pat == 'p':
                        worklist.append({'type': 'closure', 'pointer': arg.untagged})

            while stack_index < len(stack):
                assert isinstance(stack[stack_index].untagged, StaticValue)
                cont_name = show.get_name_for_address(settings, stack[stack_index].untagged.value)
                if cont_name[:7] == 'stg_ap_':
                    assert cont_name[-5:] == '_info'
                    arg_pattern = cont_name.split('_')[2]
                    num_extra_args = sum(1 for e in filter(lambda pat: pat != 'v', arg_pattern))
                    if settings.opts.verbose:
                        print("                    then apply the result to", list(map(lambda s: show.show_pretty_value(settings, s), stack[stack_index+1:][:num_extra_args])))
                    interpretation = Apply(func_type = 'closure', func = interpretation, args = interp_args(stack[stack_index+1:][:num_extra_args], arg_pattern), pattern = arg_pattern)
                    for arg in stack[stack_index+1:][:num_extra_args]:
                        worklist.append({'type': 'closure', 'pointer': arg.untagged})
                    stack_index += 1 + num_extra_args
                elif cont_name == 'stg_upd_frame_info' or cont_name == 'stg_bh_upd_frame_info':
                    if settings.opts.verbose:
                        print("                    then update the thunk at", show.show_pretty_value(settings, stack[stack_index + 1]))
                    stack_index += 2
                else:
                    if settings.opts.verbose:
                        print("                    then inspect using", show.show_pretty_value(settings, stack[stack_index]))
                        print()
                    interpretation = read_case(settings, interps, new_heaps, stack[stack_index].untagged, stack[stack_index:], interpretation)
                    stack_index = len(stack)
            if settings.opts.verbose:
                print()

            for work in worklist:
                if work['type'] == 'closure':
                    read_closure(settings, interps, new_heaps, work['pointer'])
                elif work['type'] == 'function/thunk':
                    read_function_thunk(settings, interps, new_heaps, work['address'], work['main-register'], work['arg-pattern'])
                else:
                    assert False,"bad work in worklist"

        return interpretation
    except:
        e_type, e_obj, e_tb = sys.exc_info()
        print("Error in processing code at", show.show_pretty_address(settings, address))
        print("    Error:", e_obj)
        print("    Error Location:", e_tb.tb_lineno)
        print("    Disassembly:")
        for insn in disasm.disasm_from(settings, address):
            print("        " + show.show_instruction(insn))
        print()
Example #8
0
def read_code(settings, worklist, heaps, address, extra_stack, registers):
    try:
        instructions = list(disasm.disasm_from(settings, address))

        registers[settings.rt.heap_register] = ptrutil.make_tagged(
            settings,
            Offset(base=HeapPointer(id=len(heaps), owner=address), index=-1))
        registers[settings.rt.stack_register] = ptrutil.make_tagged(
            settings, Offset(base=StackPointer(), index=-len(extra_stack)))
        mach = machine.Machine(settings, heaps, extra_stack, registers)
        mach.simulate(instructions)

        registers = mach.registers
        stack = mach.stack[registers[settings.rt.stack_register].untagged.
                           index + len(mach.stack):]

        new_heaps = heaps + [mach.heap]

        if settings.opts.verbose:
            print(
                "    Heap:",
                list(
                    map(lambda h: show.show_pretty_value(settings, h),
                        mach.heap)))
            print(
                "    Stack:",
                list(map(lambda s: show.show_pretty_value(settings, s),
                         stack)))

        if instructions[-1].operands[
                0].type == capstone.x86.X86_OP_MEM and machine.base_register(
                    instructions[-1].operands[0].mem.base
                ) == settings.rt.stack_register:
            if settings.opts.verbose:
                print(
                    "    Interpretation: return",
                    show.show_pretty_value(
                        settings, registers[settings.rt.main_register]))

            returned = registers[settings.rt.main_register].untagged

            interpretation = Pointer(returned)
            worklist.append(ClosureWork(heaps=new_heaps, pointer=returned))
        else:
            uses = []

            if instructions[-1].operands[0].type == capstone.x86.X86_OP_MEM:
                assert machine.base_register(instructions[-1].operands[0].mem.
                                             base) == settings.rt.main_register
                assert instructions[-1].operands[0].mem.disp == 0

                if settings.opts.verbose:
                    print(
                        "    Interpretation: evaluate",
                        show.show_pretty_value(
                            settings, registers[settings.rt.main_register]))

                evaled = registers[settings.rt.main_register].untagged

                stack_index = 0
                interpretation = Pointer(evaled)
                worklist.append(ClosureWork(heaps=new_heaps, pointer=evaled))
            elif instructions[-1].operands[0].type == capstone.x86.X86_OP_IMM:
                jmp_address = instructions[-1].operands[0].imm
                if jmp_address in settings.address_to_name and settings.address_to_name[
                        jmp_address][:7] == 'stg_ap_':
                    func = settings.address_to_name[jmp_address]
                    if func.split('_')[2] == '0':
                        arg_pattern = ''
                    else:
                        arg_pattern = func.split('_')[2]
                    called = registers[settings.rt.main_register].untagged
                    worklist.append(
                        ClosureWork(heaps=new_heaps, pointer=called))
                    func_type = 'closure'
                else:
                    arg_pattern = info.read_arg_pattern(settings, jmp_address)
                    called = StaticValue(value=jmp_address)
                    worklist.append(
                        FunctionThunkWork(
                            heaps=new_heaps,
                            address=jmp_address,
                            main_register=registers[settings.rt.main_register],
                            arg_pattern=arg_pattern))
                    func_type = 'info'

                num_args = sum(
                    1 for e in filter(lambda pat: pat != 'v', arg_pattern))

                if settings.opts.verbose:
                    print("    Number of non-void args:", num_args)
                    print("    Called:",
                          show.show_pretty_pointer(settings, called))
                    print("    Arg pattern:", arg_pattern)

                args = []
                stack_index = num_args
                for reg, i in zip(settings.rt.arg_registers, range(num_args)):
                    args.append(registers[reg])
                    stack_index -= 1
                args += stack[:stack_index]

                if settings.opts.verbose:
                    print(
                        "    Interpretation: call",
                        show.show_pretty_pointer(settings, called), "on",
                        list(
                            map(lambda s: show.show_pretty_value(settings, s),
                                args)))
                interpretation = Apply(func_type=func_type,
                                       func=Pointer(called),
                                       args=interp_args(args, arg_pattern),
                                       pattern=arg_pattern)

                for arg, pat in zip(args, arg_pattern):
                    if pat == 'p':
                        worklist.append(
                            ClosureWork(heaps=new_heaps, pointer=arg.untagged))

            while stack_index < len(stack):
                assert isinstance(stack[stack_index].untagged, StaticValue)
                cont_name = show.get_name_for_address(
                    settings, stack[stack_index].untagged.value)
                if cont_name[:7] == 'stg_ap_':
                    assert cont_name[-5:] == '_info'
                    arg_pattern = cont_name.split('_')[2]
                    num_extra_args = sum(
                        1 for e in filter(lambda pat: pat != 'v', arg_pattern))
                    if settings.opts.verbose:
                        print(
                            "                    then apply the result to",
                            list(
                                map(
                                    lambda s: show.show_pretty_value(
                                        settings, s),
                                    stack[stack_index + 1:][:num_extra_args])))
                    interpretation = Apply(func_type='closure',
                                           func=interpretation,
                                           args=interp_args(
                                               stack[stack_index +
                                                     1:][:num_extra_args],
                                               arg_pattern),
                                           pattern=arg_pattern)
                    for arg in stack[stack_index + 1:][:num_extra_args]:
                        worklist.append(
                            ClosureWork(heaps=new_heaps, pointer=arg.untagged))
                    stack_index += 1 + num_extra_args
                elif cont_name == 'stg_upd_frame_info' or cont_name == 'stg_bh_upd_frame_info':
                    if settings.opts.verbose:
                        print(
                            "                    then update the thunk at",
                            show.show_pretty_value(settings,
                                                   stack[stack_index + 1]))
                    stack_index += 2
                else:
                    if settings.opts.verbose:
                        print(
                            "                    then inspect using",
                            show.show_pretty_value(settings,
                                                   stack[stack_index]))
                        print()
                    interpretation = read_case(settings, worklist, new_heaps,
                                               stack[stack_index].untagged,
                                               stack[stack_index:],
                                               interpretation)
                    stack_index = len(stack)
            if settings.opts.verbose:
                print()

        return interpretation
    except:
        e_type, e_obj, e_tb = sys.exc_info()
        print("Error in processing code at",
              show.show_pretty_address(settings, address))
        print("    Error:", e_obj)
        print("    Error Location:", e_tb.tb_lineno)
        print("    Disassembly:")
        for insn in disasm.disasm_from(settings, address):
            print("        " + show.show_instruction(insn))
        print()
        return UnknownInterpretation()
Example #9
0
def main():
    arg_parser = argparse.ArgumentParser(
        description='Decompile a GHC-compiled Haskell program.')
    arg_parser.add_argument('file')
    arg_parser.add_argument('entry', default='Main_main_closure', nargs='?')
    arg_parser.add_argument('--ignore-strictness',
                            action='store_true',
                            dest='ignore_strictness')
    arg_parser.add_argument('--apply-functions',
                            action='store_true',
                            dest='apply_functions')
    arg_parser.add_argument('--no-inline-once',
                            action='store_false',
                            dest='inline_once')
    arg_parser.add_argument('--inline-constructors',
                            action='store_true',
                            dest='inline_constructors')
    arg_parser.add_argument('--show-types',
                            action='store_true',
                            dest='show_types')
    arg_parser.add_argument('--no-abbreviate-library-names',
                            action='store_false',
                            dest='abbreviate_library_names')
    arg_parser.add_argument('--verbose', action='store_true', dest='verbose')

    opts = arg_parser.parse_args()
    settings = metadata.read_settings(opts)

    # Parse the binary
    entry_pointer = StaticValue(value=settings.name_to_address[opts.entry])

    interpretations = {}
    run_worklist(settings, interpretations,
                 [ClosureWork(heaps=[], pointer=entry_pointer)])

    # Analyze the inferred code for type information to make case statements clearer

    types = {}
    for ptr in interpretations:
        infer.infer_type_for(settings, interpretations, types, ptr)
    infer.run_rename_tags(settings, interpretations, types)

    # Clean things up for human consumption

    optimize.run_destroy_empty_apply(interpretations)
    if opts.ignore_strictness:
        optimize.run_destroy_strictness(interpretations)
    interpretations = optimize.run_delete_unused(interpretations,
                                                 entry_pointer)
    optimize.run_inline_cheap(interpretations)
    if opts.inline_once:
        optimize.run_inline_once(interpretations)
    if opts.inline_constructors:
        optimize.run_inline_constructors(interpretations)
    if opts.apply_functions:
        optimize.run_apply_functions(interpretations)

    # Display our parsed file

    function_worklist = [entry_pointer]
    seen = {}
    while len(function_worklist) > 0:
        worklist = [function_worklist.pop()]
        started = False

        while len(worklist) > 0:
            pointer = worklist.pop()
            if pointer in seen or not pointer in interpretations:
                continue
            else:
                if len(seen) > 0 and not started:
                    print()
                seen[pointer] = None
                started = True

            pretty = show.show_pretty_pointer(settings, pointer)
            lhs = pretty
            if settings.opts.show_types and pointer in types:
                sys.stdout.write(pretty)
                sys.stdout.write("::")
                sys.stdout.write(
                    show.show_pretty_type(settings, types[pointer], False))
                print("")
            sys.stdout.write(lhs)
            sys.stdout.write("=")
            sys.stdout.write(
                show.show_pretty_interpretation(settings,
                                                interpretations[pointer]))
            print("")

            optimize.foreach_use(
                interpretations[pointer], lambda ptr:
                (function_worklist if ptr in interpretations and isinstance(
                    interpretations[ptr], Lambda) else worklist).append(ptr))
Example #10
0
def main():
    arg_parser = argparse.ArgumentParser(description="Decompile a GHC-compiled Haskell program.")
    arg_parser.add_argument("file")
    arg_parser.add_argument("entry", default="Main_main_closure", nargs="?")
    arg_parser.add_argument("--ignore-strictness", action="store_true", dest="ignore_strictness")
    arg_parser.add_argument("--apply-functions", action="store_true", dest="apply_functions")
    arg_parser.add_argument("--no-inline-once", action="store_false", dest="inline_once")
    arg_parser.add_argument("--inline-constructors", action="store_true", dest="inline_constructors")
    arg_parser.add_argument("--show-types", action="store_true", dest="show_types")
    arg_parser.add_argument("--no-abbreviate-library-names", action="store_false", dest="abbreviate_library_names")
    arg_parser.add_argument("--verbose", action="store_true", dest="verbose")

    opts = arg_parser.parse_args()
    settings = metadata.read_settings(opts)

    # Parse the binary

    entry_pointer = StaticValue(value=settings.name_to_address[opts.entry])

    interpretations = {}
    run_worklist(settings, interpretations, [ClosureWork(heaps=[], pointer=entry_pointer)])

    # Analyze the inferred code for type information to make case statements clearer

    types = {}
    for ptr in interpretations:
        infer.infer_type_for(settings, interpretations, types, ptr)
    infer.run_rename_tags(settings, interpretations, types)

    # Clean things up for human consumption

    optimize.run_destroy_empty_apply(interpretations)
    if opts.ignore_strictness:
        optimize.run_destroy_strictness(interpretations)
    interpretations = optimize.run_delete_unused(interpretations, entry_pointer)
    optimize.run_inline_cheap(interpretations)
    if opts.inline_once:
        optimize.run_inline_once(interpretations)
    if opts.inline_constructors:
        optimize.run_inline_constructors(interpretations)
    if opts.apply_functions:
        optimize.run_apply_functions(interpretations)

    # Display our parsed file

    function_worklist = [entry_pointer]
    seen = {}
    while len(function_worklist) > 0:
        worklist = [function_worklist.pop()]
        started = False

        while len(worklist) > 0:
            pointer = worklist.pop()
            if pointer in seen or not pointer in interpretations:
                continue
            else:
                if len(seen) > 0 and not started:
                    print()
                seen[pointer] = None
                started = True

            pretty = show.show_pretty_pointer(settings, pointer)
            lhs = pretty
            if settings.opts.show_types and pointer in types:
                print(pretty, "::", show.show_pretty_type(settings, types[pointer], False))
            print(lhs, "=", show.show_pretty_interpretation(settings, interpretations[pointer]))

            optimize.foreach_use(
                interpretations[pointer],
                lambda ptr: (
                    function_worklist
                    if ptr in interpretations and isinstance(interpretations[ptr], Lambda)
                    else worklist
                ).append(ptr),
            )