Skip to content

Commit

Permalink
New MIPS architecture (#71)
Browse files Browse the repository at this point in the history
* Import MIPS support from angr branch (MIPS BE and LE, GDB request optimization)

* Adjust MIPS support and its definitions

Co-authored-by: Fedor Niskov <[email protected]>
  • Loading branch information
rawsample and FedorNiskov authored Feb 9, 2021
1 parent 477a7c2 commit 90547c1
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 19 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ script:

# Test avatar-qemu
- docker exec avatar2 bash -c 'cd avatar2/ && AVATAR2_GDB_EXECUTABLE=gdb-multiarch AVATAR2_ARCH=ARM AVATAR2_QEMU_EXECUTABLE=qemu-system-arm nosetests-3.4 ./tests/test_qemutarget.py'
- docker exec avatar2 bash -c 'cd avatar2/ && AVATAR2_GDB_EXECUTABLE=gdb-multiarch AVATAR2_ARCH=MIPS AVATAR2_QEMU_EXECUTABLE=qemu-system-arm nosetests-3.4 ./tests/test_qemutarget.py'
- docker exec avatar2 bash -c 'cd avatar2/ && AVATAR2_GDB_EXECUTABLE=gdb-multiarch AVATAR2_ARCH=MIPS AVATAR2_QEMU_EXECUTABLE=qemu-system-mips nosetests-3.4 ./tests/test_qemutarget.py'
- docker exec avatar2 bash -c 'cd avatar2/ && AVATAR2_GDB_EXECUTABLE=gdb-multiarch AVATAR2_QEMU_EXECUTABLE=qemu-system-arm nosetests-3.4 ./tests/pyperipheral/test_pyperipheral.py'

# Test panda
- docker exec avatar2 bash -c 'cd avatar2/ && AVATAR2_GDB_EXECUTABLE=gdb-multiarch AVATAR2_ARCH=ARM AVATAR2_QEMU_EXECUTABLE=panda-system-arm nosetests-3.4 ./tests/test_qemutarget.py'
- docker exec avatar2 bash -c 'cd avatar2/ && AVATAR2_GDB_EXECUTABLE=gdb-multiarch AVATAR2_ARCH=MIPS AVATAR2_QEMU_EXECUTABLE=panda-system-arm nosetests-3.4 ./tests/test_qemutarget.py'
- docker exec avatar2 bash -c 'cd avatar2/ && AVATAR2_GDB_EXECUTABLE=gdb-multiarch AVATAR2_ARCH=MIPS AVATAR2_QEMU_EXECUTABLE=panda-system-mips nosetests-3.4 ./tests/test_qemutarget.py'
- docker exec avatar2 bash -c 'cd avatar2/ && AVATAR2_GDB_EXECUTABLE=gdb-multiarch AVATAR2_QEMU_EXECUTABLE=panda-system-arm nosetests-3.4 ./tests/pyperipheral/test_pyperipheral.py'
- docker exec avatar2 bash -c 'cd avatar2/ && AVATAR2_GDB_EXECUTABLE=gdb-multiarch AVATAR2_QEMU_EXECUTABLE=panda-system-arm AVATAR2_PANDA_EXECUTABLE=panda-system-arm nosetests-3.4 ./tests/smoke/panda_thumb.py'

Expand Down
1 change: 1 addition & 0 deletions avatar2/archs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .x86 import *
from .arm import *
from .mips import *
from .architecture import *
85 changes: 85 additions & 0 deletions avatar2/archs/mips.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from capstone import *
from keystone.keystone_const import *
from unicorn import *
from unicorn.mips_const import *
from .architecture import Architecture
import avatar2

from avatar2.installer.config import QEMU, PANDA, OPENOCD, GDB_MULTI


class MIPS32(Architecture):

get_qemu_executable = Architecture.resolve(QEMU)
get_panda_executable = Architecture.resolve(PANDA)
get_gdb_executable = Architecture.resolve(GDB_MULTI)
get_oocd_executable = Architecture.resolve(OPENOCD)


registers = {
'zero': 0,
'at': 1,
'v0': 2, 'v1': 3,
'a0': 4, 'a1': 5, 'a2': 6, 'a3': 7,
't0': 8, 't1': 9, 't2': 10, 't3': 11, 't4': 12, 't5': 13, 't6': 14, 't7': 15,
's0': 16, 's1': 17, 's2': 18, 's3': 19, 's4': 20, 's5': 21, 's6': 22, 's7': 23,
't8': 24, 't9': 25,
'k0': 26, 'k1': 27,
'gp': 28, 'sp': 29, 'fp': 30, 'ra': 31, 'pc': 32,
}

unicorn_registers = {
'zero': UC_MIPS_REG_0, 'at': UC_MIPS_REG_1, 'v0': UC_MIPS_REG_2,
'v1': UC_MIPS_REG_3, 'a0': UC_MIPS_REG_4, 'a1': UC_MIPS_REG_5,
'a2': UC_MIPS_REG_6, 'a3': UC_MIPS_REG_7, 't0': UC_MIPS_REG_8,
't1': UC_MIPS_REG_9, 't2': UC_MIPS_REG_10, 't3': UC_MIPS_REG_11,
't4': UC_MIPS_REG_12, 't5': UC_MIPS_REG_13, 't6': UC_MIPS_REG_14,
't7': UC_MIPS_REG_15, 's0': UC_MIPS_REG_16, 's1': UC_MIPS_REG_17,
's2': UC_MIPS_REG_18, 's3': UC_MIPS_REG_19, 's4': UC_MIPS_REG_20,
's5': UC_MIPS_REG_21, 's6': UC_MIPS_REG_22, 's7': UC_MIPS_REG_23,
't8': UC_MIPS_REG_24, 't9': UC_MIPS_REG_25, 'k0': UC_MIPS_REG_26,
'k1': UC_MIPS_REG_27, 'gp': UC_MIPS_REG_28, 'sp': UC_MIPS_REG_29,
'fp': UC_MIPS_REG_30, 'ra': UC_MIPS_REG_31, 'pc': UC_MIPS_REG_PC
}

pc_name = 'pc'
sr_name = 'cpsr'

capstone_arch = CS_ARCH_MIPS
keystone_arch = KS_ARCH_MIPS

unicorn_arch = UC_ARCH_MIPS
unicorn_mode = UC_MODE_MIPS32


class MIPS_BE(MIPS32):

endian = 'big'

qemu_name = 'mips'
gdb_name = 'mips'
angr_name = 'mips'

capstone_mode = CS_MODE_BIG_ENDIAN + CS_MODE_MIPS32
keystone_mode = KS_MODE_BIG_ENDIAN + KS_MODE_MIPS32
unicorn_mode = UC_MODE_BIG_ENDIAN | UC_MODE_THUMB


class MIPS_LE(MIPS32):

endian = 'little'

qemu_name = 'mipsel'
gdb_name = 'mips'
angr_name = 'mipsel'

capstone_mode = CS_MODE_LITTLE_ENDIAN + CS_MODE_MIPS32
keystone_mode = KS_MODE_LITTLE_ENDIAN + KS_MODE_MIPS32
unicorn_mode = UC_MODE_LITTLE_ENDIAN | UC_MODE_THUMB



class MIPS_24KF(MIPS_BE):

cpu_model = '24Kf'

4 changes: 2 additions & 2 deletions avatar2/avatar2.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,8 +371,8 @@ def _handle_remote_memory_read_message(self, message):
(Address = 0x%x)" % message.address)

try:
mem = range.forwarded_to.read_memory(message.address, message.size)
if not isinstance(mem, int):
mem = range.forwarded_to.read_memory(message.address, message.size, message.num_words, message.raw)
if not message.raw and message.num_words == 1 and not isinstance(mem, int):
raise Exception(("Forwarded read returned data of type %s "
"(expected: int)" % type(mem)))
success = True
Expand Down
2 changes: 2 additions & 0 deletions avatar2/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ def __init__(self, origin, id, pc, address, size, dst=None):
self.address = address
self.size = size
self.dst = dst
self.num_words = 1
self.raw = False

class RemoteMemoryWriteMessage(AvatarMessage):
def __init__(self, origin, id, pc, address, value, size, dst=None):
Expand Down
9 changes: 9 additions & 0 deletions avatar2/protocols/gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,15 @@ def remote_connect(self, ip='127.0.0.1', port=3333):
if self._arch.gdb_name == 'arm':
self.set_abi('AAPCS')

if hasattr(self._arch, 'endian'):
req = ['-gdb-set', 'endian', self._arch.endian]
ret, resp = self._sync_request(req, GDB_PROT_DONE)
if not ret:
self.log.critical(
"Unable to set endianness, received response: %s" %
resp)
raise Exception("GDBProtocol was unable to set endianness")

req = ['-target-select', 'remote', '%s:%d' % (ip, int(port))]
ret, resp = self._sync_request(req, GDB_PROT_CONN)

Expand Down
107 changes: 92 additions & 15 deletions tests/test_qemutarget.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from avatar2 import QemuTarget
from avatar2 import MemoryRange
from avatar2 import Avatar
from avatar2.archs import ARM
from avatar2.archs import ARM, MIPS_24KF
from avatar2.targets import Target, TargetStates
from avatar2.message import *

Expand All @@ -17,9 +17,42 @@

qemu = None
fake_target = None



ARCH = None
rom_addr = None
test_dir = '/tmp/testava'


arm_bin = (b'\x1e\x10\xa0\xe3' # mov r1, #0x1e
b'\x00\x00\x20\xe0' # eor r0, r0, r0
b'\x01\x00\x80\xe2' # add r0, r0, #1
b'\x01\x00\x50\xe1' # cmp r0, r1
b'\xfc\xff\xff\x1a' # bne #8
b'\x00\x00\x00\xe0' # and r0, r0, r0
b'\x00\x00\x00\xe0') # and r0, r0, r0

mips_bin = (b'\x24\x09\x00\x1e' # addiu $t1, $zero, 0x1e
b'\x01\x08\x40\x26' # xor $t0, $t0, $t0
b'\x21\x08\x00\x01' # addi $t0, $t0, 1
b'\x15\x09\xff\xfe' # bne $t0, $t1, 8
b'\x00\x00\x00\x00' # nop
b'\x01\x08\x40\x24' # and $t0, $t0, $t0
b'\x01\x08\x40\x24') # and $t0, $t0, $t0

x86_bin = (b'\xbb\x1e\x00\x00\x00' # mov ebx, 0x1e
b'\x31\xc0' # xor eax, eax
b'\x83\xc0\x01' # add eax, 1
b'\x39\xd8' # cmp eax, ebx
b'\x75\xfc' # jne 0xa
b'\x21\xc0' # and eax, eax
b'\x21\xc0') # and eax, eax

x86_64_bin = (b'\x48\xc7\xc3\x1e\x00\x00\x00' # mov rbx, 0x1e
b'\x48\x31\xc0' # xor rax, rax
b'\x48\x83\xc0\x01' # add rax, 1
b'\x48\x39\xd8' # cmp rax, rbx
b'\x75\xfc' # jne 0xa
b'\x48\x21\xc0' # and rax, rax
b'\x48\x21\xc0') # and rax, rax



Expand All @@ -39,23 +72,54 @@ def write_memory(self, addr, size, val, *args, **kwargs):
self.fake_write_val = val
return True


def setup():
global qemu
global avatar
global fake_target
avatar = Avatar(output_directory='/tmp/testava')

arch = setup_ARCH()

avatar = Avatar(arch=arch, output_directory=test_dir)
qemu = QemuTarget(avatar, name='qemu_test',
firmware="./tests/binaries/qemu_arm_test",
#firmware="./tests/binaries/qemu_arm_test",
firmware='%s/firmware' % test_dir,
)
fake_target = FakeTarget()

dev1 = avatar.add_memory_range(0x101f2000, 0x1000, 'dev1', forwarded=True,
forwarded_to=fake_target,
qemu_name='avatar-rmemory')

mem1 = avatar.add_memory_range(0x8000000, 0x1000, 'mem1',
file='%s/tests/binaries/qemu_arm_test' %
os.getcwd())
mem1 = avatar.add_memory_range(rom_addr, 0x1000, 'mem1',
#file='%s/tests/binaries/qemu_arm_test' %
# os.getcwd())
file='%s/firmware' % test_dir)

def setup_ARCH():
global ARCH
global rom_addr

ARCH = os.getenv('AVATAR2_ARCH')

if ARCH == 'ARM':
arch = ARM
firmware = arm_bin
rom_addr = 0x08000000

elif ARCH == 'MIPS':
arch = MIPS_24KF
firmware = mips_bin
rom_addr = 0x1fc00000

else:
assert False, 'Invalid Achitecture'

if not os.path.exists(test_dir): os.makedirs(test_dir)
with open('%s/firmware' % test_dir, 'wb') as f:
f.write(firmware)

return arch

def teardown():
global qemu
Expand All @@ -74,23 +138,35 @@ def test_initilization():
@with_setup(setup, teardown)
def test_step():
global qemu
global ARCH

qemu.init()
qemu.wait()
qemu.regs.pc=0x08000000

qemu.regs.pc=rom_addr
qemu.step()
assert_equal(qemu.regs.pc, 0x08000004)
assert_equal(qemu.regs.pc, rom_addr + 4)


@with_setup(setup, teardown)
def test_memory_read():
global qemu
global ARCH

qemu.init()
qemu.wait()

mem = qemu.read_memory(0x08000000,4)
assert_equal(mem, 0xe3a0101e)
mem = qemu.read_memory(rom_addr,4)

if ARCH == 'ARM':
assert_equal(mem, 0xe3a0101e)

elif ARCH == 'MIPS':
#assert_equal(mem, 0x2409001e)
assert_equal(mem, 0x1e000924)

else:
assert False, "Architecture not supported"


@with_setup(setup, teardown)
Expand All @@ -99,8 +175,9 @@ def test_memory_write():

qemu.init()
qemu.wait()
qemu.write_memory(0x08000000,4, 0x41414141)
mem = qemu.read_memory(0x08000000,4)

qemu.write_memory(rom_addr,4, 0x41414141)
mem = qemu.read_memory(rom_addr,4)
assert_equal(mem, 0x41414141)


Expand Down

0 comments on commit 90547c1

Please sign in to comment.