// "static" kernel code // 1. increase the max # of syscalls by one, then use new slot // 2. maybe find an unused syscall slot? // 3. take over an existing, rarely used syscall (not recommended) int (*foofxn)(void *args) = NULL; int sys_foo(void *args) { if (foofxn == NULL) return -ENOSYS; // ENOTSUPP return foofxn(args); } // loadable module code struct mysyscallargs // move common definitions to hdr file (also syscall number) { char *file1, *file2; int flags; } myhw1args; int mysyscall(void *myargs) { struct mysyscallargs *ptr = (struct mysyscallargs *) myargs; // my actual syscall code here. // part 1: check params // 1a: validate 'ptr' in addrspace (use sizeof *ptr) // 1b: then copy it to kernel space, named 'kptr' // 1b: validate kptr->file1, kptr->file2, etc. } // module init code static int __init init_mysyscall(void) { foofxn = mysyscall; // check only if !NULL, else error return ?; } static void __exit exit_mysyscall(void) { if (foofxn == mysyscall) foofxn = NULL; else // what to do? } module_init(init_mysyscall); module_exit(exit_mysyscall); ////////////////////////////////////////////////////////////////////// // DEBUGGING // 1. use printk: messages go to console (and logged in syslog, // which then goes to /var/log/all). you can also see the most // recent kernel messages using dmesg(8). // pros: easy to use // cons: too many can overwhelm logging system; messages lost; // timing changed (affects race conditions) #ifdef DEBUG printk(...); #endif // 2. use assertions: simple true/false check. if failed, panic/warning // traditional: ASSERT(cond); ASSERT(ptr != NULL); // in linux: BUG_ON(ptr == NULL); // conditional oops if (some_complex_condition) // unconditional oops BUG(); WARN_ON(cond); // prints kernel stack if cond is TRUE dump_stack(); // just print kernel stack WARN_ON_ONCE(cond); // same as WARN_ON, but prints only once per LoC