def build_dir(self): # Reads filenames; extends inums fn_to_ino = {} for symfn, fn in self.filenames.items(): if not self.fs.root_dir.contains(symfn): continue syminum = self.fs.root_dir[symfn] fn_to_ino[fn] = self.inums[syminum] # Reads procs[pid].fds and procs[pid].vas; extends nothing (fdmap0, vamap0) = self.build_proc(False) (fdmap1, vamap1) = self.build_proc(True) # Compute known pipe end FDs. This map is system-wide because, # for example, process 1 may be holding open a pipe that's only # used by testing in process 0. pipe_end_fds = collections.defaultdict(list) for pid, fdmap in [(False, fdmap0), (True, fdmap1)]: for fd, (symfd, inode) in fdmap.items(): if symfd.ispipe: key = (z3util.HashableAst(symfd.pipeid.someval), symfd.pipewriter.val) if key not in pipe_end_fds: # Make sure both ends are in the map, even if we never # come across an example of the other end pipe_end_fds[key] = (symfd.pipeid, {True: 0, False: 0}) okey = (key[0], not key[1]) pipe_end_fds[okey] = (symfd.pipeid, {True: 0, False: 0}) pipe_end_fds[key][1][pid] += 1 setup = {'common': testgen.CodeWriter(), 'proc0': testgen.CodeWriter(), 'proc1': testgen.CodeWriter(), 'procfinal': testgen.CodeWriter(), 'final': testgen.CodeWriter()} try: # setup_proc reads nothing; extends inums, datavals, pipes self.emit = setup['proc0'] self.setup_proc(False, fdmap0, vamap0, pipe_end_fds) self.emit = setup['proc1'] self.setup_proc(True, fdmap1, vamap1, pipe_end_fds), # setup_inodes reads inums, pipes; extends datavals self.emit = setup['common']; self.setup_inodes() # setup_filenames reads nothing; extends nothing self.emit = setup['common']; self.setup_filenames(fn_to_ino) # setup_proc_finalize reads pipes; extends nothing self.emit = setup['procfinal']; self.setup_proc_finalize() # setup_inodes_finalize reads inums, pipes; extends nothing self.emit = setup['final']; self.setup_inodes_finalize() finally: self.emit = None return setup
def __check(self, res): """Return code to check the expected values of res. res must be a dictionary mapping variable names to expected values. 'errno' and DataVals are handled specially. """ emit = testgen.CodeWriter() for var, val in res.items(): if var == 'errno': continue if isinstance(val, DataVal): cval = val.first_byte var += '[0]' elif isinstance(val, fs_module.SOffset): # We can't map this through the per-file offsets interpreter # because we don't know which file to look in. cval = val.someval * DATAVAL_BYTES elif isinstance(val, simsym.Symbolic): # XXX Should we enumerate result values? This might only come # up in lseek. cval = val.someval else: cval = val emit('expect_result("%s", %s, %d);' % (var, var, cval)) if 'errno' in res: emit('expect_errno(%d);' % res['errno']) return emit
def on_model(self, testid, model, constraint): super(FsTestGenerator, self).on_model(testid, model, constraint) emit = testgen.CodeWriter() self.__pending_funcs.clear() try: emit("""\ /* * calls: %s */""" % " ".join(self.callset_names)) fs = FsState(model['Fs'], self.sar, constraint) pids = [] fns = {} for callidx, callname in enumerate(self.callset_names): # Generate test code for this call. As a side-effect, this will # fill in structures we need to write the setup code. args = self.get_call_args(callidx) res = self.get_result(callidx) fns['test_%d' % callidx] \ = self.func(emit, 'int', 'test_%s_%d' % (testid, callidx), fs.gen_code(callname, args, res)) if hasattr(args, 'pid'): pids.append(args.pid.val) else: # Some calls don't take a pid because their process doesn't matter pids.append(False) # Write setup code setup = fs.build_dir() for phase in ('common', 'proc0', 'proc1', 'final', 'procfinal'): fns['setup_' + phase] \ = self.func(emit, 'void', 'setup_%s_%s' % (testid, phase), setup[phase]) except SkipTest as e: print "Skipping test %s: %s" % (testid, e) return # Commit to this code self.__funcs.update(self.__pending_funcs) self.emit(emit) strargs = { 'testid': testid, 'pid0': pids[0], 'pid1': pids[1], 'name0': self.callset_names[0], 'name1': self.callset_names[1] } strargs.update(fns) self.fstests.append("""\ { "fs-%(testid)s", &%(setup_common)s, { { &%(setup_proc0)s }, { &%(setup_proc1)s } }, &%(setup_procfinal)s, &%(setup_final)s, { { &%(test_0)s, %(pid0)d, "%(name0)s" }, { &%(test_1)s, %(pid1)d, "%(name1)s" } }, &cleanup }""" % strargs)
def gen_code(self, callname, args, res): f = getattr(self, callname) self.emit = writer = testgen.CodeWriter() try: f(args, res.copy()) finally: self.emit = None return writer
def gen_code(self, callname, args, res): f = getattr(self, callname, None) if f is None: raise SkipTest('Test generation for %s not implemented' % callname) self.emit = writer = testgen.CodeWriter() try: f(args, res.copy()) finally: self.emit = None return writer
def func(self, emit, ret, fname, body): key = (ret, str(body)) existing = self.__funcs.get(key) code = 'static %s %s(void) {\n%s\n}' % (ret, fname, body.indent()) if existing is None: self.__pending_funcs[key] = fname emit(code) return fname else: # Put the original body in as a comment for readability emit(testgen.CodeWriter()(code).indent('// ')) emit('// ^ See %s' % existing) return existing
def __init__(self, test_file_name): super(FsTestGenerator, self).__init__(test_file_name) self.emit = testgen.CodeWriter(open(test_file_name, 'w')) self.fstests = [] self.__funcs = {} self.__pending_funcs = {} # Get some constants from fs global DATAVAL_BYTES DATAVAL_BYTES = fs_module.DATAVAL_BYTES self.emit("""\ //+++ common #define _GNU_SOURCE 1 #include <errno.h> #include <fcntl.h> #include <limits.h> #include <setjmp.h> #include <stdio.h> #include <unistd.h> #include <sys/stat.h> #include <sys/mman.h> #include <stdint.h> #include <stdbool.h> #include "fstest.h" __attribute__((__unused__)) static void init_map_anon(uintptr_t va, bool writable, char value) { char *r = mmap((void*)va, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); if (r == MAP_FAILED) setup_error("mmap"); *r = value; if (!writable) { int r2 = mprotect(r, 4096, PROT_READ); if (r2 < 0) setup_error("mprotect"); } // Ensure test cores don't shoot down the setup core xinvalidate(r, 4096); } __attribute__((__unused__)) static void init_map_file(uintptr_t va, bool writable, const char *fname, off_t offset) { int fd = open(fname, O_RDWR); if (fd < 0) setup_error("open"); void *r = mmap((void*)va, 4096, PROT_READ | (writable ? PROT_WRITE : 0), MAP_SHARED | MAP_FIXED, fd, offset); if (r == MAP_FAILED) setup_error("mmap"); close(fd); } """) # Generate datavals for i, d in enumerate(all_datavals): self.emit("__attribute__((__weak__)) const char %s[%d] = {%d};" % (d.expr, DATAVAL_BYTES, d.first_byte)) # Create a buffer for datavals. This is in the BSS, so we'll # touch it after fork (unlike, say, if it were on the stack). self.emit("__attribute__((__weak__)) char datavalbuf[%d];" % DATAVAL_BYTES) self.emit() self.emit("//+++ tests")