From 0a6ba6a14e6252072ecd90a348b06bcffa521b88 Mon Sep 17 00:00:00 2001 From: Axel Tillequin Date: Sat, 9 May 2020 16:49:30 +0200 Subject: [PATCH] merging by hand LRGH pull request + minor typos --- amoco/arch/core.py | 2 +- amoco/arch/mips/r3000/asm.py | 18 ++-- amoco/arch/sparc/cpu_v8.py | 2 +- amoco/arch/sparc/formats.py | 152 +++++++++++++++++++--------------- amoco/arch/sparc/parsers.py | 87 ++++++++++++++++++- amoco/arch/x86/parsers.py | 3 +- amoco/cfg.py | 2 +- amoco/config.py | 2 +- amoco/system/core.py | 2 +- amoco/system/memory.py | 2 +- amoco/ui/render.py | 29 ++++++- tests/test_arch_sparc.py | 106 ++++++++++++++++++++++++ tests/test_arch_x64_mapper.py | 22 +++++ 13 files changed, 341 insertions(+), 88 deletions(-) create mode 100644 tests/test_arch_sparc.py create mode 100644 tests/test_arch_x64_mapper.py diff --git a/amoco/arch/core.py b/amoco/arch/core.py index c3dbe62..97ad3d0 100644 --- a/amoco/arch/core.py +++ b/amoco/arch/core.py @@ -630,7 +630,7 @@ class Formatter(object): def __init__(self, formats): self.formats = formats - self.default = ("{i.mnemonic} ", lambda i: ", ".join(map(str, i.operands))) + self.default = ("{i.mnemonic:<20}", lambda i: ", ".join(map(str, i.operands))) def getkey(self, i): if i.mnemonic in self.formats: diff --git a/amoco/arch/mips/r3000/asm.py b/amoco/arch/mips/r3000/asm.py index 89bd0a1..c1d3ce6 100644 --- a/amoco/arch/mips/r3000/asm.py +++ b/amoco/arch/mips/r3000/asm.py @@ -145,46 +145,46 @@ def i_BLTZAL(ins,fmap): @__npc def i_BREAK(ins,fmap): - ext("BREAK").call(fmap,ins.code) + ext("BREAK").call(fmap,code=ins.code) @__npc def i_CFC(ins, fmap): rt, rd = ins.operands if rt is not zero: - fmap[rt] = ext("CFC%d"%(ins.z),size=rt.size).call(fmap,rd) + fmap[rt] = ext("CFC%d"%(ins.z),size=rt.size).call(fmap,rd=rd) @__npc def i_MFC(ins, fmap): rt, rd = ins.operands if rt is not zero: - fmap[rt] = ext("MFC%d"%(ins.z),size=rt.size).call(fmap,rd) + fmap[rt] = ext("MFC%d"%(ins.z),size=rt.size).call(fmap,rd=rd) @__npc def i_COP(ins, fmap): fun = ins.cofun - ext("COP%d"%(ins.z)).call(fmap,fun) + ext("COP%d"%(ins.z)).call(fmap,cofun=fun) @__npc def i_CTC(ins, fmap): rt, rd = ins.operands - ext("CTC%d"%(ins.z)).call(fmap,rd,rt) + ext("CTC%d"%(ins.z)).call(fmap,rd=rd,rt=rt) @__npc def i_MTC(ins, fmap): rt, rd = ins.operands - ext("MTC%d"%(ins.z)).call(fmap,rd,rt) + ext("MTC%d"%(ins.z)).call(fmap,rd=rd,rt=rt) @__npc def i_LWC(ins, fmap): rt, base, offset = ins.operands data = mem(base+offset,32) - ext("LWC%d"%(ins.z)).call(fmap,rt,data) + ext("LWC%d"%(ins.z)).call(fmap,rt=rt,data=data) @__npc def i_SWC(ins, fmap): rt, base, offset = ins.operands addr = fmap(base+offset) - fmap[mem(data,32)] = ext("SWC%d"%(ins.z),size=32).call(fmap,rt) + fmap[mem(data,32)] = ext("SWC%d"%(ins.z),size=32).call(fmap,rt=rt) @__npc def i_DIV(ins, fmap): @@ -407,4 +407,4 @@ def i_SRLV(ins, fmap): @__npc def i_SYSCALL(ins, fmap): - ext("SYSCALL").call(fmap,ins.code) + ext("SYSCALL").call(fmap,code=ins.code) diff --git a/amoco/arch/sparc/cpu_v8.py b/amoco/arch/sparc/cpu_v8.py index 55e8243..1716153 100644 --- a/amoco/arch/sparc/cpu_v8.py +++ b/amoco/arch/sparc/cpu_v8.py @@ -14,7 +14,7 @@ from amoco.arch.sparc.formats import SPARC_V8_full from amoco.arch.sparc.formats import SPARC_V8_synthetic -instruction_sparc.set_formatter(SPARC_V8_full) +instruction_sparc.set_formatter(SPARC_V8_synthetic) # define disassembler: from amoco.arch.sparc import spec_v8 diff --git a/amoco/arch/sparc/formats.py b/amoco/arch/sparc/formats.py index 77ac41f..ef9a64a 100644 --- a/amoco/arch/sparc/formats.py +++ b/amoco/arch/sparc/formats.py @@ -3,7 +3,8 @@ from .env import * from .utils import * from amoco.arch.core import Formatter -from amoco.ui.render import Token, TokenListJoin +from amoco.ui.render import highlight, Token, TokenListJoin +from amoco.ui.render import replace_mnemonic_token, replace_opn_token whitespace = " " @@ -26,25 +27,25 @@ def address(a): def deref(a): - return ( + return [ [(Token.Memory, "[")] + address(a.base + a.disp) - + [(Token.Memory, "]%s" % a.seg)] - ) + + [(Token.Memory, "]%s" % (a.seg or ""))] + ] def mnemo_icc(i): s = i.mnemonic if i.misc["icc"]: s += "cc" - return [(Token.Mnemonic, s)] + return [(Token.Mnemonic, "{:<8}".format(s))] def mnemo_cond(i): s = CONDxB[i.mnemonic][i.cond] if i.misc["annul"]: s += ",a" - return [(Token.Mnemonic, s)] + return [(Token.Mnemonic, "{:<8}".format(s))] def reg_or_imm(x, t="%d"): @@ -97,9 +98,10 @@ def label(i): if i.operands[0]._is_reg: return [(Token.Register, "%" + str(i.operands[0].ref))] if i.operands[0]._is_cst: - return [(Token.Address, "%s" % i.misc["dst"])] - offset = i.operands[0].signextend(32) * 4 - return [(Token.Address, str(_pc + offset))] + offset = i.operands[0].signextend(32) * 4 + target = i.misc["dst"] or (_pc+offset) + return [(Token.Address, str(target))] + raise TypeError("operand type not supported") CONDB = { @@ -177,7 +179,7 @@ def label(i): CONDxB = {"b": CONDB, "fb": CONDFB, "cb": CONDCB} -mnemo = lambda i: [(Token.Mnemonic, "{i.mnemonic}".format(i=i))] +mnemo = lambda i: [(Token.Mnemonic, "{i.mnemonic:<8}".format(i=i))] format_mn = [mnemo] format_regs = [mnemo, lambda i: TokenListJoin(", ", regs(i))] format_ld = [mnemo, lambda i: TokenListJoin(", ", deref(i.operands[0]) + regn(i, 1))] @@ -205,7 +207,7 @@ def label(i): lambda i: address(i.operands[0]) + [(Token.Literal, ", ")] + regn(i, 1), ] format_addr = [mnemo, lambda i: address(i.operands[0])] -format_t = [lambda i: [(Token.Mnemonic, CONDT[i.cond])] + reg_or_imm(i.operands[0])] +format_t = [lambda i: [(Token.Mnemonic, "{:<8}".format(CONDT[i.cond]))] + reg_or_imm(i.operands[0])] format_rd = format_regs format_wr = [ mnemo, @@ -248,11 +250,11 @@ def label(i): def SPARC_V8_synthetic(null, i, toks=False): - s = SPARC_V8_full(i) - return SPARC_Synthetic_renaming(s, i) + s = SPARC_V8_full(i, True) + return SPARC_Synthetic_renaming(s, i, toks) -def SPARC_Synthetic_renaming(s, i): +def SPARC_Synthetic_renaming(s, i, toks=False): if i.mnemonic == "sethi" and i.operands[0] == cst(0, 22) and i.operands[1] == g0: return "nop" if ( @@ -260,75 +262,95 @@ def SPARC_Synthetic_renaming(s, i): and not i.misc["icc"] and i.operands[0] == i.operands[1] == g0 ): - return s.replace("or", "clr").replace("%g0, ", "") - if i.mnemonic == "or" and not i.misc["icc"] and i.operands[0] == g0: - return s.replace("or", "mov").replace("%g0, ", "") - if i.mnemonic == "or" and not i.misc["icc"] and i.operands[0] == i.operands[2]: - return s.replace("or", "bset").replace("%%%s," % i.operands[0], "", 1) - if i.mnemonic == "rd": + replace_mnemonic_token(s,"clr") + replace_opn_token(s,1,None) + replace_opn_token(s,0,None) + elif i.mnemonic == "or" and not i.misc["icc"] and i.operands[0] == g0: + replace_mnemonic_token(s,"mov") + replace_opn_token(s,0,None) + elif i.mnemonic == "or" and not i.misc["icc"] and i.operands[0] == i.operands[2]: + replace_mnemonic_token(s,"bset") + replace_opn_token(s,0,None) + elif i.mnemonic == "rd": op1 = str(i.operands[0]) if op1.startswith("asr") or op1 in ("y", "psr", "wim", "tbr"): - return s.replace("rd", "mov") - if i.mnemonic == "wr" and i.operands[0] == g0: - return s.replace("wr", "mov").replace("%g0,", "") - if i.mnemonic == "sub" and i.misc["icc"] and i.operands[2] == g0: - return s.replace("subcc", "cmp").replace(", %g0", "") - if i.mnemonic == "jmpl" and i.operands[1] == g0: + replace_mnemonic_token(s,"mov") + elif i.mnemonic == "wr" and i.operands[0] == g0: + replace_mnemonic_token(s,"mov") + replace_opn_token(s,0,None) + elif i.mnemonic == "sub" and i.misc["icc"] and i.operands[2] == g0: + replace_mnemonic_token(s,"cmp") + replace_opn_token(s,2,None) + elif i.mnemonic == "jmpl" and i.operands[1] == g0: if i.operands[0] == (i7 + cst(8)): - return "ret" - if i.operands[0] == (o7 + cst(8)): - return "retl" - return s.replace("jmpl", "jmp").replace(", %g0", "") - if i.mnemonic == "jmpl" and i.operands[1] == o7: - return s.replace("jmpl", "call").replace(", %o7", "") - if ( + s = [(Token.Mnemonic, "ret")] + elif i.operands[0] == (o7 + cst(8)): + s = [(Token.Mnemonic, "retl")] + else: + replace_mnemonic_token(s,"jmp") + replace_opn_token(s,1,None) + elif i.mnemonic == "jmpl" and i.operands[1] == o7: + replace_mnemonic_token(s,"call") + replace_opn_token(s,1,None) + elif ( i.mnemonic == "or" and i.misc["icc"] and i.operands[1]._is_reg and i.operands[0] == i.operands[2] == g0 ): - return s.replace("orcc", "tst").replace("%g0,", "").replace(", %g0", "") - if ( + replace_mnemonic_token(s,"tst") + replace_opn_token(s,2,None) + replace_opn_token(s,0,None) + elif ( i.mnemonic == "restore" and i.operands[0] == i.operands[1] == i.operands[2] == g0 ): - return "restore" + s = [(Token.Mnemonic, "restore")] if i.mnemonic == "save" and i.operands[0] == i.operands[1] == i.operands[2] == g0: - return "save" + s = [(Token.Mnemonic, "save")] if i.mnemonic == "xnor" and i.operands[1] == g0: - s = s.replace("xnor", "not").replace("%g0,", "", 1) + replace_mnemonic_token(s,"not") + replace_opn_token(s,1,None) if i.operands[0] == i.operands[2]: - return s.rpartition(",")[0] - return s - if i.mnemonic == "sub" and i.operands[0] == g0 and i.operands[1]._is_reg: - s = s.replace("sub", "neg").replace("%g0,", "", 1) + replace_opn_token(s,2,None) + elif i.mnemonic == "sub" and i.operands[0] == g0 and i.operands[1]._is_reg: + replace_mnemonic_token(s,"neg") + replace_opn_token(s,0,None) if i.operands[1] == i.operands[2]: - return s.rpartition(",")[0] - return s - if i.mnemonic == "add" and i.operands[0] == i.operands[2] and i.operands[1]._is_cst: + replace_opn_token(s,2,None) + elif i.mnemonic == "add" and i.operands[0] == i.operands[2] and i.operands[1]._is_cst: m = "inccc" if i.misc["icc"] else "inc" + replace_mnemonic_token(s,m) if i.operands[1] == 1: - return "{}{}%{}".format(m, whitespace, i.operands[0]) + replace_opn_token(s,2,None) + replace_opn_token(s,1,None) else: - return "{}{}{}, %{}".format(m, whitespace, i.operands[1], i.operands[0]) - if i.mnemonic == "sub" and i.operands[0] == i.operands[2] and i.operands[1]._is_cst: + replace_opn_token(s,0,None) + elif i.mnemonic == "sub" and i.operands[0] == i.operands[2] and i.operands[1]._is_cst: m = "deccc" if i.misc["icc"] else "dec" + replace_mnemonic_token(s,m) if i.operands[1] == 1: - return "{} %{}".format(m, i.operands[0]) + replace_opn_token(s,2,None) + replace_opn_token(s,1,None) else: - return "{}{}{}, %{}".format(m, whitespace, i.operands[1], i.operands[0]) - if i.mnemonic == "and" and i.misc["icc"] and i.operands[2] == g0: - s = s.replace("andcc", "btst").replace(", %g0", "") - m = s.split() - return "{}{}{}, {}".format(m[0], whitespace, m[2], m[1].replace(",", "")) - if i.mnemonic == "andn" and not i.misc["icc"] and i.operands[0] == i.operands[2]: - return s.replace("andn", "bclr").replace("%%%s," % i.operands[0], "", 1) - if i.mnemonic == "xor" and not i.misc["icc"] and i.operands[0] == i.operands[2]: - return s.replace("xor", "btog").replace("%%%s," % i.operands[0], "", 1) - if i.mnemonic == "stb" and i.operands[0] == g0: - return s.replace("stb", "clrb").replace("%g0, ", "") - if i.mnemonic == "sth" and i.operands[0] == g0: - return s.replace("sth", "clrh").replace("%g0, ", "") - if i.mnemonic == "st" and i.operands[0] == g0: - return s.replace("st", "clr").replace("%g0, ", "") - return s + replace_opn_token(s,0,None) + elif i.mnemonic == "and" and i.misc["icc"] and i.operands[2] == g0: + replace_mnemonic_token(s,"btst") + replace_opn_token(s,2,None) + s[1],s[3] = s[3],s[1] + elif i.mnemonic == "andn" and not i.misc["icc"] and i.operands[0] == i.operands[2]: + replace_mnemonic_token(s,"bclr") + replace_opn_token(s,0,None) + elif i.mnemonic == "xor" and not i.misc["icc"] and i.operands[0] == i.operands[2]: + replace_mnemonic_token(s,"btog") + replace_opn_token(s,0,None) + elif i.mnemonic == "stb" and i.operands[0] == g0: + replace_mnemonic_token(s,"clrb") + replace_opn_token(s,0,None) + elif i.mnemonic == "sth" and i.operands[0] == g0: + replace_mnemonic_token(s,"clrh") + replace_opn_token(s,0,None) + elif i.mnemonic == "st" and i.operands[0] == g0: + replace_mnemonic_token(s,"clr") + replace_opn_token(s,0,None) + return s if toks else highlight(s) diff --git a/amoco/arch/sparc/parsers.py b/amoco/arch/sparc/parsers.py index f3a3d41..6a77db5 100644 --- a/amoco/arch/sparc/parsers.py +++ b/amoco/arch/sparc/parsers.py @@ -112,11 +112,90 @@ def action_instr(toks): exp.setParseAction(action_exp) instr.setParseAction(action_instr) - +from amoco.cas.expressions import cst, op +from amoco.arch.sparc.spec_v8 import ISPECS +from amoco.arch.sparc.formats import CONDB, CONDT +spec_table = dict([(spec.iattr['mnemonic'], spec) for spec in ISPECS ]) +b_synonyms = {'b':'ba','bgeu':'bcc','blu':'bcs','bz':'be','bnz':'bne'} +t_synonyms = {'t':'ta','tgeu':'tcc','tlu':'tcs','tz':'te','tnz':'tne'} +b_cond = dict([(mn,cond) for cond,mn in CONDB.items()]) +t_cond = dict([(mn,cond) for cond,mn in CONDT.items()]) def asmhelper(i): - if i.mnemonic == "mov": - i.mnemonic = "or" - i.operands.insert(0, env.g0) + for idx, a in enumerate(i.operands): + if a._is_mem: + i.operands[idx] = a.a + # Add implicit arguments + if i.mnemonic in ['inc','dec'] and len(i.operands) == 1: + i.operands.insert(0,cst(1)) + # Expand reduced forms + if i.mnemonic=='bset': + i.mnemonic = 'or' + i.operands.insert(0,i.operands[1]) + elif i.mnemonic=='mov': + i.mnemonic = 'or' + i.operands.insert(0,env.g0) + elif i.mnemonic=='retl': + i.mnemonic = 'jmpl' + i.operands.insert(0,op('+',env.o7,cst(8))) + i.operands.insert(1,env.g0) + elif i.mnemonic=='jmp': + i.mnemonic = 'jmpl' + i.operands.insert(1,env.g0) + elif i.mnemonic=='clr' and i.operands[0]._is_reg: + i.mnemonic = 'or' + i.operands.insert(0,env.g0) + i.operands.insert(0,env.g0) + elif i.mnemonic=='clr': + i.mnemonic = 'st' + i.operands.insert(0,env.g0) + elif i.mnemonic=='inc': + i.mnemonic = 'add' + i.operands.insert(0,i.operands[1]) + elif i.mnemonic=='dec': + i.mnemonic = 'sub' + i.operands.insert(0,i.operands[1]) + elif i.mnemonic=='cmp': + i.mnemonic = 'subcc' + i.operands.insert(2,env.g0) + elif i.mnemonic=='btst': + i.mnemonic = 'andcc' + i.operands.insert(2,env.g0) + i.operands[0:2] = [ i.operands[1], i.operands[0] ] + elif i.mnemonic=='nop': + i.mnemonic = 'sethi' + i.operands = [ cst(0,22), env.g0 ] + elif i.mnemonic=='restore' and len(i.operands) == 0: + i.operands = [ env.g0, env.g0, env.g0 ] + # Branches and cc + if i.mnemonic.endswith('cc') and not i.mnemonic in ['taddcc' , 'tsubcc', 'mulscc']: + i.mnemonic = i.mnemonic[:-2] + i.misc['icc'] = True + if i.mnemonic.endswith(',a'): + i.misc['annul'] = True + i.mnemonic = i.mnemonic.rstrip(',a') + if i.mnemonic in b_synonyms: + i.mnemonic = b_synonyms[i.mnemonic] + if i.mnemonic in b_cond: + i.cond = b_cond[i.mnemonic] + i.mnemonic = 'b' + if i.mnemonic in t_synonyms: + i.mnemonic = t_synonyms[i.mnemonic] + if i.mnemonic in t_cond: + i.cond = t_cond[i.mnemonic] + i.mnemonic = 't' + if i.mnemonic=='call': + if len(i.operands)>1 and i.operands[1] != cst(0): + raise ValueError('call has a non-zero second argument') + i.operands = [ i.operands[0] ] + # Additional internal tweaks + if i.mnemonic=='sethi' and i.operands[0]._is_cst: + i.operands[0].size = 22 + elif i.mnemonic=='std': + i.rd = env.r.index(i.operands[0]) + elif i.mnemonic=='ldd': + i.rd = env.r.index(i.operands[1]) + i.spec = spec_table[i.mnemonic] + i.bytes = (0,0,0,0) # To have i.length == 4, for pc_npc emulation return i diff --git a/amoco/arch/x86/parsers.py b/amoco/arch/x86/parsers.py index c3675f7..c646747 100644 --- a/amoco/arch/x86/parsers.py +++ b/amoco/arch/x86/parsers.py @@ -50,7 +50,6 @@ def att_syntax_gen(env, CONDITION_CODES, cpu_addrsize, instruction): "data32", "addr32", "lock", - "wait", "rep", "repz", "repe", @@ -648,7 +647,7 @@ class intel_syntax: noprefix = False pfx = pp.oneOf( - ["data16", "addr16", "data32", "addr32", "lock", "wait", "rep", "repe", "repne"] + ["data16", "addr16", "data32", "addr32", "lock", "rep", "repe", "repne"] ) spfx = pp.oneOf(["dword", "word", "byte"], caseless=True) mpfx = spfx + pp.oneOf(["ptr"], caseless=True) diff --git a/amoco/cfg.py b/amoco/cfg.py index 80d1a1d..38b7fab 100644 --- a/amoco/cfg.py +++ b/amoco/cfg.py @@ -69,7 +69,7 @@ class node(Vertex): """ def __init__(self, acode): - Vertex.__init__(self, data=acode) + super().__init__(data=acode) pre = "blck_" if acode._is_block else "func_" self.name = "{}{}".format(pre, str(self.data.address)) self._map = None diff --git a/amoco/config.py b/amoco/config.py index a3e7250..6a1c8ad 100644 --- a/amoco/config.py +++ b/amoco/config.py @@ -295,7 +295,7 @@ def __str__(self): conf = Config() -from amoco.logger import Log as _LogClass +from amoco.logger import Log as _LogClass #lgtm [py/unsafe-cyclic-import] logger = _LogClass(__name__) logger.debug("loading module") diff --git a/amoco/system/core.py b/amoco/system/core.py index e1f14ed..3891f5d 100644 --- a/amoco/system/core.py +++ b/amoco/system/core.py @@ -198,8 +198,8 @@ def get_int64(self, loc): "get 64-bit int expression of current state(loc)" return self.getx(loc, size=64, sign=True) - "get 64-bit unsigned int expression of current state(loc)" def get_uint64(self, loc): + "get 64-bit unsigned int expression of current state(loc)" return self.getx(loc, size=64) def get_int32(self, loc): diff --git a/amoco/system/memory.py b/amoco/system/memory.py index 4dde4b5..a814e0a 100644 --- a/amoco/system/memory.py +++ b/amoco/system/memory.py @@ -291,7 +291,7 @@ def addtomap(self, z): j = self.locate(z.end) # h = [] if j is None: - assert i is None + assert i is None or i==0 self._map.insert(0, z) self.__update_cache() return diff --git a/amoco/ui/render.py b/amoco/ui/render.py index 887c33d..e5f5cc7 100644 --- a/amoco/ui/render.py +++ b/amoco/ui/render.py @@ -138,10 +138,15 @@ def highlight(toks, formatter=None, outfile=None): def TokenListJoin(j, lst): if isinstance(j, str): j = (Token.Literal, j) - res = lst[0:1] + res = lst[0] + if not isinstance(res,list): + res = [res] for x in lst[1:]: res.append(j) - res.append(x) + if isinstance(x,list): + res.extend(x) + else: + res.append(x) return res @@ -495,3 +500,23 @@ def op(self,symbol): icons.mop[".>>"] = "\u00B1\u226b" icons.mop["<<<"] = "\u22d8" icons.mop[">>>"] = "\u22d9" + +def replace_mnemonic_token(l,value): + for i in range(len(l)): + tn,tv = l[i] + if tn==Token.Mnemonic: + tv = value.ljust(len(tv)) + l[i] = (tn,tv) + +def replace_opn_token(l,n,value): + index = 1+(2*n) + if value is None: + if index+1 < len(l): + l.pop(index+1) + l.pop(index) + else: + tn,tv = l[index] + if isinstance(value,tuple): + l[index] = value + else: + l[index] = (tn, value) diff --git a/tests/test_arch_sparc.py b/tests/test_arch_sparc.py new file mode 100644 index 0000000..38a1f4b --- /dev/null +++ b/tests/test_arch_sparc.py @@ -0,0 +1,106 @@ +import pytest +import codecs +from amoco.arch.sparc import cpu_v8 as cpu +from amoco.arch.sparc.env import * +from amoco.arch.sparc.parsers import sparc_syntax + +# enforce synthetic syntax and NullFormatter output: +cpu.instruction_sparc.set_formatter(cpu.SPARC_V8_synthetic) +from amoco.ui import render +render.conf.UI.formatter = 'Null' + +def test_decoder_000(): + c = b'\x9d\xe3\xbf\x98' + i = cpu.disassemble(c) + assert i.mnemonic == 'save' + assert i.operands[0].ref == 'sp' + assert i.operands[1] == -104 + assert i.operands[2].ref == 'sp' + assert str(i) == 'save %sp, -104, %sp' + +def test_decoder_001(): + c = b'\xc0\x27\xbf\xfc' + i = cpu.disassemble(c) + assert i.mnemonic == 'st' + assert i.operands[0].ref == 'g0' + assert i.operands[1].size == 32 + assert i.operands[1].base.ref == 'fp' + assert i.operands[1].disp == -4 + assert str(i) == 'clr [%fp+-4]' + +def test_decoder_002(): + c = b'\xc2\x07\xbf\xfc' + i = cpu.disassemble(c) + assert i.mnemonic == 'ld' + assert i.operands[0].size == 32 + assert i.operands[0].base.ref == 'fp' + assert i.operands[0].disp == -4 + assert i.operands[1].ref == 'g1' + assert str(i) == 'ld [%fp+-4], %g1' + +def test_decoder_003(): + c = b'\x82\x00\x60\x42' + i = cpu.disassemble(c) + assert i.mnemonic == 'add' + assert i.operands[0].ref == 'g1' + assert i.operands[1] == 0x42 + assert i.operands[2].ref == 'g1' + assert str(i) == 'inc 66, %g1' + +def test_decoder_004(): + c = b'\xc2\x27\xbf\xfc' + i = cpu.disassemble(c) + assert i.mnemonic == 'st' + assert i.operands[0].ref == 'g1' + assert i.operands[1].size == 32 + assert i.operands[1].base.ref == 'fp' + assert i.operands[1].disp == -4 + assert str(i) == 'st %g1, [%fp+-4]' + +def test_decoder_005(): + c = b'\xb0\x10\x00\x01' + i = cpu.disassemble(c) + assert i.mnemonic == 'or' + assert i.operands[0].ref == 'g0' + assert i.operands[1].ref == 'g1' + assert i.operands[2].ref == 'i0' + assert str(i) == 'mov %g1, %i0' + +def test_decoder_006(): + c = b'\x81\xe8\x00\x00' + i = cpu.disassemble(c) + assert i.mnemonic == 'restore' + assert str(i) == 'restore' + +def test_decoder_007(): + c = b'\x81\xc3\xe0\x08' + i = cpu.disassemble(c) + assert i.mnemonic == 'jmpl' + assert str(i.operands[0]) == '(o7+0x8)' + assert i.operands[1].ref == 'g0' + assert str(i) == 'retl' + +def test_decoder_008(): + c = b'\x01\x00\x00\x00' + i = cpu.disassemble(c) + assert i.mnemonic == 'nop' + assert str(i) == 'nop ' + +def test_parser_001(): + s = "nop" + i = sparc_syntax.instr.parseString(s)[0] + assert i.mnemonic == 'sethi' + assert str(i) == 'nop' + +def test_parser_002(): + s = "inc 0x42, %g1" + i = sparc_syntax.instr.parseString(s)[0] + assert i.mnemonic == 'add' + assert str(i) == 'inc 66, %g1' + +def test_parser_002b(): + s = "add %g1, 66, %g1" + i = sparc_syntax.instr.parseString(s)[0] + print("- %r"%i) + assert i.mnemonic == 'add' + assert str(i) == 'inc 66, %g1' diff --git a/tests/test_arch_x64_mapper.py b/tests/test_arch_x64_mapper.py new file mode 100644 index 0000000..3aaa434 --- /dev/null +++ b/tests/test_arch_x64_mapper.py @@ -0,0 +1,22 @@ +import pytest +from amoco.cas.mapper import mapper +from amoco.arch.x64 import cpu_x64 as cpu +from amoco.arch.x64.env import * +from amoco.cas import expressions + + +def test_mapper_000(): + # create two instructions + # movq %rcx, (%rip) + # movq (%rip), %rcx + i0 = cpu.disassemble(b"\x48\x89\x0d\x00\x00\x00\x00") + i1 = cpu.disassemble(b"\x48\x8b\x0d\x00\x00\x00\x00") + # modify the first instruction to insert a label, e.g. because + # there is a relocation + # movq %rcx, foo(%rip) + i0.operands[0].a.disp = expressions.lab('foo', size=64) + # evaluate those two instructions + m=mapper() + i0(m) + i1(m) + assert str(m[rcx]) == 'M64(rip+14)'