Tony Breeds
2005-Dec-09 05:55 UTC
[Xen-devel] [PATCH 2/3] make check infrastructure for xen/ directory
Signed-off-by: Tony Breeds <tony@bakeyournoodle.com> ----- Forwarded message from Rusty Russell <rusty@rustcorp.com.au> ----- To: Tony Breeds <tony@bakeyournoodle.com> From: Rusty Russell <rusty@rustcorp.com.au> Subject: [PATCH 2/3] make check infrastructure for xen/ directory Date: Fri, 09 Dec 2005 16:46:27 +1100 This introduces some fake xen core components and headers, so we can test each C source file in xen/common in isolation. The behaviour of the functions is controlled by the test code, and it also contains extra sanity checks (eg. memory leaks, locks held, irqs disabled). Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> diff -urN --exclude=.hg --exclude=''*~'' --exclude=''*.aux'' xen-unstable.hg-mainline/xen/test/fake-include.h xen-unstable.hg-check/xen/test/fake-include.h --- xen-unstable.hg-mainline/xen/test/fake-include.h 1970-01-01 10:00:00.000000000 +1000 +++ xen-unstable.hg-check/xen/test/fake-include.h 2005-12-09 16:33:19.000000000 +1100 @@ -0,0 +1,237 @@ +#ifndef _XEN_TEST_FAKE_INCLUDE +#define _XEN_TEST_FAKE_INCLUDE + +#if (ULONG_MAX >> (CHAR_BIT*4)) == 0 +#define BITS_PER_LONG (CHAR_BIT*4) +#elif (ULONG_MAX >> (CHAR_BIT*8)) == 0 +#define BITS_PER_LONG (CHAR_BIT*8) +#else +#error Cannot determine BITS_PER_LONG +#endif + +#define BITS_TO_LONGS(bits) \ + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] + +/* FIXME: Get rid of EXPORT_SYMBOL */ +#define EXPORT_SYMBOL(sym) + +#define __user + +#define BUG_ON(x) assert(!(x)) +#define ASSERT(x) assert(x) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define NR_EVENT_CHANNELS (sizeof(unsigned long) * sizeof(unsigned long) * 64) +#define MAX_EVTCHNS NR_EVENT_CHANNELS +#define EVTCHNS_PER_BUCKET 128 +#define NR_EVTCHN_BUCKETS (MAX_EVTCHNS / EVTCHNS_PER_BUCKET) + +#include "../include/xen/list.h" +#include "../include/public/xen.h" + +unsigned int hweight32(unsigned int w); + +/* Linux-style typedefs */ +typedef int64_t s64; +typedef uint64_t u64; +typedef int32_t s32; +typedef uint32_t u32; +typedef int16_t s16; +typedef uint16_t u16; +typedef int8_t s8; +typedef uint8_t u8; + +typedef int64_t s_time_t; + +typedef struct { + struct list_head _list; + const char *_name; + int _l; +} spinlock_t; +typedef struct { + struct list_head _list; + const char *_name; + unsigned int _w; unsigned int _r; +} rwlock_t; + +#define __cacheline_aligned +#define unlikely(x) (x) +#define xmalloc(type) ((type *)fake_xmalloc(sizeof(type), __FILE__, __LINE__)) +#define xmalloc_array(type, num) ((type *)fake_xmalloc(sizeof(type) * (num), __FILE__, __LINE__)) +void *fake_xmalloc(size_t size, const char *file, int line); +void fake_xfree(void *p); +#define xfree(p) fake_xfree(p) + +#define for_each_online_cpu(i) for ((i) = 0; (i) < NR_CPUS; (i)++) + +extern void printk(const char *format, ...) +__attribute__ ((format (printf, 1, 2))); +#define printf printk + +/* FIXME: Not used in Xen */ +#define __init + +#define NR_CPUS 2 +#define NR_PIRQS 256 + +s_time_t NOW(void); + +void cpu_raise_softirq(unsigned int cpu, unsigned int nr); +int smp_processor_id(void); + +typedef void keyhandler_t(unsigned char key); +void register_keyhandler(unsigned char key, keyhandler_t *handler, + char *desc); + +#define __stringify_1(x) #x +#define __stringify(x) __stringify_1(x) + +void spin_lock_init(spinlock_t *lock); +void _spin_lock_irq(spinlock_t *lock, const char *name); +void spin_unlock_irq(spinlock_t *lock); +#define spin_lock_irqsave(lock, flags) \ + _spin_lock_irqsave((lock), &(flags), __stringify(lock)) +void _spin_lock_irqsave(spinlock_t *lock, unsigned long *flags, + const char *name); +void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags); +void _spin_lock(spinlock_t *lock, const char *name); +void spin_unlock(spinlock_t *lock); +void _spin_lock_recursive(spinlock_t *lock, const char *name); +void spin_unlock_recursive(spinlock_t *lock); +#define spin_lock(lock) _spin_lock(lock, __stringify(lock)) +#define spin_lock_recursive(lock) \ + _spin_lock_recursive(lock, __stringify(lock)) +#define spin_lock_irq(lock) _spin_lock_irq((lock), __stringify(lock)) +#define SPIN_LOCK_UNLOCKED ((spinlock_t){ ._l = 88 }) + +void _write_lock(rwlock_t *lock, const char *name); +void _read_lock(rwlock_t *lock, const char *name); +#define write_lock(lock) _write_lock((lock), __stringify(lock)) +#define read_lock(lock) _read_lock((lock), __stringify(lock)) +void write_unlock(rwlock_t *lock); +void read_unlock(rwlock_t *lock); + +#define copy_from_user(to, from, n) \ + fake_copy_from_user((to), (from), (n), __FILE__, __LINE__) +unsigned long fake_copy_from_user(void *to, const void __user *from, + unsigned n, const char *file, int line); +#define copy_to_user(to, from, n) \ + fake_copy_to_user((to), (from), (n), __FILE__, __LINE__) +unsigned long fake_copy_to_user(void __user *to, const void *from, + unsigned n, const char *file, int line); + +#define prefetch(x) (0) + +#define __initcall(x) + +typedef unsigned long cpumask_t; +#define CPUMAP_RUNANYWHERE 0xFFFFFFFF + +typedef struct { int _val; } atomic_t; +void atomic_set(atomic_t *a, int i); +#define _atomic_set(a, i) atomic_set(&(a), (i)) +int atomic_read(atomic_t *a); +#define _atomic_read(a) atomic_read(&(a)) +void atomic_inc(atomic_t *v); +int atomic_dec_and_test(atomic_t *a); +atomic_t atomic_compareandswap(atomic_t old, atomic_t new, atomic_t *v); +unsigned int __cmpxchg(volatile void *ptr, + unsigned long old, + unsigned long new, + int size); + +void set_bit(int bit, void *addr); +void clear_bit(int bit, void *addr); +int test_bit(int bit, void *addr); +int test_and_set_bit(int bit, void *addr); +int test_and_clear_bit(int bit, void *addr); + +struct domain { + domid_t domain_id; + spinlock_t big_lock; + shared_info_t *shared_info; + atomic_t refcnt; + void *ssid; + unsigned long domain_flags; + int shutdown_code; + struct list_head page_list; + struct list_head xenpage_list; + spinlock_t page_alloc_lock; + struct domain *next_in_list; + struct domain *next_in_hashbucket; + struct vcpu *vcpu[MAX_VIRT_CPUS]; + cpumask_t cpumask; + unsigned long vm_assist; + struct evtchn *evtchn[NR_EVTCHN_BUCKETS]; + spinlock_t evtchn_lock; + u16 pirq_to_evtchn[NR_PIRQS]; + unsigned int tot_pages; + unsigned int max_pages; + xen_domain_handle_t handle; + u32 pirq_mask[NR_PIRQS/32]; +}; + +struct vcpu { + int vcpu_id; + int processor; + struct domain *domain; + struct vcpu *next_in_list; + atomic_t pausecnt; + unsigned long vcpu_flags; + u16 virq_to_evtchn[NR_VIRQS]; + s_time_t cpu_time; + cpumap_t cpumap; +}; + +struct cpu_info { + struct cpu_user_regs guest_cpu_user_regs; + unsigned int processor_id; + struct vcpu *current_ed; +}; + +/* evntchn state values */ +#define ECS_FREE 0 +#define ECS_RESERVED 1 +#define ECS_UNBOUND 2 +#define ECS_INTERDOMAIN 3 +#define ECS_PIRQ 4 +#define ECS_VIRQ 5 +#define ECS_IPI 6 + +struct evtchn +{ + u16 state; + u16 notify_vcpu_id; + union { + struct { + domid_t remote_domid; + } unbound; + struct { + u16 remote_port; + struct domain *remote_dom; + } interdomain; + u16 pirq; + u16 virq; + } u; +}; + +extern struct vcpu *current; +void domain_destruct(struct domain *d); +void put_domain(struct domain *d); +int get_domain(struct domain *d); +int IS_PRIV(struct domain *d); + +struct domain *find_domain_by_id(domid_t dom); + +void put_domain(struct domain *d); + +#define IDLE_DOMAIN_ID (0x7FFFU) +#define is_idle_task(_d) (test_bit(_DOMF_idle_domain, &(_d)->domain_flags)) + +#define RW_LOCK_UNLOCKED ((rwlock_t) { ._r = 0, ._w = 0 }) +#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) + +#define always_inline +#endif /* _XEN_TEST_FAKE_INCLUDE */ diff -urN --exclude=.hg --exclude=''*~'' --exclude=''*.aux'' xen-unstable.hg-mainline/xen/test/fake-support.h xen-unstable.hg-check/xen/test/fake-support.h --- xen-unstable.hg-mainline/xen/test/fake-support.h 1970-01-01 10:00:00.000000000 +1000 +++ xen-unstable.hg-check/xen/test/fake-support.h 2005-12-09 16:33:19.000000000 +1100 @@ -0,0 +1,81 @@ +/* Routines for tests to manipulate the results of the fake xen functions */ +#ifndef _FAKE_SUPPORT_H +#define _FAKE_SUPPORT_H + +#include "fake-include.h" + +/* Use these in tests to create __user pointers. */ +void __user *fake_to_user(const void *p); +void *fake_from_user(const void __user *p); + +/* Use this to make sure all memory has been initialized (under + * valgrind). Ignore return val. */ +int fake_check_memory(void *mem, unsigned len); + +/* Locks held and irqs blocked. */ +extern unsigned int fake_lock_count; +extern unsigned int fake_irq_state; + +/* cpu_raise_softirq */ +extern unsigned int fake_cpu_raise_softirq_in_cpu; +extern unsigned int fake_cpu_raise_softirq_in_nr; + +/* register_keyhandler */ +extern unsigned char fake_register_keyhandler_in_key; +extern keyhandler_t *fake_register_keyhandler_in_handler; +extern char *fake_register_keyhandler_in_desc; + +/* NOW */ +extern s_time_t fake_NOW_out; + +/* get_domain */ +extern struct domain *fake_get_domain_in_d; +extern int fake_get_domain_out; + +/* IS_PRIV */ +extern struct domain *_fake_IS_PRIV_in_d; +extern int fake_IS_PRIV_out; + +/* xmalloc */ +extern int fake_xmalloc_out_FAIL; +/* Adjust this if you know how many bytes will be allocated/freed */ +extern unsigned int fake_xmalloc_expected; +/* Use these flags to indicate that something will be allocated/freed */ +extern int fake_expect_xmalloc, fake_expect_xfree; + +/* Sometimes the lock is not in scope, so we use name. */ +extern void fake_must_have_spinlock(const char *); +extern void fake_must_have_readlock(const char *); +extern void fake_must_have_writelock(const char *); + +/* xfree */ +extern void *fake_xfree_in_ptr; + +/* find_domain_by_id */ +extern struct domain *fake_find_domain_out; + +/* Test suite command line processor */ +extern void parse_test_args(int argc, char *argv[]); + +/* Dynamic suppression registration */ +extern void register_suppression(const char *file, int line); + +/* Checks no locks held, no irqs disabled, no memory leaks */ +extern void fake_check_status(const char *file, int line); + +#define test_cond(expr) \ +do { \ + int _x = (expr); \ + fake_check_status(__FILE__, __LINE__); \ + if (!(_x)) \ + test_cond_fail(#expr, __FILE__, __LINE__, \ + __PRETTY_FUNCTION__); \ +} while (0) + + +extern void __attribute__((noreturn)) test_cond_fail(const char *expression, + const char *file, + int line, + const char *function); + +#endif /* _FAKE_SUPPORT_H */ diff -urN --exclude=.hg --exclude=''*~'' --exclude=''*.aux'' xen-unstable.hg-mainline/xen/test/fake.c xen-unstable.hg-check/xen/test/fake.c --- xen-unstable.hg-mainline/xen/test/fake.c 1970-01-01 10:00:00.000000000 +1000 +++ xen-unstable.hg-check/xen/test/fake.c 2005-12-09 16:33:19.000000000 +1100 @@ -0,0 +1,671 @@ +/* Generic routines which most things in the Xen core expect. + Copyright (C) 2005 Rusty Russell IBM Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <assert.h> +#include <stdint.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/wait.h> +#include <errno.h> + +#include "fake-support.h" + +/* All these functions can be overridden by individual tests. */ +#define __override __attribute__((weak)) + +struct suppression { + struct list_head list; + int line; + char *file; +}; + +enum test_is {ON=0, OFF=1}; + +enum option_bits { + XMALLOC_FAIL=0, + USERCOPY_FAIL=1, +}; + +struct option { + enum option_bits bit; + char *name; +}; + +static struct option options[] = { + { .bit = XMALLOC_FAIL, .name = "xmalloc" }, + { .bit = USERCOPY_FAIL, .name = "usercopy" }, +}; + +static char *arg_prefixes[] = { + "--fail-tests=", + "--fail-", + "--nofail-tests=", + "--nofail-", +}; + +static char *sep = ","; +static char *negate = "--no"; + +static unsigned long active_tests = ULONG_MAX; + +struct failure { + struct list_head list; + const char *file; + int line; +}; +static LIST_HEAD(failures); +static LIST_HEAD(suppressions); + +void register_suppression(const char *file, int line) +{ + struct suppression *s; + + s = malloc(sizeof(*s)); + s->file = file; + s->line = line; + list_add_tail(&s->list, &suppressions); +} + +static void print_failures(const char *file, int line) +{ + struct failure *i; + + fprintf(stderr, "--failures="); + list_for_each_entry(i, &failures, list) + fprintf(stderr, "%s:%i,", i->file, i->line); + fprintf(stderr, "%s:%i\n", file, line); +} + +static int should_i_fail(const char *file, int line, int option_bit) +{ + int status; + pid_t pid; + struct failure *f; + struct suppression *s; + + if (!(active_tests & (1<<option_bit))) + return 0; + + list_for_each_entry(s, &suppressions, list) { + if (s->line == line && strcmp(s->file, file) == 0) { + return 0; + } + } + + pid = fork(); + if (pid == 0) { + f = malloc(sizeof(*f)); + f->file = file; + f->line = line; + list_add_tail(&f->list, &failures); + return 1; + } + + if (pid == -1) { + fprintf(stderr, "Failed to fork() child: %s\n", + strerror(errno)); + exit(1); + } + + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { + /* 7 means child already printed error msg. */ + if (!WIFEXITED(status) || WEXITSTATUS(status) != 7) { + fprintf(stderr, "Child %d %s %i\n", (int)pid, + WIFEXITED(status) ? "exited with status" + : "died with signal", + WIFEXITED(status) ? WEXITSTATUS(status) + : WTERMSIG(status)); + print_failures(file, line); + } + exit(7); + } + return 0; +} + +unsigned int __override hweight32(unsigned int w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +void __override atomic_set(atomic_t *a, int i) +{ + a->_val = ~i; +} + +int __override atomic_dec_and_test(atomic_t *a) +{ + assert(~(a->_val) != 0); + a->_val = ~(~a->_val - 1); + return (~a->_val == 0); +} + +void __override atomic_inc(atomic_t *a) +{ + a->_val = ~(~a->_val + 1); +} + +int __override atomic_read(atomic_t *a) +{ + return ~a->_val; +} + +unsigned int __override __cmpxchg(volatile void *ptr, + unsigned long old, + unsigned long new, + int size) +{ + unsigned long prev; + + switch (size) { + case 1: + prev = *(u8 *)ptr; + if (prev == old) + *(u8 *)ptr = new; + break; + case 2: + prev = *(u16 *)ptr; + if (prev == old) + *(u16 *)ptr = new; + break; + case 4: + prev = *(u32 *)ptr; + if (prev == old) + *(u32 *)ptr = new; + break; +#ifdef __x86_64__ + case 8: + prev = *(u64 *)ptr; + if (prev == old) + *(u64 *)ptr = new; + break; +#endif + default: + assert(0); + } + return prev; +} + +atomic_t __override atomic_compareandswap(atomic_t old, atomic_t new, atomic_t *v) +{ + atomic_t rc; + rc._val = __cmpxchg(&v->_val, old._val, new._val, sizeof(*v)); + return rc; +} + +void __override printk(const char *format, ...) +{ + abort(); +} + +unsigned int fake_cpu_raise_softirq_in_cpu; +unsigned int fake_cpu_raise_softirq_in_nr; +void __override cpu_raise_softirq(unsigned int cpu, unsigned int nr) +{ + fake_cpu_raise_softirq_in_cpu = cpu; + fake_cpu_raise_softirq_in_nr = nr; +} + +unsigned char fake_register_keyhandler_in_key; +keyhandler_t *fake_register_keyhandler_in_handler; +char *fake_register_keyhandler_in_desc; +void __override register_keyhandler(unsigned char key, keyhandler_t *handler, + char *desc) +{ + fake_register_keyhandler_in_key = key; + fake_register_keyhandler_in_handler = handler; + fake_register_keyhandler_in_desc = desc; +} + +unsigned int fake_lock_count = 0; +unsigned int fake_irq_state = 0; +void __override spin_lock_init(spinlock_t *lock) +{ + *lock = SPIN_LOCK_UNLOCKED; +} + +static LIST_HEAD(spinlocks); +void _spin_lock(spinlock_t *lock, const char *name) +{ + assert(lock->_l == 88); + list_add(&lock->_list, &spinlocks); + lock->_name = name; + lock->_l = 89; + fake_lock_count++; +} + +void spin_unlock(spinlock_t *lock) +{ + assert(lock->_l == 89); + list_del(&lock->_list); + *lock = SPIN_LOCK_UNLOCKED; + assert(fake_lock_count > 0); + fake_lock_count--; +} + +void __override _spin_lock_irqsave(spinlock_t *lock, unsigned long *flags, + const char *name) +{ + _spin_lock(lock, name); + *flags = (776 + (long)lock) | fake_irq_state; + fake_irq_state = 1; +} + +void __override _spin_lock_irq(spinlock_t *lock, const char *name) +{ + _spin_lock(lock, name); + assert(fake_irq_state == 0); + fake_irq_state = 1; +} + +void __override spin_unlock_irq(spinlock_t *lock) +{ + spin_unlock(lock); + assert(fake_irq_state == 1); + fake_irq_state = 0; +} + +void __override spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) +{ + spin_unlock(lock); + assert((flags & ~0x1UL) == 776 + (long)lock); + fake_irq_state = (flags & 1); +} + +static LIST_HEAD(rwlocks); +void __override _write_lock(rwlock_t *lock, const char *name) +{ + list_add(&lock->_list, &rwlocks); + lock->_name = name; + assert(lock->_w == 0); + assert(lock->_r == 0); + lock->_w = 1; +} + +void __override _read_lock(rwlock_t *lock, const char *name) +{ + list_add(&lock->_list, &rwlocks); + lock->_name = name; + assert(lock->_w == 0); + assert(lock->_r == 0); + lock->_r = 1; +} + +void __override write_unlock(rwlock_t *lock) +{ + list_del(&lock->_list); + assert(lock->_w == 1); + assert(lock->_r == 0); + lock->_w = 0; +} + +void __override read_unlock(rwlock_t *lock) +{ + list_del(&lock->_list); + assert(lock->_w == 0); + assert(lock->_r == 1); + lock->_r = 0; +} + +/* FIXME: Recursion isn''t actually supported in this test suite */ +void __override _spin_lock_recursive(spinlock_t *lock, const char *name) +{ + _spin_lock(lock, name); +} + +void __override spin_unlock_recursive(spinlock_t *lock) +{ + spin_unlock(lock); +} + + +int __override smp_processor_id(void) +{ + return 0; +} + +s_time_t fake_NOW_out; +s_time_t __override NOW(void) +{ + return fake_NOW_out; +} + +void __override domain_destruct(struct domain *d) +{ + free(d); +} + +struct domain *fake_put_domain_in_d; +void __override put_domain(struct domain *d) +{ + fake_put_domain_in_d = d; + if (atomic_dec_and_test(&d->refcnt)) + domain_destruct(d); +} + +struct domain *fake_get_domain_in_d; +int fake_get_domain_out = 1; +int __override get_domain(struct domain *d) +{ + fake_get_domain_in_d = d; + if (!fake_get_domain_out) + return 0; + atomic_inc(&d->refcnt); + return 1; +} + +struct domain *fake_find_domain_out; +struct domain *__override find_domain_by_id(domid_t dom) +{ + if (!fake_find_domain_out) + return NULL; + + atomic_inc(&fake_find_domain_out->refcnt); + return fake_find_domain_out; +} + +void __override set_bit(int bit, void *addr) +{ + unsigned long *bitmap = (unsigned long *)addr; + bitmap[bit/BITS_PER_LONG] |= (1 << (bit%BITS_PER_LONG)); +} + +void __override clear_bit(int bit, void *addr) +{ + unsigned long *bitmap = (unsigned long *)addr; + bitmap[bit/BITS_PER_LONG] &= ~(1 << (bit%BITS_PER_LONG)); +} + +int __override test_bit(int bit, void *addr) +{ + unsigned long *bitmap = (unsigned long *)addr; + + return bitmap[bit/BITS_PER_LONG] & (1 << (bit%BITS_PER_LONG)); +} + +int __override test_and_set_bit(int bit, void *addr) +{ + int old = test_bit(bit, addr); + set_bit(bit, addr); + + return old; +} + +int __override test_and_clear_bit(int bit, void *addr) +{ + int old = test_bit(bit, addr); + clear_bit(bit, addr); + + return old; +} + +/* Use these in tests to create __user pointers: we bit-invert them. */ +void __user *__override fake_to_user(const void *p) +{ + return (void *)~((unsigned long)p); +} + +void *__override fake_from_user(const void __user *p) +{ + return (void *)~((unsigned long)p); +} + +unsigned long __override fake_copy_from_user(void *to, + const void __user *from, + unsigned n, + const char *file, + int line) +{ + if (should_i_fail(file, line, USERCOPY_FAIL)) + return 1; + + memcpy(to, fake_from_user(from), n); + return 0; +} + +unsigned long __override fake_copy_to_user(void __user *to, const void *from, + unsigned n, + const char *file, + int line) +{ + if (should_i_fail(file, line, USERCOPY_FAIL)) + return 1; + + memcpy(fake_from_user(to), from, n); + return 0; +} + +struct fake_xmalloc_hdr +{ + const char *file; + int line; + size_t size; +}; + +static int fake_xmalloc_bytes; +unsigned int fake_xmalloc_expected; +int fake_expect_xmalloc, fake_expect_xfree; +void *fake_xmalloc(size_t size, const char *file, int line) +{ + struct fake_xmalloc_hdr *h; + if (should_i_fail(file, line, XMALLOC_FAIL)) + return NULL; + + h = malloc(sizeof(*h) + size); + h->file = file; + h->line = line; + h->size = size; + + fake_xmalloc_bytes += size; + return h+1; +} + +struct domain *fake_IS_PRIV_in_d; +/* Assume privilege unless told otherwise */ +int fake_IS_PRIV_out = 1; +int __override IS_PRIV(struct domain *d) +{ + fake_IS_PRIV_in_d = d; + return fake_IS_PRIV_out; +} + +void *fake_xfree_in_ptr; +void fake_xfree(void *ptr) +{ + struct fake_xmalloc_hdr *h; + + if (ptr == NULL) + return; + + fake_xfree_in_ptr = ptr; + + h = ((struct fake_xmalloc_hdr *)ptr)-1; + + fake_xmalloc_bytes -= h->size; + assert(fake_xmalloc_bytes >= 0); + + free(h); +} + +struct vcpu *current; + +/* Use this to check that memory has been fully initialized (valgrind). + * We don''t use memcheck.h''s VALGRIND_CHECK_DEFINED since we don''t want to + * depend on valgrind. Ignore return value. */ +int fake_check_memory(void *mem, unsigned len) +{ + unsigned int i, sum = 0; + + for (i = 0; i < len; i++) + sum += ((char *)mem)[i]; + + /* Valgrind not that bright: as soon as we "use" result it will + * complain if uninitialized */ + if (sum) + return 100; + return 0; +} + +static void process_test_arg(char *arg, enum test_is state) +{ + char *arg_pos; + + arg_pos = strtok(arg, sep); + do { + int i; + unsigned long mask = 0UL; + int found = 0; + + if (arg_pos == NULL) + break; + + for(i=0; i<ARRAY_SIZE(options); i++) { + if (strcmp("all", arg_pos) == 0) { + found = 1; + mask = ULONG_MAX; + if (state == OFF) { + mask = 0UL; + } + } else if (strcmp("none", arg_pos) == 0) { + found = 1; + mask = 0UL; + if (state == OFF) { + mask = ULONG_MAX; + } + } else if (strcmp(options[i].name, arg_pos) == 0) { + found = 1; + mask = (1<<options[i].bit); + } + + if (found) { + if (state == ON) { + active_tests |= mask; + } else { + active_tests ^= ~mask; + } + + break; + } + + } + + } while ((arg_pos = strtok(NULL, sep)) != NULL); +} + +void parse_test_args(int argc, char *argv[]) +{ + int i = 0; + + while (++i < argc) { + int j; + for(j=0; j<ARRAY_SIZE(arg_prefixes); j++) { + int len = strlen(arg_prefixes[j]); + + if (strncmp(arg_prefixes[j], argv[i], len) == 0) { + enum test_is state = ON; + if (strstr(arg_prefixes[j], negate) != NULL) { + state = OFF; + } + process_test_arg(argv[i] +len, state); + } + } + } +} + +static void __attribute__((noreturn)) +test_fail(const char *file, int line, const char *function, + const char *expression) +{ + fprintf(stderr, "%s:%d: %s: Fake Assertion `%s'' failed.\n", + file, line, function, expression); + abort(); +} + +/* assert */ +void test_cond_fail(const char *expression, const char *file, + int line, const char *function) +{ + /* Failures will... err... cause failure. */ + if (!list_empty(&failures)) + exit(0); + + test_fail(file, line, function, expression); +} + +void fake_must_have_spinlock(const char *name) +{ + spinlock_t *i; + list_for_each_entry(i, &spinlocks, _list) + if (strcmp(i->_name, name) == 0) + return; + assert(0); +} + +void fake_must_have_readlock(const char *name) +{ + rwlock_t *i; + list_for_each_entry(i, &rwlocks, _list) + if (strcmp(i->_name, name) == 0) { + assert(i->_r && !i->_w); + return; + } + assert(0); +} + +void fake_must_have_writelock(const char *name) +{ + rwlock_t *i; + list_for_each_entry(i, &rwlocks, _list) + if (strcmp(i->_name, name) == 0) { + assert(i->_w && !i->_r); + return; + } + assert(0); +} + +/* Checks no locks held, no irqs disabled, no memory leaks */ +void fake_check_status(const char *file, int line) +{ + if (fake_expect_xmalloc) { + if (fake_xmalloc_bytes <= fake_xmalloc_expected) + test_cond_fail("xmalloc expected", file, line, + "test_cond"); + fake_xmalloc_expected = fake_xmalloc_bytes; + fake_expect_xmalloc = 0; + } else if (fake_expect_xfree) { + if (fake_xmalloc_bytes >= fake_xmalloc_expected) + test_cond_fail("xfree expected", file, line, + "test_cond"); + fake_xmalloc_expected = fake_xmalloc_bytes; + fake_expect_xfree = 0; + } else if (fake_xmalloc_bytes != fake_xmalloc_expected) + test_fail(file, line, "test_cond", "xmalloc leak"); + if (fake_lock_count != 0) + test_fail(file, line, "test_cond", "spinlock leak"); + if (fake_irq_state != 0) + test_fail(file, line, "test_cond", "irq leak"); +} -- ccontrol: http://freshmeat.net/projects/ccontrol ----- End forwarded message ----- Yours Tony linux.conf.au http://linux.conf.au/ || http://lca2006.linux.org.au/ Jan 23-28 2006 The Australian Linux Technical Conference! _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel