* initial
* Clean, only store address in message if not symbolic
If it's symbolic,it renders like
Generating testcase No. 2 - Invalid symbolic memory access (mode:r) <<manticore.core.smtlib.expression.BitVecAnd object at 0x7fd6dcd14410>>
which is not useful output to the user.
* Format as hex
* Fix tests
* Rm comments
1700 lines
54 KiB
Python
1700 lines
54 KiB
Python
from cStringIO import StringIO
|
|
from manticore.core.smtlib import Solver, Operators
|
|
import unittest
|
|
import tempfile, os
|
|
import gc, pickle
|
|
import fcntl
|
|
import resource
|
|
from manticore.core.memory import *
|
|
|
|
def issymbolic(value):
|
|
return isinstance(value, Expression)
|
|
|
|
def isconcrete(value):
|
|
return not issymbolic(value)
|
|
|
|
|
|
class MemoryTest(unittest.TestCase):
|
|
_multiprocess_can_split_ = True
|
|
def get_open_fds(self):
|
|
fds = []
|
|
for fd in range(3, resource.RLIMIT_NOFILE):
|
|
try:
|
|
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
|
except IOError:
|
|
continue
|
|
fds.append(fd)
|
|
return fds
|
|
|
|
def setUp(self):
|
|
import sys
|
|
sys.setrecursionlimit(10000)
|
|
solver._stop_proc()
|
|
self.fds = self.get_open_fds()
|
|
def tearDown(self):
|
|
solver._stop_proc()
|
|
gc.collect()
|
|
gc.garbage = []
|
|
gc.collect()
|
|
self.assertEqual(self.fds, self.get_open_fds())
|
|
|
|
def test_ceil_floor_page_memory_page_12(self):
|
|
mem = Memory32()
|
|
#Basic check ceil
|
|
self.assertEqual(0x12346000, mem._ceil(0x12345678))
|
|
self.assertEqual(0x12346000, mem._ceil(0x12346000))
|
|
self.assertEqual(0x00000000, mem._ceil(0xffffffff))
|
|
#Basic check floor
|
|
self.assertEqual(0x12345000, mem._floor(0x12345678))
|
|
self.assertEqual(0x12345000, mem._floor(0x12345000))
|
|
self.assertEqual(0xfffff000, mem._floor(0xffffffff))
|
|
#Basic check page
|
|
self.assertEqual(0x12345, mem._page(0x12345678))
|
|
self.assertEqual(0x12345, mem._page(0x12345000))
|
|
self.assertEqual(0xfffff, mem._page(0xffffffff))
|
|
|
|
def test_ceil_floor_page_memory_page_13(self):
|
|
mem = SMemory32L(ConstraintSet())
|
|
self.assertEqual(0x00002000, mem._ceil(0x00002000))
|
|
self.assertEqual(0x00002000, mem._floor(0x00002000))
|
|
self.assertEqual(0x00000001, mem._page(0x00003FFF))
|
|
|
|
self.assertEqual(0xABC0E000, mem._ceil(0xABC0D590))
|
|
self.assertEqual(0xABC0C000, mem._floor(0xABC0D590))
|
|
self.assertEqual(0x55E06, mem._page(0xABC0D590))
|
|
|
|
def test_search_and_mmap_several_chunks_memory_page_12(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
#Check the search gives any value as the mem is free
|
|
self.assertEqual(mem._search(0x1000, 0x20000000), 0x20000000)
|
|
#Check the search still gives any value as the mem is still free
|
|
self.assertEqual(mem._search(0x1000, 0xf0000000), 0xf0000000)
|
|
|
|
#Check the default initial value
|
|
self.assertEqual(mem._search(0x1000, None), 0xf7fff000)
|
|
|
|
|
|
#alloc/map a byte at default address.
|
|
first = mem.mmap(None, 0x0001, 'r')
|
|
self.assertEqual(first, 0xf7fff000)
|
|
|
|
#Okay 2 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
#check valid
|
|
self.assertTrue(first in mem)
|
|
self.assertTrue(mem.access_ok((first), 'r'))
|
|
self.assertFalse(isinstance(mem[first], Expression))
|
|
self.assertTrue(first+0x1000-1 in mem)
|
|
self.assertTrue(mem.access_ok((first+0x1000-1), 'r'))
|
|
self.assertFalse(isinstance(mem[first+0x1000-1], Expression))
|
|
#bytes outside the map should be not valid
|
|
self.assertFalse(first-1 in mem)
|
|
self.assertFalse(first+0x1000 in mem)
|
|
|
|
|
|
#alloc/map another map. Should be consecutive to the lower address
|
|
second = mem.mmap(None, 0x1000, 'w')
|
|
#Okay 2 maps
|
|
self.assertEqual(len(mem.mappings()), 2)
|
|
#check valid
|
|
self.assertTrue(second in mem)
|
|
self.assertTrue(mem.access_ok((second), 'w'))
|
|
self.assertTrue(second+0x1000-1 in mem)
|
|
self.assertTrue(mem.access_ok((second+0x1000-1), 'w'))
|
|
#bytes outside the map should be not valid
|
|
self.assertFalse(second-1 in mem)
|
|
self.assertFalse(first+0x1000 in mem)
|
|
|
|
#alloc/map a byte
|
|
third = mem.mmap(None, 0x1000, 'x')
|
|
|
|
#Okay 3 maps
|
|
self.assertEqual(len(mem.mappings()), 3)
|
|
|
|
self.assertTrue(first in mem)
|
|
self.assertTrue(mem.access_ok((first), 'r'))
|
|
|
|
self.assertTrue(second in mem)
|
|
self.assertTrue(mem.access_ok((second), 'w'))
|
|
|
|
self.assertTrue(third in mem)
|
|
self.assertTrue(mem.access_ok((third), 'x'))
|
|
|
|
self.assertFalse(third-1 in mem)
|
|
self.assertFalse(first+0x1000 in mem)
|
|
|
|
self.assertFalse(mem.access_ok((second), 'x'))
|
|
mem.munmap(second,1)
|
|
self.assertFalse(second in mem)
|
|
self.assertEqual(len(mem.mappings()), 2)
|
|
|
|
#---------alloc in the free spaces now!----------------
|
|
forth = mem.mmap(second, 0x1000, 'x')
|
|
self.assertEqual(forth, mem._ceil(third+1))
|
|
self.assertTrue(forth in mem)
|
|
self.assertTrue(mem.access_ok((forth), 'x'))
|
|
|
|
def test_search_and_mmap_several_chunks_testing_limits_memory_page_12(self):
|
|
mem = Memory32()
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
#Check the search gives basically any value as the mem is free
|
|
self.assertEqual(mem._search(0x1000, 0x20000000), 0x20000000)
|
|
|
|
#alloc/map a byte
|
|
first = mem.mmap(0xFFFF000, 0x0001, 'r')
|
|
zero = mem.mmap(0x000, 0x0001, 'w')
|
|
|
|
#Okay 2 map
|
|
self.assertEqual(len(mem.mappings()), 2)
|
|
|
|
self.assertTrue(first in mem)
|
|
self.assertTrue(mem.access_ok((first), 'r'))
|
|
#self.assertFalse(mem.has_symbols(first))
|
|
|
|
self.assertTrue(zero in mem)
|
|
self.assertRaises(AssertionError, mem.mmap, 0x0000F000, 0, 'r')
|
|
|
|
self.assertEqual(zero, 0)
|
|
|
|
def test_try_to_allocate_greater_than_last_space_memory_page_12(self):
|
|
mem = Memory32()
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
#alloc/map a byte
|
|
for i in range(16):
|
|
mem.mmap( i<< 28, 0x1000, 'r')
|
|
self.assertEqual(len(mem.mappings()), 16)
|
|
self.assertRaises(MemoryException, mem.mmap, None, 0x10000000, 'r')
|
|
|
|
self.assertEqual(len(mem.mappings()), 16)
|
|
|
|
|
|
def test_access_symbolic_r(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
sym = cs.new_bitvec(32)
|
|
val = cs.new_bitvec(8)
|
|
|
|
cs.add(sym.uge(0xfff))
|
|
cs.add(sym.ule(0x1010))
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
self.assertRaises(MemoryException, mem.__getitem__, 0x1000)
|
|
self.assertRaises(MemoryException, mem.__getitem__, sym)
|
|
self.assertRaises(MemoryException, mem.__setitem__, 0x1000, '\x42')
|
|
self.assertRaises(MemoryException, mem.__setitem__, sym, '\x42')
|
|
|
|
|
|
#alloc/map a byte
|
|
first = mem.mmap(0x1000, 0x1000, 'r')
|
|
|
|
|
|
self.assertEqual(first, 0x1000)
|
|
self.assertEqual(mem[0x1000], '\x00')
|
|
self.assertRaises(MemoryException, mem.__getitem__, sym)
|
|
self.assertRaises(MemoryException, mem.__setitem__, 0x1000, '\x41')
|
|
self.assertRaises(MemoryException, mem.__setitem__, 0x1000, val)
|
|
self.assertRaises(MemoryException, mem.__setitem__, sym, '\x41')
|
|
self.assertRaises(MemoryException, mem.__setitem__, sym, val)
|
|
|
|
|
|
def test_access_symbolic_w(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
sym = cs.new_bitvec(32)
|
|
val = cs.new_bitvec(8)
|
|
|
|
cs.add(sym.uge(0xfff))
|
|
cs.add(sym.ule(0x1010))
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
self.assertRaises(MemoryException, mem.__getitem__, 0x1000)
|
|
self.assertRaises(MemoryException, mem.__getitem__, sym)
|
|
|
|
|
|
self.assertRaises(MemoryException, mem.__setitem__, 0x1000, '\x41')
|
|
self.assertRaises(MemoryException, mem.__setitem__, sym, '\x41')
|
|
|
|
#alloc/map a byte
|
|
first = mem.mmap(0x1000, 0x1000, 'w')
|
|
|
|
self.assertEqual(first, 0x1000)
|
|
self.assertRaises(MemoryException, mem.__getitem__, 0x1000)
|
|
self.assertRaises(MemoryException, mem.__getitem__, sym)
|
|
mem[0x1000] = '\x40'
|
|
mem[0x1000] = val
|
|
self.assertRaises(MemoryException, mem.__setitem__, sym, '\x41')
|
|
self.assertRaises(MemoryException, mem.__setitem__, sym, val)
|
|
|
|
cs.add( sym.uge(0x1000))
|
|
|
|
mem[sym] = '\x40'
|
|
mem[sym] = val
|
|
|
|
def test_access(self):
|
|
mem = Memory32()
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
#alloc/map a byte
|
|
first = mem.mmap(0x1000, 0x1000, 'r')
|
|
second = mem.mmap(0x2000, 0x1000, 'w')
|
|
third = mem.mmap(0x3000, 0x1000, 'x')
|
|
|
|
#Okay 3 maps
|
|
self.assertEqual(len(mem.mappings()), 3)
|
|
self.assertItemsEqual((first,second,third), (0x1000,0x2000,0x3000))
|
|
|
|
#not mapped implies no access
|
|
self.assertFalse(mem.access_ok(first-1, 'r'))
|
|
self.assertFalse(mem.access_ok(first-1, 'w'))
|
|
self.assertFalse(mem.access_ok(first-1, 'x'))
|
|
self.assertFalse(mem.access_ok(third+0x1000+1, 'r'))
|
|
self.assertFalse(mem.access_ok(third+0x1000+1, 'w'))
|
|
self.assertFalse(mem.access_ok(third+0x1000+1, 'x'))
|
|
|
|
#expected access
|
|
self.assertTrue(mem.access_ok(first, 'r'))
|
|
self.assertTrue(mem.access_ok(second, 'w'))
|
|
self.assertTrue(mem.access_ok(third, 'x'))
|
|
|
|
#unexpected access single
|
|
self.assertFalse(mem.access_ok(first, 'w'))
|
|
self.assertFalse(mem.access_ok(second, 'x'))
|
|
self.assertFalse(mem.access_ok(third, 'r'))
|
|
self.assertFalse(mem.access_ok(first, 'x'))
|
|
self.assertFalse(mem.access_ok(second, 'r'))
|
|
self.assertFalse(mem.access_ok(third, 'w'))
|
|
|
|
#unexpected access double
|
|
self.assertFalse(mem.access_ok(first, 'rw'))
|
|
self.assertFalse(mem.access_ok(second, 'wx'))
|
|
self.assertFalse(mem.access_ok(third, 'rx'))
|
|
self.assertFalse(mem.access_ok(first, 'wx'))
|
|
self.assertFalse(mem.access_ok(second, 'rx'))
|
|
self.assertFalse(mem.access_ok(third, 'rw'))
|
|
|
|
#unexpected access triple
|
|
self.assertFalse(mem.access_ok(first, 'rwx'))
|
|
self.assertFalse(mem.access_ok(second, 'rwx'))
|
|
self.assertFalse(mem.access_ok(third, 'rwx'))
|
|
|
|
#Map slices
|
|
self.assertTrue(mem.access_ok(slice(first,first+0x1000), 'r'))
|
|
self.assertFalse(mem.access_ok(slice(first,first+0x1000), 'w'))
|
|
self.assertFalse(mem.access_ok(slice(first,first+0x1000), 'x'))
|
|
self.assertFalse(mem.access_ok(slice(second,second+0x1000), 'r'))
|
|
self.assertTrue(mem.access_ok(slice(second,second+0x1000), 'w'))
|
|
self.assertFalse(mem.access_ok(slice(second,second+0x1000), 'x'))
|
|
self.assertFalse(mem.access_ok(slice(third,third+0x1000), 'r'))
|
|
self.assertFalse(mem.access_ok(slice(third,third+0x1000), 'w'))
|
|
self.assertTrue(mem.access_ok(slice(third,third+0x1000), 'x'))
|
|
|
|
#All 3 maps
|
|
self.assertFalse(mem.access_ok(slice(first,third+0x1000), 'r'))
|
|
self.assertFalse(mem.access_ok(slice(first,third+0x1000), 'w'))
|
|
self.assertFalse(mem.access_ok(slice(first,third+0x1000), 'x'))
|
|
|
|
|
|
self.assertFalse(mem.access_ok(slice(first-1,first+0x1000), 'r'))
|
|
self.assertFalse(mem.access_ok(slice(first,first+0x1001), 'r'))
|
|
self.assertFalse(mem.access_ok(slice(second-1,second+0x1000), 'r'))
|
|
self.assertFalse(mem.access_ok(slice(second,second+0x1001), 'r'))
|
|
self.assertFalse(mem.access_ok(slice(third-1,third+0x1000), 'r'))
|
|
self.assertFalse(mem.access_ok(slice(third,third+0x1001), 'r'))
|
|
|
|
|
|
|
|
def test_not_enough_memory_page_12(self):
|
|
mem = Memory32()
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
#alloc/map a chunk
|
|
first = mem.mmap((0x100000000/2), 0x1000, 'r')
|
|
|
|
#Okay 2 map
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
self.assertTrue(first in mem)
|
|
self.assertTrue(mem.access_ok((first), 'r'))
|
|
|
|
self.assertRaises(MemoryException, mem.mmap, 0, (0x100000000/2)+1, 'r')
|
|
|
|
def testBasicAnonMap(self):
|
|
m = AnonMap(0x10000000, 0x2000, 'rwx')
|
|
|
|
#Check the size
|
|
self.assertEqual(len(m), 0x2000)
|
|
|
|
|
|
#check the outside limits
|
|
self.assertRaises(IndexError, m.__setitem__, 0x10000000-1, 'A')
|
|
self.assertRaises(IndexError, m.__setitem__, 0x10002000, 'A')
|
|
self.assertRaises(IndexError, m.__getitem__, 0x10000000-1)
|
|
self.assertRaises(IndexError, m.__getitem__, 0x10002000)
|
|
|
|
|
|
#check it is initialized with zero
|
|
self.assertEqual(m[0x10000000], Operators.CHR(0))
|
|
self.assertEqual(m[0x10002000-1], Operators.CHR(0))
|
|
|
|
|
|
#check all characters go and come back the same...
|
|
#at the first byte of the mapping
|
|
addr = 0x10000000
|
|
for c in xrange(0, 0x100):
|
|
m[addr] = Operators.CHR(c)
|
|
self.assertEqual(m[addr], Operators.CHR(c))
|
|
|
|
#at the last byte of the mapping
|
|
addr = 0x10002000-1
|
|
for c in xrange(0, 0x100):
|
|
m[addr] = Operators.CHR(c)
|
|
self.assertEqual(m[addr], Operators.CHR(c))
|
|
|
|
|
|
def test_basic_get_char(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
addr = mem.mmap(None, 0x10, 'rw')
|
|
mem[addr] = 'a'
|
|
|
|
mem[addr+0x10:addr+0x20] = 'Y'*0x10
|
|
self.assertItemsEqual(mem[addr+0x10-1:addr+0x20+1], '\x00' + 'Y'*0x10 +'\x00')
|
|
|
|
|
|
def test_basic_put_char_get_char(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
#alloc/map a litlle mem
|
|
addr = mem.mmap(None, 0x10, 'r')
|
|
for c in xrange(0, 0x10):
|
|
self.assertRaises(MemoryException, mem.__setitem__, addr+c, 'a')
|
|
|
|
addr = mem.mmap(None, 0x10, 'x')
|
|
for c in xrange(0, 0x10):
|
|
self.assertRaises(MemoryException, mem.__setitem__, addr+c, 'a')
|
|
|
|
addr = mem.mmap(None, 0x10, 'w')
|
|
for c in xrange(0, 0x10):
|
|
mem[addr+c] = 'a'
|
|
|
|
for c in xrange(0, 0x10):
|
|
self.assertRaises(MemoryException, mem.__getitem__, addr+c)
|
|
|
|
addr = mem.mmap(None, 0x10, 'wx')
|
|
for c in xrange(0, 0x10):
|
|
mem[addr+c] = 'a'
|
|
for c in xrange(0, 0x10):
|
|
self.assertRaises(MemoryException, mem.__getitem__, addr+c)
|
|
|
|
addr = mem.mmap(None, 0x10, 'rw')
|
|
for c in xrange(0, 0x10):
|
|
mem[addr+c] = 'a'
|
|
for c in xrange(0, 0x10):
|
|
self.assertEquals(mem[addr+c], 'a')
|
|
|
|
def testBasicMappingsLimits(self):
|
|
mem = Memory32()
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
#Check the search gives basically any value as the mem is free
|
|
self.assertEqual(mem._search(0x1000, 0x20000000), 0x20000000)
|
|
|
|
#alloc/map a litlle mem
|
|
size = 0x1000
|
|
addr = mem.mmap(None, size, 'rwx')
|
|
|
|
#Okay 1 map
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#positive tests
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
|
|
for i in xrange(addr, addr+size):
|
|
self.assertTrue(i in mem)
|
|
|
|
#negative tests
|
|
self.assertFalse(0 in mem)
|
|
self.assertFalse(0xffffffff in mem)
|
|
self.assertFalse(-1 in mem)
|
|
self.assertFalse(0xfffffffffffffffffffffffffff in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+0x1000 in mem)
|
|
|
|
#check all characters go and come back the same...
|
|
for c in xrange(0, 0x100):
|
|
mem[addr+0x800] = Operators.CHR(c)
|
|
self.assertEqual(mem[addr+0x800], Operators.CHR(c))
|
|
|
|
def testBasicMappingsPermissions(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
#Chack the search gives basically any value as the mem is free
|
|
self.assertEqual(mem._search(0x1000, 0x20000000), 0x20000000)
|
|
|
|
#alloc/map a litlle mem
|
|
size = 0x1000
|
|
addr = mem.mmap(None, 0x1000, 'r')
|
|
|
|
#Okay 1 map
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#positive tests
|
|
self.assertTrue(addr in mem)
|
|
self.assertFalse(mem.access_ok(addr, 'w'))
|
|
self.assertFalse(mem.access_ok(addr, 'x'))
|
|
self.assertTrue(mem.access_ok(addr, 'r'))
|
|
self.assertFalse(isinstance(mem[addr], Expression))
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(mem.access_ok(addr+size-1, 'w'))
|
|
self.assertFalse(mem.access_ok(addr+size-1, 'x'))
|
|
self.assertTrue(mem.access_ok(addr+size-1, 'r'))
|
|
self.assertTrue(addr-1 not in mem)
|
|
|
|
|
|
#ad hoc sensible tests
|
|
self.assertFalse(0 in mem)
|
|
self.assertFalse(0xffffffff in mem)
|
|
self.assertFalse(-1 in mem)
|
|
self.assertFalse(0xfffffffffffffffffffffffffff in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(mem.access_ok(addr-1, 'w'))
|
|
self.assertFalse(mem.access_ok(addr-1, 'x'))
|
|
self.assertFalse(mem.access_ok(addr-1, 'r'))
|
|
self.assertFalse(addr+size in mem)
|
|
self.assertFalse(mem.access_ok((addr+size), 'w'))
|
|
self.assertFalse(mem.access_ok((addr+size), 'x'))
|
|
self.assertFalse(mem.access_ok((addr+size), 'r'))
|
|
|
|
|
|
def testBasicUnmapping(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x10000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(None, size, 'rwx')
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size in mem)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr, size)
|
|
|
|
#Okay 0 maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
#limits
|
|
self.assertFalse(addr in mem)
|
|
self.assertFalse(addr+size-1 in mem)
|
|
|
|
#re alloc mem should be at the same address
|
|
addr1 = mem.mmap(addr, size, 'rwx')
|
|
self.assertEqual(addr1, addr)
|
|
|
|
|
|
def testRoundingToPageUnmapping(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x10000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(None, size, 'rwx')
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size in mem)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr+0x1000+0x1234, 0x1234)
|
|
|
|
'''
|
|
00000000f7ff0000-00000000f7ff2000 rwx 00000000
|
|
00000000f7ff4000-00000000f8000000 rwx 00000000
|
|
'''
|
|
|
|
#Okay 2 maps
|
|
self.assertEqual(len(mem.mappings()), 2)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+0x1000 in mem)
|
|
self.assertTrue(addr+0x2000-1 in mem)
|
|
self.assertFalse(addr+0x2100 in mem)
|
|
self.assertFalse(addr+0x2001 in mem)
|
|
self.assertFalse(addr+0x2000 in mem)
|
|
self.assertFalse(addr+0x4000-1 in mem)
|
|
self.assertTrue(addr+0x4000 in mem)
|
|
self.assertEqual(str(mem), '00000000f7ff0000-00000000f7ff2000 rwx 00000000 \n00000000f7ff4000-00000000f8000000 rwx 00000000 ')
|
|
|
|
def testBasicUnmappingBegginning(self):
|
|
mem = Memory32()
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x10000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(None, size, 'rwx')
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size in mem)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr, size/2)
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertFalse(addr in mem)
|
|
self.assertFalse(addr+size/2-1 in mem)
|
|
self.assertTrue(addr+size/2 in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
|
|
#re alloc mem should be at the same address
|
|
addr1 = mem.mmap(addr, size/2, 'rwx')
|
|
self.assertEqual(addr1, addr)
|
|
|
|
def testBasicUnmappingEnd(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x10000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(None, size, 'rwx')
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size in mem)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr+size/2, size)
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size/2-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size/2 in mem)
|
|
self.assertFalse(addr+size-1 in mem)
|
|
|
|
def testBasicUnmappingMiddle(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x30000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(None, size, 'rwx')
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size in mem)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr+size/3, size/3)
|
|
|
|
#Okay 2 maps
|
|
self.assertEqual(len(mem.mappings()), 2)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size/3-1 in mem)
|
|
self.assertTrue(addr+2*size/3 in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size/3 in mem)
|
|
self.assertFalse(addr+2*size/3-1 in mem)
|
|
self.assertFalse(addr+size in mem)
|
|
|
|
addr1 = mem.mmap(None, size/3, 'rwx')
|
|
self.assertEqual(addr1, addr+size/3)
|
|
|
|
def testBasicUnmapping2(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
#Check the search gives basically any value as the mem is free
|
|
self.assertEqual(mem._search(0x1000, 0x20000000), 0x20000000)
|
|
|
|
size = 0x10000
|
|
#alloc/map a little mem
|
|
addr0 = mem.mmap(None, size, 'rwx')
|
|
#alloc/map another little mem
|
|
addr1 = mem.mmap(addr0+size, size, 'rw')
|
|
|
|
#They are consecutive
|
|
self.assertEqual(addr0+size, addr1)
|
|
|
|
#and 2 maps
|
|
self.assertEqual(len(mem.mappings()), 2)
|
|
|
|
#limits
|
|
self.assertTrue(addr0 in mem)
|
|
self.assertTrue(addr0+size-1 in mem)
|
|
self.assertTrue(addr0+1 in mem)
|
|
self.assertTrue(addr1-1 in mem)
|
|
self.assertTrue(addr1 in mem)
|
|
self.assertTrue(addr1+size-1 in mem)
|
|
self.assertFalse(addr0-1 in mem)
|
|
self.assertFalse(addr1+size in mem)
|
|
|
|
#Okay unmap a section touching both mappings
|
|
mem.munmap(addr0+size/2, size)
|
|
#Still 2 maps
|
|
self.assertEqual(len(mem.mappings()), 2)
|
|
|
|
#limits
|
|
self.assertTrue(addr0 in mem)
|
|
self.assertTrue(addr0 + size/2-1 in mem)
|
|
self.assertTrue(addr1 + size/2 in mem)
|
|
self.assertTrue(addr1 + size-1 in mem)
|
|
|
|
self.assertFalse(addr0-1 in mem)
|
|
self.assertFalse((addr0 + size/2) in mem)
|
|
|
|
self.assertFalse((addr1+size/2-1) in mem)
|
|
self.assertFalse(addr1+size in mem)
|
|
self.assertFalse(addr1 in mem)
|
|
|
|
|
|
#re alloc mem should be at the same address
|
|
addr_re = mem.mmap(addr0+size/2, size-0x1000, 'rwx')
|
|
self.assertEqual(addr_re, addr0+size/2)
|
|
|
|
#Now 3 maps
|
|
self.assertEqual(len(mem.mappings()), 3)
|
|
|
|
def testBasicUnmappingErr(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
size = 0x2000
|
|
#alloc/map a little mem
|
|
addr0 = mem.mmap(None, size, 'rwx')
|
|
#alloc/map another little mem
|
|
addr1 = mem.mmap(addr0+size, size, 'rwx')
|
|
#alloc/map another little mem
|
|
addr2 = mem.mmap(addr1+size, size, 'rwx')
|
|
|
|
#They are consecutive
|
|
self.assertEqual(addr0+size, addr1)
|
|
#They are consecutive
|
|
self.assertEqual(addr1+size, addr2)
|
|
|
|
#and 2 maps
|
|
self.assertEqual(len(mem.mappings()), 3)
|
|
|
|
#Okay unmap a section touching both mappings
|
|
mem.munmap(addr1, size)
|
|
|
|
#Still 2 maps
|
|
self.assertEqual(len(mem.mappings()), 2)
|
|
|
|
|
|
def testBasicUnmappingOverLowerLimit(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x10000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(0x10000, size, 'rwx')
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size in mem)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr-size/2, size)
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertTrue(addr+size/2 in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr in mem)
|
|
self.assertFalse(addr+size/2-1 in mem)
|
|
|
|
def testBasicUnmappingOverHigherLimit(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x10000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(0x10000, size, 'rwx')
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size in mem)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr+size/2, size)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size/2-1 in mem)
|
|
self.assertFalse(addr+size/2 in mem)
|
|
self.assertFalse(addr+size-1 in mem)
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
def testUnmappingAll(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x10000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(None, size, 'rwx')
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size in mem)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr, size/2)
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr+size/2, size/2)
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
def testBasicUnmappingOverBothLimits(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x30000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(0x10000, size, 'rwx')
|
|
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size in mem)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr+size - size/3, size/2)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr - (size/2 - size/3), size/2)
|
|
|
|
#limits
|
|
self.assertTrue((addr+size - size/3 - 1) in mem )
|
|
self.assertFalse((addr+size - size/3) in mem )
|
|
|
|
self.assertFalse((addr - (size/2 - size/3) + size/2 - 1) in mem )
|
|
self.assertTrue((addr - (size/2 - size/3) + size/2) in mem )
|
|
|
|
self.assertFalse(addr in mem)
|
|
self.assertFalse(addr+size-1 in mem)
|
|
#Okay 1 maps
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
def test_mmapFile(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('a'*0x1001)
|
|
rwx_file.close()
|
|
|
|
addr_a = mem.mmapFile(0, 0x1000, 'rwx', rwx_file.name)
|
|
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
self.assertEqual(mem[addr_a], 'a')
|
|
self.assertEqual(mem[addr_a+(0x1000/2)], 'a')
|
|
self.assertEqual(mem[addr_a+(0x1000-1)], 'a')
|
|
self.assertRaises(MemoryException, mem.__getitem__, addr_a+(0x1000))
|
|
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('b'*0x1001)
|
|
rwx_file.close()
|
|
|
|
addr_b = mem.mmapFile(0, 0x1000, 'rw', rwx_file.name)
|
|
|
|
self.assertEqual(len(mem.mappings()), 2)
|
|
|
|
self.assertEqual(mem[addr_b], 'b')
|
|
self.assertEqual(mem[addr_b+(0x1000/2)], 'b')
|
|
self.assertEqual(mem[addr_b+(0x1000-1)], 'b')
|
|
|
|
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('c'*0x1001)
|
|
rwx_file.close()
|
|
|
|
addr_c = mem.mmapFile(0, 0x1000, 'rx', rwx_file.name)
|
|
|
|
self.assertEqual(len(mem.mappings()), 3)
|
|
|
|
self.assertEqual(mem[addr_c], 'c')
|
|
self.assertEqual(mem[addr_c+(0x1000/2)], 'c')
|
|
self.assertEqual(mem[addr_c+(0x1000-1)], 'c')
|
|
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('d'*0x1001)
|
|
rwx_file.close()
|
|
|
|
addr_d = mem.mmapFile(0, 0x1000, 'r', rwx_file.name)
|
|
|
|
self.assertEqual(len(mem.mappings()), 4)
|
|
|
|
self.assertEqual(mem[addr_d], 'd')
|
|
self.assertEqual(mem[addr_d+(0x1000/2)], 'd')
|
|
self.assertEqual(mem[addr_d+(0x1000-1)], 'd')
|
|
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('e'*0x1001)
|
|
rwx_file.close()
|
|
|
|
addr_e = mem.mmapFile(0, 0x1000, 'w', rwx_file.name)
|
|
|
|
self.assertEqual(len(mem.mappings()), 5)
|
|
|
|
self.assertRaises(MemoryException, mem.__getitem__, addr_e)
|
|
self.assertRaises(MemoryException, mem.__getitem__, addr_e+(0x1000/2))
|
|
self.assertRaises(MemoryException, mem.__getitem__, addr_e+(0x1000-1))
|
|
|
|
def test_basic_mapping_with_mmapFile(self):
|
|
mem = SMemory32(ConstraintSet())
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('d'*0x1001)
|
|
rwx_file.close()
|
|
addr = mem.mmapFile(0, 0x1000, 'rwx', rwx_file.name)
|
|
|
|
#One mapping
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
for i in xrange(addr, addr+0x1000):
|
|
self.assertTrue(i in mem)
|
|
self.assertTrue(mem.access_ok((i), 'r'))
|
|
self.assertTrue(mem.access_ok((i), 'w'))
|
|
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(mem.access_ok((addr-1), 'r'))
|
|
self.assertFalse(mem.access_ok((addr-1), 'w'))
|
|
self.assertFalse(addr+0x1000 in mem)
|
|
self.assertFalse(mem.access_ok((addr+0x1000), 'r'))
|
|
self.assertFalse(mem.access_ok((addr+0x1000), 'w'))
|
|
|
|
|
|
self.assertFalse(mem.access_ok(slice(addr-1,addr+1), 'r'))
|
|
self.assertFalse(mem.access_ok(slice(addr-1,addr+1), 'w'))
|
|
self.assertTrue(mem.access_ok(slice(addr,addr+1), 'rw'))
|
|
|
|
|
|
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
r_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
r_file.file.write('b'*0x1000)
|
|
r_file.close()
|
|
mem.mmapFile(0, 0x1000, 'r', r_file.name)
|
|
|
|
|
|
#Two mapping
|
|
self.assertEqual(len(mem.mappings()), 2)
|
|
|
|
rw_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rw_file.file.write('abcd'* (0x1000/4))
|
|
rw_file.close()
|
|
addr = mem.mmapFile(None, 0x1000, 'rw', rw_file.name)
|
|
|
|
self.assertItemsEqual(mem[addr:addr+6], 'abcdab')
|
|
self.assertItemsEqual(mem[addr+1:addr+7], 'bcdabc')
|
|
self.assertItemsEqual(mem[addr+2:addr+8], 'cdabcd')
|
|
self.assertItemsEqual(mem[addr+3:addr+9], 'dabcda')
|
|
|
|
#Three mapping
|
|
self.assertEqual(len(mem.mappings()), 3)
|
|
|
|
size = 0x30000
|
|
w_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
w_file.file.write('abc'*(size/3))
|
|
w_file.close()
|
|
addr = mem.mmapFile(0x20000000, size, 'w', w_file.name)
|
|
|
|
#Four mapping
|
|
self.assertEqual(len(mem.mappings()), 4)
|
|
|
|
#Okay unmap
|
|
mem.munmap(addr+size/3, size/3)
|
|
|
|
#Okay 2 maps
|
|
self.assertEqual(len(mem.mappings()), 5)
|
|
|
|
#limits
|
|
self.assertTrue(addr in mem)
|
|
self.assertTrue(addr+size/3-1 in mem)
|
|
self.assertTrue(addr+2*size/3 in mem)
|
|
self.assertTrue(addr+size-1 in mem)
|
|
self.assertFalse(addr-1 in mem)
|
|
self.assertFalse(addr+size/3 in mem)
|
|
self.assertFalse(addr+2*size/3-1 in mem)
|
|
self.assertFalse(addr+size in mem)
|
|
|
|
#re alloc mem should be at the same address
|
|
addr1 = mem.mmap(addr, size, 'rwx')
|
|
self.assertTrue(addr1, addr)
|
|
|
|
#Delete the temporary file
|
|
os.unlink(rwx_file.name)
|
|
os.unlink(r_file.name)
|
|
os.unlink(w_file.name)
|
|
|
|
|
|
def test_mix_of_concrete_and_symbolic__push_pop_cleaning_store(self):
|
|
#global mainsolver
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
|
|
start_mapping_addr = mem.mmap(None, 0x1000, 'rwx')
|
|
|
|
concrete_addr = start_mapping_addr
|
|
symbolic_addr = start_mapping_addr+1
|
|
|
|
mem[concrete_addr] = 'C'
|
|
sym = cs.new_bitvec(8)
|
|
|
|
mem[symbolic_addr] = sym
|
|
cs.add(sym.uge(0xfe))
|
|
values = list(solver.get_all_values(cs, sym))
|
|
self.assertIn(0xfe, values)
|
|
self.assertIn(0xff, values)
|
|
self.assertNotIn(0x7f, values)
|
|
|
|
self.assertTrue(isinstance(mem[symbolic_addr], Expression))
|
|
|
|
values = list(solver.get_all_values(cs, mem[symbolic_addr]))
|
|
self.assertIn(0xfe, values)
|
|
self.assertIn(0xff, values)
|
|
self.assertNotIn(0x7f, values)
|
|
|
|
with cs as cs_temp:
|
|
cs_temp.add(sym==0xfe)
|
|
values = list(solver.get_all_values(cs_temp, sym))
|
|
self.assertIn(0xfe, values)
|
|
self.assertNotIn(0xff, values)
|
|
self.assertNotIn(0x7f, values)
|
|
values = list(solver.get_all_values(cs_temp, mem[symbolic_addr]))
|
|
self.assertIn(0xfe, values)
|
|
self.assertNotIn(0xff, values)
|
|
self.assertNotIn(0x7f, values)
|
|
|
|
|
|
values = list(solver.get_all_values(cs, sym))
|
|
self.assertIn(0xfe, values)
|
|
self.assertIn(0xff, values)
|
|
self.assertNotIn(0x7f, values)
|
|
values = list(solver.get_all_values(cs, mem[symbolic_addr]))
|
|
self.assertIn(0xfe, values)
|
|
self.assertIn(0xff, values)
|
|
self.assertNotIn(0x7f, values)
|
|
|
|
def test_mix_of_concrete_and_symbolic(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
|
|
start_mapping_addr = mem.mmap(None, 0x1000, 'rwx')
|
|
|
|
concretes = [0, 2, 4, 6]
|
|
symbolics = [1, 3, 5, 7]
|
|
|
|
for range in concretes:
|
|
mem[start_mapping_addr+range] = 'C'
|
|
|
|
for range in symbolics:
|
|
mem[start_mapping_addr+range] = cs.new_bitvec(8)
|
|
|
|
for range in concretes:
|
|
self.assertTrue(isconcrete(mem[start_mapping_addr+range]))
|
|
|
|
for range in concretes:
|
|
self.assertFalse(issymbolic(mem[start_mapping_addr+range]))
|
|
|
|
for range in symbolics:
|
|
self.assertTrue(issymbolic(mem[start_mapping_addr+range]))
|
|
|
|
for range in symbolics:
|
|
self.assertFalse(isconcrete(mem[start_mapping_addr+range]))
|
|
|
|
for range in symbolics:
|
|
mem[start_mapping_addr+range] = 'C'
|
|
|
|
for range in concretes:
|
|
mem[start_mapping_addr+range] = cs.new_bitvec(8)
|
|
|
|
for range in symbolics:
|
|
self.assertTrue(isconcrete(mem[start_mapping_addr+range]))
|
|
|
|
for range in symbolics:
|
|
self.assertFalse(issymbolic(mem[start_mapping_addr+range]))
|
|
|
|
for range in concretes:
|
|
self.assertTrue(issymbolic(mem[start_mapping_addr+range]))
|
|
|
|
for range in concretes:
|
|
self.assertFalse(isconcrete(mem[start_mapping_addr+range]))
|
|
|
|
def test_one_concrete_one_symbolic(self):
|
|
#global mainsolver
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
|
|
addr_for_symbol1 = mem.mmap(None, 0x1000, 'rwx')
|
|
mem[addr_for_symbol1] = 'A'
|
|
|
|
symbol1 = cs.new_bitvec(8)
|
|
|
|
cs.add(Operators.OR(symbol1==Operators.ORD('B'), symbol1==Operators.ORD('C')))
|
|
|
|
mem[addr_for_symbol1+1] = symbol1
|
|
|
|
values = list(solver.get_all_values(cs, symbol1))
|
|
self.assertIn(Operators.ORD('B'), values)
|
|
self.assertIn(Operators.ORD('C'), values)
|
|
|
|
symbol2 = cs.new_bitvec(32)
|
|
cs.add(symbol2>=addr_for_symbol1)
|
|
cs.add(symbol2<=addr_for_symbol1+1)
|
|
|
|
c = mem[symbol2]
|
|
self.assertTrue(issymbolic(c))
|
|
|
|
values = list(solver.get_all_values(cs, c))
|
|
|
|
self.assertIn(Operators.ORD('A'), values)
|
|
self.assertIn(Operators.ORD('B'), values)
|
|
self.assertIn(Operators.ORD('C'), values)
|
|
|
|
def testBasicSymbolic(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
|
|
#alloc/map a little mem
|
|
size = 0x10000
|
|
addr = mem.mmap(None, size, 'rwx')
|
|
#initialize first 10 bytes as [100, 101, 102, .. 109]
|
|
for i in xrange(10):
|
|
mem[addr+i] = Operators.CHR(100+i)
|
|
|
|
#initialize first 10 bytes as [100, 101, 102, .. 109]
|
|
for i in xrange(10):
|
|
self.assertEqual(mem[addr+i], Operators.CHR(100+i))
|
|
|
|
|
|
#make a free symbol of 32 bits
|
|
x = cs.new_bitvec(32)
|
|
#constraint it to range into [addr, addr+10)
|
|
cs.add(x>=addr)
|
|
cs.add(x<addr+10)
|
|
|
|
#Well.. x is symbolic
|
|
self.assertTrue(issymbolic(x))
|
|
#It shall be a solution
|
|
self.assertTrue(solver.check(cs))
|
|
#if we ask for a possible solution (an x that comply with the constraints)
|
|
sol = solver.get_value(cs, x)
|
|
#it should comply..
|
|
self.assertTrue(sol >= addr and sol<addr+10)
|
|
|
|
#min and max value should be addr and addr+9
|
|
m, M = solver.minmax(cs, x)
|
|
self.assertEqual(m, addr)
|
|
self.assertEqual(M, addr+9)
|
|
|
|
#If we ask for all possible solutions...
|
|
for val in solver.get_all_values(cs, x):
|
|
#any solution must comply..
|
|
self.assertTrue(sol >= addr and sol<addr+10)
|
|
|
|
#so now lets ask the memory for values pointed by addr
|
|
c = mem[x]
|
|
for val in solver.get_all_values(cs, c):
|
|
self.assertTrue(val>=100 and val<110)
|
|
|
|
#constraint the address a litle more
|
|
cs.add(x<=addr)
|
|
#It shall be a solution
|
|
self.assertTrue(solver.check(cs))
|
|
#if we ask for a possible solution
|
|
sol = solver.get_value(cs, x)
|
|
#it must be addr
|
|
self.assertTrue(sol == addr)
|
|
|
|
#lets ask the memory for the value under that address
|
|
c = mem[x]
|
|
sol = solver.get_value(cs, c)
|
|
self.assertTrue(Operators.ORD(sol)==100)
|
|
|
|
self.assertItemsEqual(mem[x:x+4], "defg")
|
|
self.assertItemsEqual(mem[addr:addr+4], "defg")
|
|
mem, x = pickle.loads(pickle.dumps((mem,x)))
|
|
self.assertItemsEqual(mem[x:x+4], "defg")
|
|
self.assertItemsEqual(mem[addr:addr+4], "defg")
|
|
|
|
|
|
def testMultiSymbolic(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
|
|
#alloc/map a little mem
|
|
size = 0x10000
|
|
addr = mem.mmap(None, size, 'rwx')
|
|
#initialize first 10 bytes as [100, 101, 102, .. 109]
|
|
for i in xrange(addr, addr+10):
|
|
mem[i] = Operators.CHR(100+i-addr)
|
|
|
|
#Make a char that ranges from 'A' to 'Z'
|
|
v = cs.new_bitvec(32)
|
|
cs.add(v>=Operators.ORD('A'))
|
|
cs.add(v<=Operators.ORD('Z'))
|
|
|
|
#assign it to the first 10 bytes
|
|
mem[addr+5] = Operators.CHR(v)
|
|
|
|
|
|
#mak a free symbol of 32 bits
|
|
x = cs.new_bitvec(32)
|
|
#constraint it to range into [addr, addr+10)
|
|
cs.add(x>=addr)
|
|
cs.add(x<addr+10)
|
|
|
|
#so now lets ask the memory for values pointed by addr
|
|
c = mem[x]
|
|
for val in solver.get_all_values(cs, c,1000):
|
|
self.assertTrue(val>=100 and val<110 or val >= Operators.ORD('A') and val <= Operators.ORD('Z'))
|
|
|
|
def testmprotectFailReading(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x10000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(None, size, 'rwx')
|
|
mem[addr] = 'a'
|
|
|
|
self.assertEqual(mem[addr], 'a')
|
|
|
|
mem.mprotect(addr, size, 'w')
|
|
with self.assertRaisesRegexp(InvalidMemoryAccess, 'Invalid memory access \(mode:.\) <{:x}>'.format(addr)):
|
|
_ = mem[addr]
|
|
|
|
|
|
|
|
def testmprotectFailSymbReading(self):
|
|
cs = ConstraintSet()
|
|
|
|
#In the beggining the solver was 'sat' ...
|
|
self.assertTrue(solver.check(cs))
|
|
|
|
|
|
mem = SMemory32(cs)
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x3000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(None, size, 'rwx')
|
|
|
|
#okay we should have 1 map
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#free middle page
|
|
mem.munmap(addr+0x1000 , 1)
|
|
|
|
#And now just 2
|
|
self.assertEqual(len(mem.mappings()), 2)
|
|
|
|
#lets write some chars at the beginning of each page
|
|
mem[addr] = 'a'
|
|
mem[addr+0x2000] = 'b'
|
|
|
|
#check it....
|
|
self.assertEqual(mem[addr], 'a')
|
|
self.assertEqual(mem[addr+0x2000], 'b')
|
|
|
|
#make a free symbol of 32 bits
|
|
x = cs.new_bitvec(32)
|
|
#constraint it to range into [addr, addr+10)
|
|
cs.add(x>=addr)
|
|
cs.add(x<=addr+0x2000)
|
|
|
|
#Well.. x is symbolic
|
|
self.assertTrue(issymbolic(x))
|
|
#It shall be a solution
|
|
self.assertTrue(solver.check(cs))
|
|
#if we ask for a possible solution (an x that comply with the constraints)
|
|
sol = solver.get_value(cs, x)
|
|
#it should comply..
|
|
self.assertTrue(sol >= addr and sol<=addr+0x2000)
|
|
#print map(hex,sorted(solver.get_all_values(cs, x, 0x100000))), map(hex,solver.minmax(cs, x)), mem[x]
|
|
|
|
#No Access Reading <4160741376>
|
|
# self.assertRaisesRegexp(MemoryException, r"No access reading.*", mem.__getitem__, x)
|
|
with self.assertRaisesRegexp(InvalidSymbolicMemoryAccess, 'Invalid symbolic memory access.*'.format(addr)):
|
|
_ = mem[x]
|
|
# mem[addr] = 'a'
|
|
|
|
def testmprotectFailWriting(self):
|
|
mem = Memory32()
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x10000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(None, size, 'wx')
|
|
mem[addr] = 'a'
|
|
mem.mprotect(addr, size, 'r')
|
|
with self.assertRaisesRegexp(InvalidMemoryAccess, 'Invalid memory access \(mode:w\) <{:x}>'.format(addr)):
|
|
mem[addr] = 'a'
|
|
|
|
def testmprotecNoReadthenOkRead(self):
|
|
mem = Memory32()
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
|
|
size = 0x10000
|
|
#alloc/map a little mem
|
|
addr = mem.mmap(None, size, 'wx')
|
|
mem[addr] = 'a'
|
|
|
|
with self.assertRaisesRegexp(InvalidMemoryAccess, 'Invalid memory access \(mode:r\) <{:x}>'.format(addr)):
|
|
_ = mem[addr]
|
|
|
|
mem.mprotect(addr, size, 'r')
|
|
self.assertEqual(mem[addr], 'a')
|
|
|
|
def test_COW(self):
|
|
m = AnonMap(0x10000000, 0x2000, 'rwx')
|
|
|
|
#Check the size
|
|
self.assertEqual(len(m), 0x2000)
|
|
|
|
#Set Some chars
|
|
m[0x10001000:0x10001002] = 'AB'
|
|
m[0x10002000-1] = 'Z'
|
|
|
|
#check it is initialized with zero
|
|
self.assertItemsEqual(m[0x10001000:0x10001002], 'AB')
|
|
self.assertEqual(m[0x10002000-1], 'Z')
|
|
self.assertItemsEqual(m[0x10001000:0x10002000], 'AB'+ 0xffd*'\x00' +'Z')
|
|
|
|
#Make COW
|
|
cow = COWMap(m, 0x1000)
|
|
|
|
#Check COW length
|
|
self.assertEqual(len(cow), 0x1000)
|
|
|
|
#check it is initialized with zero
|
|
self.assertItemsEqual(m[0x10001000:0x10001002], 'AB')
|
|
self.assertEqual(m[0x10002000-1], 'Z')
|
|
self.assertItemsEqual(m[0x10001000:0x10002000], 'AB'+ 0xffd*'\x00' +'Z')
|
|
self.assertItemsEqual(cow[0x10001000:0x10002000], 'AB'+ 0xffd*'\x00' +'Z')
|
|
|
|
#Set and check some chars
|
|
cow[0x10001000:0x10001002] = 'ab'
|
|
cow[0x10002000-1] = 'z'
|
|
self.assertItemsEqual(cow[0x10001000:0x10001002], 'ab')
|
|
self.assertEqual(cow[0x10002000-1], 'z')
|
|
self.assertItemsEqual(m[0x10001000:0x10001002], 'AB')
|
|
self.assertEqual(m[0x10002000-1], 'Z')
|
|
self.assertItemsEqual(cow[0x10001000:0x10002000], 'ab'+ 0xffd*'\x00' +'z')
|
|
|
|
|
|
#Set and check some chars
|
|
cow[0x10002000-1] = 'z'
|
|
self.assertEqual(cow[0x10001000], 'a')
|
|
self.assertEqual(cow[0x10002000-1], 'z')
|
|
self.assertEqual(m[0x10001000], 'A')
|
|
self.assertEqual(m[0x10002000-1], 'Z')
|
|
|
|
def test_pickle_mmap_anon(self):
|
|
m = AnonMap(0x10000000, 0x3000, 'rwx')
|
|
m[0x10001000] = 'A'
|
|
s = StringIO(pickle.dumps(m))
|
|
m = pickle.load(s)
|
|
self.assertEqual(m[0x10001000], 'A')
|
|
|
|
|
|
def test_pickle_mmap_file(self):
|
|
#file mapping
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('X'*0x3000)
|
|
rwx_file.close()
|
|
m = FileMap(0x10000000, 0x3000, 'rwx', rwx_file.name)
|
|
m[0x10000000] = 'Y'
|
|
s = StringIO(pickle.dumps(m))
|
|
m = pickle.load(s)
|
|
self.assertEqual(m[0x10001000], 'X')
|
|
self.assertEqual(m[0x10000000], 'Y')
|
|
|
|
def test_pickle_mmap_anon_cow(self):
|
|
m = AnonMap(0x10000000, 0x3000, 'rwx', 'X'*0x1000+'Y'*0x1000+'Z'*0x1000)
|
|
m = COWMap(m)
|
|
s = StringIO(pickle.dumps(m))
|
|
m = pickle.load(s)
|
|
self.assertEqual(m[0x10001000], 'Y')
|
|
self.assertEqual(m.start, 0x10000000)
|
|
self.assertEqual(m.end, 0x10003000)
|
|
|
|
def test_pickle_mmap_anon_cow_offset(self):
|
|
m = AnonMap(0x10000000, 0x3000, 'rwx', 'X'*0x1000+'Y'*0x1000+'Z'*0x1000)
|
|
m = COWMap(m, offset=0x1000, size=0x1000)
|
|
s = StringIO(pickle.dumps(m))
|
|
m = pickle.load(s)
|
|
self.assertEqual(m[0x10001000], 'Y')
|
|
self.assertEqual(m.start, 0x10001000)
|
|
self.assertEqual(m.end, 0x10002000)
|
|
|
|
|
|
def test_pickle_mmap_file_cow(self):
|
|
#file mapping
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('X'*0x1000+'Y'*0x1000+'Z'*0x1000)
|
|
rwx_file.close()
|
|
m = FileMap(0x10000000, 0x3000, 'rwx', rwx_file.name)
|
|
m = COWMap(m)
|
|
s = StringIO(pickle.dumps(m))
|
|
m = pickle.load(s)
|
|
self.assertEqual(m[0x10001000], 'Y')
|
|
self.assertEqual(m.start, 0x10000000)
|
|
self.assertEqual(m.end, 0x10003000)
|
|
|
|
def test_pickle_mmap_file_cow_offset(self):
|
|
#file mapping
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('X'*0x1000+'Y'*0x1000+'Z'*0x1000)
|
|
rwx_file.close()
|
|
m = FileMap(0x10000000, 0x3000, 'rwx', rwx_file.name)
|
|
m = COWMap(m, size=0x1000, offset=0x1000)
|
|
s = StringIO(pickle.dumps(m))
|
|
m = pickle.load(s)
|
|
self.assertEqual(m[0x10001000], 'Y')
|
|
self.assertEqual(m.start, 0x10001000)
|
|
self.assertEqual(m.end, 0x10002000)
|
|
|
|
|
|
def test_pickle(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
|
|
#start with no maps
|
|
self.assertEqual(len(mem.mappings()), 0)
|
|
#alloc/map a byte
|
|
addr_a = mem.mmap(None, 0x1000, 'r')
|
|
|
|
#one map
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
#file mapping
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('a'*0x3000)
|
|
rwx_file.close()
|
|
addr_f = mem.mmapFile(0, 0x3000, 'rwx', rwx_file.name)
|
|
mem.munmap(addr_f+0x1000, 0x1000)
|
|
#two map2
|
|
self.assertEqual(len(mem.mappings()), 3)
|
|
|
|
sym = cs.new_bitvec(8)
|
|
mem[addr_f] = sym
|
|
|
|
#save it
|
|
|
|
s = StringIO(pickle.dumps(mem))
|
|
|
|
#load it
|
|
mem1 = pickle.load(s)
|
|
|
|
#two maps
|
|
self.assertEqual(len(mem1.mappings()), 3)
|
|
|
|
os.unlink(rwx_file.name)
|
|
|
|
def testMultiSymbolicWrites(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory64(cs)
|
|
mem.mmap(0x10000, 0x1000, 'rwx')
|
|
self.assertEqual(len(mem.mappings()), 1)
|
|
|
|
addr = cs.new_bitvec(64)
|
|
cs.add(addr == 0x10000)
|
|
value = cs.new_bitvec(8)
|
|
cs.add(value == 0x41)
|
|
mem[addr] = value
|
|
|
|
self.assertEqual(solver.get_all_values(cs, mem[addr]), [0x41])
|
|
|
|
addr1 = cs.new_bitvec(64)
|
|
cs.add(Operators.OR(addr1 == 0x10000, addr1 == 0x10001))
|
|
value1 = cs.new_bitvec(8)
|
|
cs.add(value1 == 0x42)
|
|
mem[addr1] = value1
|
|
|
|
self.assertItemsEqual(solver.get_all_values(cs, mem[0x10000]), [0x41, 0x42])
|
|
self.assertItemsEqual(solver.get_all_values(cs, mem[0x10001]), [0x00, 0x42])
|
|
|
|
addr2 = cs.new_bitvec(64)
|
|
cs.add(Operators.OR(addr2 == 0x10000, addr2 == 0x10001, addr2 == 0x10002))
|
|
value2 = cs.new_bitvec(8)
|
|
cs.add(value2 == 0x43)
|
|
mem[addr2] = value2
|
|
|
|
self.assertItemsEqual(solver.get_all_values(cs, mem[0x10000]), [0x41, 0x42, 0x43])
|
|
self.assertItemsEqual(solver.get_all_values(cs, mem[0x10001]), [0x00, 0x42, 0x43])
|
|
self.assertItemsEqual(solver.get_all_values(cs, mem[0x10002]), [0x00, 0x43])
|
|
|
|
|
|
def test_mmap_file(self):
|
|
#file mapping
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('X'*0x3000)
|
|
rwx_file.close()
|
|
m = FileMap(0x10000000, 0x3000, 'rwx', rwx_file.name)
|
|
m[0x10000000:0x10000002] = 'YZ'
|
|
self.assertEqual(m[0x10000000], 'Y')
|
|
self.assertEqual(m[0x10000001], 'Z')
|
|
self.assertItemsEqual(m[0x10000000:0x10000003], 'YZX')
|
|
|
|
head, tail = m.split(0)
|
|
self.assertEqual(head, None)
|
|
self.assertEqual(tail, m)
|
|
|
|
head, tail = m.split(0x10000000)
|
|
self.assertEqual(head, None)
|
|
self.assertEqual(tail, m)
|
|
|
|
head, tail = m.split(0x10003001)
|
|
self.assertEqual(head, head)
|
|
self.assertEqual(tail, None)
|
|
|
|
|
|
head, tail = m.split(0x10003000-1)
|
|
self.assertEqual(len(head), 0x3000-1)
|
|
self.assertEqual(len(tail), 1)
|
|
|
|
def test_mmap_anon_split(self):
|
|
#file mapping
|
|
m = AnonMap(0x10000000, 0x3000, 'rwx')
|
|
m[0x10000000:0x10000002] = 'YZ'
|
|
self.assertEqual(m[0x10000000], 'Y')
|
|
self.assertEqual(m[0x10000001], 'Z')
|
|
self.assertItemsEqual(m[0x10000000:0x10000003], 'YZ\x00')
|
|
|
|
head, tail = m.split(0)
|
|
self.assertEqual(head, None)
|
|
self.assertEqual(tail, m)
|
|
|
|
head, tail = m.split(0x10000000)
|
|
self.assertEqual(head, None)
|
|
self.assertEqual(tail, m)
|
|
|
|
head, tail = m.split(0x10003001)
|
|
self.assertEqual(head, head)
|
|
self.assertEqual(tail, None)
|
|
|
|
|
|
head, tail = m.split(0x10003000-1)
|
|
self.assertEqual(len(head), 0x3000-1)
|
|
self.assertEqual(len(tail), 1)
|
|
|
|
m = pickle.loads(pickle.dumps(m))
|
|
self.assertItemsEqual(m[0x10000000:0x10000003], 'YZ\x00')
|
|
|
|
|
|
def test_mmap_file_extra(self):
|
|
#file mapping
|
|
rwx_file = tempfile.NamedTemporaryFile('w+b', delete=False)
|
|
rwx_file.file.write('X'*0x2800)
|
|
rwx_file.close()
|
|
m = FileMap(0x10000000, 0x3000, 'rwx', rwx_file.name)
|
|
self.assertItemsEqual(m[0x10000000:0x10003000], 'X'*0x2800 + '\x00'*0x800)
|
|
|
|
m[0x100027f0:0x10002810] = 'Y'*0x20
|
|
self.assertItemsEqual(m[0x10000000:0x10003000], 'X'*0x27f0 + 'Y'*0x20 + '\x00'*0x7f0)
|
|
|
|
m = pickle.loads(pickle.dumps(m))
|
|
self.assertItemsEqual(m[0x10000000:0x10003000], 'X'*0x27f0 + 'Y'*0x20 + '\x00'*0x7f0)
|
|
|
|
def test_mem_basic_trace(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
|
|
addr = mem.mmap(None, 0x1000, 'rw')
|
|
|
|
mem.push_record_writes()
|
|
mem.write(addr, 'a')
|
|
mem.write(addr+1, 'b')
|
|
writes = mem.pop_record_writes()
|
|
|
|
self.assertIn((addr, ['a']), writes)
|
|
self.assertIn((addr+1, ['b']), writes)
|
|
|
|
|
|
def test_mem_trace_no_overwrites(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
|
|
addr = mem.mmap(None, 0x1000, 'rw')
|
|
|
|
mem.push_record_writes()
|
|
mem.write(addr, 'a')
|
|
mem.write(addr, 'b')
|
|
writes = mem.pop_record_writes()
|
|
|
|
self.assertIn((addr, ['a']), writes)
|
|
self.assertIn((addr, ['b']), writes)
|
|
|
|
def test_mem_trace_nested(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
|
|
addr = mem.mmap(None, 0x1000, 'rw')
|
|
|
|
mem.push_record_writes()
|
|
mem.write(addr, 'a')
|
|
mem.write(addr+1, 'b')
|
|
mem.push_record_writes()
|
|
mem.write(addr+2, 'c')
|
|
mem.write(addr+3, 'd')
|
|
inner_writes = mem.pop_record_writes()
|
|
outer_writes = mem.pop_record_writes()
|
|
|
|
# Make sure writes do not appear in a trace started after them
|
|
self.assertNotIn((addr, ['a']), inner_writes)
|
|
self.assertNotIn((addr+1, ['b']), inner_writes)
|
|
# Make sure the first two are in the outer write
|
|
self.assertIn((addr, ['a']), outer_writes)
|
|
self.assertIn((addr+1, ['b']), outer_writes)
|
|
# Make sure the last two are in the inner write
|
|
self.assertIn((addr+2, ['c']), inner_writes)
|
|
self.assertIn((addr+3, ['d']), inner_writes)
|
|
# Make sure the last two are also in the outer write
|
|
self.assertIn((addr+2, ['c']), outer_writes)
|
|
self.assertIn((addr+3, ['d']), outer_writes)
|
|
|
|
|
|
def test_mem_trace_ignores_failing(self):
|
|
cs = ConstraintSet()
|
|
mem = SMemory32(cs)
|
|
addr = mem.mmap(None, 0x1000, 'rw')
|
|
|
|
mem.push_record_writes()
|
|
with self.assertRaises(MemoryException):
|
|
mem.write(addr-0x5000, 'a')
|
|
trace = mem.pop_record_writes()
|
|
|
|
# Make sure erroring writes don't get recorded
|
|
self.assertEqual(len(trace), 0)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|
|
|