aboutsummaryrefslogtreecommitdiffstats
path: root/dmcub/dmcub_isa.py
blob: 7d61bef044822b7ae7abf7e0c0b66757a56931d1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/env python3
"""Identify the DMCUB core ISA empirically: disassemble the code region under
every plausible capstone architecture and score linear-sweep coverage.

Scoring: sweep N bytes from a fixed offset, count bytes consumed by successfully
decoded instructions vs bytes skipped, and additionally require the decode to be
"self-consistent" (a wrong ISA typically decodes a low fraction and produces a
scatter of rare mnemonics).
"""
import collections
import sys

import capstone as cs

ARCHS = [
    ('riscv32', cs.CS_ARCH_RISCV, cs.CS_MODE_RISCV32),
    ('riscv32c', cs.CS_ARCH_RISCV, cs.CS_MODE_RISCV32 | cs.CS_MODE_RISCVC),
    ('riscv64', cs.CS_ARCH_RISCV, cs.CS_MODE_RISCV64),
    ('riscv64c', cs.CS_ARCH_RISCV, cs.CS_MODE_RISCV64 | cs.CS_MODE_RISCVC),
    ('arm', cs.CS_ARCH_ARM, cs.CS_MODE_ARM),
    ('thumb', cs.CS_ARCH_ARM, cs.CS_MODE_THUMB),
    ('arm64', cs.CS_ARCH_ARM64, cs.CS_MODE_ARM),
    ('mips32el', cs.CS_ARCH_MIPS, cs.CS_MODE_MIPS32 | cs.CS_MODE_LITTLE_ENDIAN),
    ('ppc32', cs.CS_ARCH_PPC, cs.CS_MODE_32),
    ('sparc', cs.CS_ARCH_SPARC, cs.CS_MODE_BIG_ENDIAN),
    ('x86-32', cs.CS_ARCH_X86, cs.CS_MODE_32),
]


def score(data, arch, mode, base=0):
    try:
        md = cs.Cs(arch, mode)
    except cs.CsError:
        return None
    md.skipdata = True
    covered = 0
    skipped = 0
    mnem = collections.Counter()
    for ins in md.disasm(data, base):
        if ins.mnemonic in ('.byte', '.db'):
            skipped += ins.size
        else:
            covered += ins.size
            mnem[ins.mnemonic] += 1
    total = covered + skipped
    return {
        'cover': covered / total if total else 0.0,
        'ninsn': sum(mnem.values()),
        'uniq': len(mnem),
        'top': mnem.most_common(8),
    }


def main():
    path = sys.argv[1]
    off = int(sys.argv[2], 0) if len(sys.argv) > 2 else 0x100
    n = int(sys.argv[3], 0) if len(sys.argv) > 3 else 0x4000
    data = open(path, 'rb').read()[off:off + n]
    print('%s @ 0x%x len 0x%x' % (path, off, len(data)))
    rows = []
    for name, arch, mode in ARCHS:
        r = score(data, arch, mode)
        if r:
            rows.append((r['cover'], name, r))
    for cover, name, r in sorted(rows, reverse=True):
        print('  %-9s cover=%5.1f%%  insns=%-6d uniq=%-4d %s' % (
            name, cover * 100, r['ninsn'], r['uniq'],
            ' '.join('%s:%d' % (m, c) for m, c in r['top'])))


if __name__ == '__main__':
    main()