sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 1 | |
| 2 | Dealing with missing system call or ioctl wrappers in Valgrind |
| 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 4 | You're probably reading this because Valgrind bombed out whilst |
| 5 | running your program, and advised you to read this file. The good |
| 6 | news is that, in general, it's easy to write the missing syscall or |
| 7 | ioctl wrappers you need, so that you can continue your debugging. If |
| 8 | you send the resulting patches to me, then you'll be doing a favour to |
| 9 | all future Valgrind users too. |
| 10 | |
| 11 | Note that an "ioctl" is just a special kind of system call, really; so |
| 12 | there's not a lot of need to distinguish them (at least conceptually) |
| 13 | in the discussion that follows. |
| 14 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 15 | All this machinery is in coregrind/vg_syscalls.c. |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 16 | |
| 17 | |
| 18 | What are syscall/ioctl wrappers? What do they do? |
| 19 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 20 | Valgrind does what it does, in part, by keeping track of everything your |
| 21 | program does. When a system call happens, for example a request to read |
| 22 | part of a file, control passes to the Linux kernel, which fulfills the |
| 23 | request, and returns control to your program. The problem is that the |
| 24 | kernel will often change the status of some part of your program's memory |
| 25 | as a result, and skins (instrumentation plug-ins) may need to know about |
| 26 | this. |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 27 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 28 | Syscall and ioctl wrappers have two jobs: |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 29 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 30 | 1. Tell a skin what's about to happen, before the syscall takes place. A |
| 31 | skin could perform checks beforehand, eg. if memory about to be written |
| 32 | is actually writeable. This part is useful, but not strictly |
| 33 | essential. |
| 34 | |
| 35 | 2. Tell a skin what just happened, after a syscall takes place. This is |
| 36 | so it can update its view of the program's state, eg. that memory has |
| 37 | just been written to. This step is essential. |
| 38 | |
| 39 | The "happenings" mostly involve reading/writing of memory. |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 40 | |
| 41 | So, let's look at an example of a wrapper for a system call which |
| 42 | should be familiar to many Unix programmers. |
| 43 | |
| 44 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 45 | The syscall wrapper for time() |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 46 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 47 | Removing the debug printing clutter, it looks like this: |
| 48 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 49 | case __NR_time: /* syscall 13 */ |
| 50 | /* time_t time(time_t *t); */ |
| 51 | if (arg1 != (UInt)NULL) { |
| 52 | SYSCALL_TRACK( pre_mem_write, tst, "time", arg1, sizeof(time_t) ); |
| 53 | } |
| 54 | KERNEL_DO_SYSCALL(tid,res); |
| 55 | if (!VG_(is_kerror)(res) && arg1 != (UInt)NULL) { |
| 56 | VG_TRACK( post_mem_write, arg1, sizeof(time_t) ); |
| 57 | } |
| 58 | break; |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 59 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 60 | The first thing we do is, if a non-NULL buffer is passed in as the argument, |
| 61 | tell the skin that the buffer is about to be written to: |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 62 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 63 | if (arg1 != (UInt)NULL) { |
| 64 | SYSCALL_TRACK( pre_mem_write, tst, "time", arg1, sizeof(time_t) ); |
| 65 | } |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 66 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 67 | Now Valgrind asks the kernel to actally do the system call, for the thread |
| 68 | identified by thread ID "tid", depositing the return value in "res": |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 69 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 70 | KERNEL_DO_SYSCALL(tid, res); |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 71 | |
| 72 | Finally, the really important bit. If, and only if, the system call |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 73 | was successful, tell the skin that the memory was written: |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 74 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 75 | if (!VG_(is_kerror)(res) && arg1 != (UInt)NULL) { |
| 76 | VG_TRACK( post_mem_write, arg1, sizeof(time_t) ); |
| 77 | } |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 78 | |
| 79 | The function VG_(is_kerror) tells you whether or not its argument |
| 80 | represents a Linux kernel return error code. Hence the test. |
| 81 | |
| 82 | |
| 83 | Writing your own syscall wrappers (see below for ioctl wrappers) |
| 84 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 85 | If Valgrind tells you that system call NNN is unimplemented, do the |
| 86 | following: |
| 87 | |
| 88 | 1. Find out the name of the system call: |
| 89 | |
| 90 | grep NNN /usr/include/asm/unistd.h |
| 91 | |
| 92 | This should tell you something like __NR_mysyscallname. |
| 93 | |
| 94 | |
| 95 | 2. Do 'man 2 mysyscallname' to get some idea of what the syscall |
| 96 | does. |
| 97 | |
| 98 | |
| 99 | 3. Add a case to the already-huge collection of wrappers in |
njn | 39209d4 | 2003-06-13 15:02:29 +0000 | [diff] [blame] | 100 | coregrind/vg_syscalls.c. For each in-memory parameter which is |
| 101 | read or written by the syscall, do one of |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 102 | |
| 103 | SYSCALL_TRACK( pre_mem_read, ... ) |
| 104 | SYSCALL_TRACK( pre_mem_read_asciiz, ... ) |
| 105 | SYSCALL_TRACK( pre_mem_write, ... ) |
| 106 | |
| 107 | for that parameter. Then do the syscall. Then, if the syscall |
| 108 | succeeds, issue suitable VG_TRACK( post_mem_write, ... ) calls. |
| 109 | (There's no need for post_mem_read calls.) |
| 110 | |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 111 | If you find this difficult, read the wrappers for other syscalls |
| 112 | for ideas. A good tip is to look for the wrapper for a syscall |
| 113 | which has a similar behaviour to yours, and use it as a |
| 114 | starting point. |
| 115 | |
| 116 | If you have to #include headers for structure definitions, |
| 117 | put your #includes into vg_unsafe.h. |
| 118 | |
| 119 | Test it. |
| 120 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 121 | Note that a common error is to call VG_TRACK( post_mem_write, ... ) |
| 122 | with 0 (NULL) as the first (address) argument. This usually means |
| 123 | your logic is slightly inadequate. It's a sufficiently common bug |
| 124 | that there's a built-in check for it, and you'll get a "probably |
| 125 | sanity check failure" for the syscall wrapper you just made, if this |
| 126 | is the case. |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 127 | |
| 128 | Note that many syscalls are bracketed by #if defined(__NR_mysyscall) |
| 129 | ... #endif, because they exist only in the 2.4 kernel and not |
| 130 | the 2.2 kernel. This enables the same piece of code to serve both |
| 131 | kernels. Please try and stick to this convention. |
| 132 | |
| 133 | |
| 134 | 4. Once happy, send me the patch. Pretty please. |
| 135 | |
| 136 | |
| 137 | |
| 138 | |
| 139 | Writing your own ioctl wrappers |
| 140 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 141 | Is pretty much the same as writing syscall wrappers. |
| 142 | |
njn | 75b31b3 | 2003-06-12 11:24:10 +0000 | [diff] [blame] | 143 | There's a default case, sometimes it isn't correct and you have to write a |
| 144 | more specific case to get the right behaviour. |
sewardj | de4a1d0 | 2002-03-22 01:27:54 +0000 | [diff] [blame] | 145 | |
| 146 | As above, please do send me the resulting patch. |
| 147 | |
| 148 | |