def test_read_unsigned(self): data = b"\x01\x02\x03\x04\x05\x06\x07\x08" for word_size in [8, 4]: for byteorder in ["little", "big"]: flags = PlatformFlags(0) if word_size == 8: flags |= PlatformFlags.IS_64_BIT if byteorder == "little": flags |= PlatformFlags.IS_LITTLE_ENDIAN prog = mock_program( Platform(Architecture.UNKNOWN, flags), segments=[MockMemorySegment(data, 0xFFFF0000, 0xA0)], ) for size in [1, 2, 4, 8]: read_fn = getattr(prog, f"read_u{8 * size}") value = int.from_bytes(data[:size], byteorder) self.assertEqual(read_fn(0xFFFF0000), value) self.assertEqual(read_fn(0xA0, True), value) if size == word_size: self.assertEqual(prog.read_word(0xFFFF0000), value) self.assertEqual(prog.read_word(0xA0, True), value) prog = mock_program( MOCK_32BIT_PLATFORM, segments=[MockMemorySegment(data, 0xFFFF0000, 0xA0)] )
def test_pointer(self): prog = mock_program() self.assertEqual(prog.type("int *"), pointer_type(8, int_type("int", 4, True))) self.assertEqual( prog.type("const int *"), pointer_type(8, int_type("int", 4, True, Qualifiers.CONST)), ) self.assertEqual( prog.type("int * const"), pointer_type(8, int_type("int", 4, True), Qualifiers.CONST), ) self.assertEqual( prog.type("int **"), pointer_type(8, pointer_type(8, int_type("int", 4, True))), ) self.assertEqual( prog.type("int *((*))"), pointer_type(8, pointer_type(8, int_type("int", 4, True))), ) self.assertEqual( prog.type("int * const *"), pointer_type( 8, pointer_type(8, int_type("int", 4, True), Qualifiers.CONST) ), )
def test_read_float(self): pi32 = struct.unpack("f", struct.pack("f", math.pi))[0] for bit_size in [32, 64]: for bit_offset in range(8): for byteorder in ["little", "big"]: if bit_size == 64: fmt = "<d" expected = math.pi else: fmt = "<f" expected = pi32 tmp = int.from_bytes(struct.pack(fmt, math.pi), "little") if byteorder == "little": tmp <<= bit_offset else: tmp <<= (8 - bit_size - bit_offset) % 8 buf = tmp.to_bytes((bit_size + bit_offset + 7) // 8, byteorder) prog = mock_program(segments=[MockMemorySegment(buf, 0)]) obj = Object( prog, prog.float_type( "double" if bit_size == 64 else "float", bit_size // 8, byteorder, ), address=0, bit_offset=bit_offset, ) self.assertEqual(obj.value_(), expected)
def test_pointer_type(self): prog = mock_program() self.assertEqual(prog.pointer_type(prog.type('int')), prog.type('int *')) self.assertEqual(prog.pointer_type('int'), prog.type('int *')) self.assertEqual(prog.pointer_type(prog.type('int'), Qualifiers.CONST), prog.type('int * const'))
def test_pointer_to_pointer_to_array(self): prog = mock_program() self.assertEqual( prog.type("int (**)[2]"), pointer_type( 8, pointer_type(8, array_type(2, int_type("int", 4, True)))), )
def test_bad_address(self): data = b'hello, world!' prog = mock_program(segments=[MockMemorySegment(data, 0xffff0000)]) self.assertRaisesRegex(FaultError, 'could not find memory segment', prog.read, 0xdeadbeef, 4) self.assertRaisesRegex(FaultError, 'could not find memory segment', prog.read, 0xffff0000, 4, True)
def test_simple_read(self): data = b'hello, world' prog = mock_program(segments=[ MockMemorySegment(data, 0xffff0000, 0xa0), ]) self.assertEqual(prog.read(0xffff0000, len(data)), data) self.assertEqual(prog.read(0xa0, len(data), True), data)
def test_array_of_pointers_to_array(self): prog = mock_program() self.assertEqual( prog.type("int (*[2])[3]"), array_type( 2, pointer_type(8, array_type(3, int_type("int", 4, True)))), )
def test_different_programs_compound_callback(self): with self.assertRaisesRegex(ValueError, "objects are from different program"): self.prog.struct_type( None, 4, (TypeMember(lambda: mock_program().int_type("int", 4, True)), )).members[0].type
def test_bad_address(self): data = b"hello, world!" prog = mock_program(segments=[MockMemorySegment(data, 0xFFFF0000)]) self.assertRaisesRegex(FaultError, "could not find memory segment", prog.read, 0xDEADBEEF, 4) self.assertRaisesRegex(FaultError, "could not find memory segment", prog.read, 0xFFFF0000, 4, True)
def test_different_programs_array(self): self.assertRaisesRegex( ValueError, "type is from different program", self.prog.pointer_type, mock_program().int_type("int", 4, True), )
def test_lookup_error(self): prog = mock_program() self.assertRaisesRegex(LookupError, "^could not find constant 'foo'$", prog.constant, 'foo') self.assertRaisesRegex(LookupError, "^could not find constant 'foo' in 'foo.c'$", prog.constant, 'foo', 'foo.c') self.assertRaisesRegex(LookupError, "^could not find function 'foo'$", prog.function, 'foo') self.assertRaisesRegex(LookupError, "^could not find function 'foo' in 'foo.c'$", prog.function, 'foo', 'foo.c') self.assertRaisesRegex(LookupError, "^could not find 'typedef foo'$", prog.type, 'foo') self.assertRaisesRegex(LookupError, "^could not find 'typedef foo' in 'foo.c'$", prog.type, 'foo', 'foo.c') self.assertRaisesRegex(LookupError, "^could not find variable 'foo'$", prog.variable, 'foo') self.assertRaisesRegex(LookupError, "^could not find variable 'foo' in 'foo.c'$", prog.variable, 'foo', 'foo.c') # prog[key] should raise KeyError instead of LookupError. self.assertRaises(KeyError, prog.__getitem__, 'foo') # Even for non-strings. self.assertRaises(KeyError, prog.__getitem__, 9)
def test_invalid_read_fn(self): prog = mock_program() self.assertRaises(TypeError, prog.add_memory_segment, 0xFFFF0000, 8, b"foo") prog.add_memory_segment(0xFFFF0000, 8, lambda: None) self.assertRaises(TypeError, prog.read, 0xFFFF0000, 8) prog.add_memory_segment( 0xFFFF0000, 8, lambda address, count, offset, physical: None ) self.assertRaises(TypeError, prog.read, 0xFFFF0000, 8) prog.add_memory_segment( 0xFFFF0000, 8, lambda address, count, offset, physical: "asdf" ) self.assertRaises(TypeError, prog.read, 0xFFFF0000, 8) prog.add_memory_segment( 0xFFFF0000, 8, lambda address, count, offset, physical: b"" ) self.assertRaisesRegex( ValueError, r"memory read callback returned buffer of length 0 \(expected 8\)", prog.read, 0xFFFF0000, 8, )
def test_default_primitive_types(self): def spellings(tokens, num_optional=0): for i in range(len(tokens) - num_optional, len(tokens) + 1): for perm in itertools.permutations(tokens[:i]): yield " ".join(perm) for word_size in [8, 4]: prog = mock_program(MOCK_PLATFORM if word_size == 8 else MOCK_32BIT_PLATFORM) self.assertEqual(prog.type("_Bool"), prog.bool_type("_Bool", 1)) self.assertEqual(prog.type("char"), prog.int_type("char", 1, True)) for spelling in spellings(["signed", "char"]): self.assertEqual(prog.type(spelling), prog.int_type("signed char", 1, True)) for spelling in spellings(["unsigned", "char"]): self.assertEqual(prog.type(spelling), prog.int_type("unsigned char", 1, False)) for spelling in spellings(["short", "signed", "int"], 2): self.assertEqual(prog.type(spelling), prog.int_type("short", 2, True)) for spelling in spellings(["short", "unsigned", "int"], 1): self.assertEqual(prog.type(spelling), prog.int_type("unsigned short", 2, False)) for spelling in spellings(["int", "signed"], 1): self.assertEqual(prog.type(spelling), prog.int_type("int", 4, True)) for spelling in spellings(["unsigned", "int"]): self.assertEqual(prog.type(spelling), prog.int_type("unsigned int", 4, False)) for spelling in spellings(["long", "signed", "int"], 2): self.assertEqual(prog.type(spelling), prog.int_type("long", word_size, True)) for spelling in spellings(["long", "unsigned", "int"], 1): self.assertEqual( prog.type(spelling), prog.int_type("unsigned long", word_size, False), ) for spelling in spellings(["long", "long", "signed", "int"], 2): self.assertEqual(prog.type(spelling), prog.int_type("long long", 8, True)) for spelling in spellings(["long", "long", "unsigned", "int"], 1): self.assertEqual(prog.type(spelling), prog.int_type("unsigned long long", 8, False)) self.assertEqual(prog.type("float"), prog.float_type("float", 4)) self.assertEqual(prog.type("double"), prog.float_type("double", 8)) for spelling in spellings(["long", "double"]): self.assertEqual(prog.type(spelling), prog.float_type("long double", 16)) self.assertEqual( prog.type("size_t"), prog.typedef_type( "size_t", prog.int_type("unsigned long", word_size, False)), ) self.assertEqual( prog.type("ptrdiff_t"), prog.typedef_type("ptrdiff_t", prog.int_type("long", word_size, True)), )
def test_adjacent_segments(self): data = b"hello, world!\0foobar" prog = mock_program(segments=[ MockMemorySegment(data[:4], 0xFFFF0000), MockMemorySegment(data[4:14], 0xFFFF0004), MockMemorySegment(data[14:], 0xFFFFF000), ]) self.assertEqual(prog.read(0xFFFF0000, 14), data[:14])
def test_different_programs_function_parameter_callback(self): with self.assertRaisesRegex(ValueError, "objects are from different programs"): self.prog.function_type( self.prog.void_type(), (TypeParameter( lambda: mock_program().int_type("int", 4, True)), ), ).parameters[0].type
def test_different_programs_function_parameter(self): self.assertRaisesRegex( ValueError, "object is from different program", self.prog.function_type, self.prog.void_type(), (TypeParameter(mock_program().int_type("int", 4, True)), ), )
def test_different_programs_function_return(self): self.assertRaisesRegex( ValueError, "type is from different program", self.prog.function_type, mock_program().int_type("int", 4, True), (), )
def test_different_programs_typedef(self): self.assertRaisesRegex( ValueError, "type is from different program", self.prog.typedef_type, "INT", mock_program().int_type("int", 4, True), )
def test_different_programs_compound(self): self.assertRaisesRegex( ValueError, "object is from different program", self.prog.struct_type, None, 4, (TypeMember(mock_program().int_type("int", 4, True)), ), )
def test_different_programs_enum(self): self.assertRaisesRegex( ValueError, "type is from different program", self.prog.enum_type, None, mock_program().int_type("int", 4, True), (), )
def test_pointer_to_array(self): prog = mock_program() self.assertEqual( prog.type('int (*)[2]'), pointer_type(8, array_type(2, int_type('int', 4, True)))) self.assertEqual( prog.type('int (*)[2][3]'), pointer_type( 8, array_type(2, array_type(3, int_type('int', 4, True)))))
def test_primitive_type(self): prog = mock_program(types=[ int_type('long', 4, True), int_type('unsigned long', 4, True), ]) self.assertEqual(prog.type('long'), int_type('long', 4, True)) # unsigned long with signed=True isn't valid, so it should be ignored. self.assertEqual(prog.type('unsigned long'), int_type('unsigned long', 8, False))
def test_constant(self): mock_obj = MockObject('PAGE_SIZE', int_type('int', 4, True), value=4096) prog = mock_program(objects=[mock_obj]) self.assertEqual(prog['PAGE_SIZE'], Object(prog, int_type('int', 4, True), value=4096)) self.assertEqual(prog.object('PAGE_SIZE', FindObjectFlags.CONSTANT), prog['PAGE_SIZE']) self.assertTrue('PAGE_SIZE' in prog)
def test_pointer_to_array_of_pointers(self): prog = mock_program() self.assertEqual( prog.type('int *(*)[2]'), pointer_type( 8, array_type(2, pointer_type(8, int_type('int', 4, True))))) self.assertEqual( prog.type('int *((*)[2])'), pointer_type( 8, array_type(2, pointer_type(8, int_type('int', 4, True)))))
def test_variable(self): mock_obj = MockObject("counter", int_type("int", 4, True), address=0xFFFF0000) prog = mock_program(objects=[mock_obj]) self.assertEqual( prog["counter"], Object(prog, int_type("int", 4, True), address=0xFFFF0000) ) self.assertEqual( prog.object("counter", FindObjectFlags.VARIABLE), prog["counter"] ) self.assertTrue("counter" in prog)
def test_segment_overflow(self): data = b"hello, world!" prog = mock_program(segments=[MockMemorySegment(data, 0xFFFF0000)]) self.assertRaisesRegex( FaultError, "could not find memory segment", prog.read, 0xFFFF0000, len(data) + 1, )
def test_size_t_and_ptrdiff_t(self): # 64-bit architecture with 4-byte long/unsigned long. types = [] prog = mock_program(types=types) types.append(prog.int_type("long", 4, True)) types.append(prog.int_type("unsigned long", 4, False)) self.assertIdentical( prog.type("size_t"), prog.typedef_type("size_t", prog.type("unsigned long long")), ) self.assertIdentical( prog.type("ptrdiff_t"), prog.typedef_type("ptrdiff_t", prog.type("long long")), ) # 32-bit architecture with 8-byte long/unsigned long. types = [] prog = mock_program(MOCK_32BIT_PLATFORM, types=types) types.append(prog.int_type("long", 8, True)) types.append(prog.int_type("unsigned long", 8, False)) self.assertIdentical( prog.type("size_t"), prog.typedef_type("size_t", prog.type("unsigned int")) ) self.assertIdentical( prog.type("ptrdiff_t"), prog.typedef_type("ptrdiff_t", prog.type("int")) ) # Nonsense sizes. types = [] prog = mock_program(types=types) types.append(prog.int_type("int", 1, True)) types.append(prog.int_type("unsigned int", 1, False)) types.append(prog.int_type("long", 1, True)) types.append(prog.int_type("unsigned long", 1, False)) types.append(prog.int_type("long long", 2, True)) types.append(prog.int_type("unsigned long long", 2, False)) self.assertRaisesRegex( ValueError, "no suitable integer type for size_t", prog.type, "size_t" ) self.assertRaisesRegex( ValueError, "no suitable integer type for ptrdiff_t", prog.type, "ptrdiff_t" )
def test_variable(self): mock_obj = MockObject('counter', int_type('int', 4, True), address=0xffff0000) prog = mock_program(objects=[mock_obj]) self.assertEqual( prog['counter'], Object(prog, int_type('int', 4, True), address=0xffff0000)) self.assertEqual(prog.object('counter', FindObjectFlags.VARIABLE), prog['counter']) self.assertTrue('counter' in prog)
def test_function(self): mock_obj = MockObject( "func", function_type(void_type(), (), False), address=0xFFFF0000 ) prog = mock_program(objects=[mock_obj]) self.assertEqual( prog["func"], Object(prog, function_type(void_type(), (), False), address=0xFFFF0000), ) self.assertEqual(prog.object("func", FindObjectFlags.FUNCTION), prog["func"]) self.assertTrue("func" in prog)