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 | |
| 15 | All this machinery is in vg_syscall_mem.c. |
| 16 | |
| 17 | |
| 18 | What are syscall/ioctl wrappers? What do they do? |
| 19 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 20 | Valgrind does what it does, in part, by keeping track of the status of |
| 21 | all bytes of memory accessible by your program. When a system call |
| 22 | happens, for example a request to read part of a file, control passes |
| 23 | to the Linux kernel, which fulfills the request, and returns control |
| 24 | to your program. The problem is that the kernel will often change the |
| 25 | status of some part of your program's memory as a result. |
| 26 | |
| 27 | The job of syscall and ioctl wrappers is to spot such system calls, |
| 28 | and update Valgrind's memory status maps accordingly. This is |
| 29 | essential, because not doing so would cause you to be flooded with |
| 30 | errors later on, and, in general, because it's important that |
| 31 | Valgrind's idea of accessible memory corresponds to that of the Linux |
| 32 | kernel's. And for other reasons too. |
| 33 | |
| 34 | In addition, Valgrind takes the opportunity to perform some sanity |
| 35 | checks on the parameters you are presenting to system calls. This |
| 36 | isn't essential for the correct operation of Valgrind, but it does |
| 37 | allow it to warn you about various kinds of misuses which would |
| 38 | otherwise mean your program just dies without warning, usually with a |
| 39 | segmentation fault. |
| 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 | |
| 45 | The syscall wrapper for read() |
| 46 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 47 | Removing the debug printing clutter, it looks like this: |
| 48 | |
| 49 | case __NR_read: /* syscall 3 */ |
| 50 | /* size_t read(int fd, void *buf, size_t count); */ |
| 51 | must_be_writable( "read(buf)", arg2, arg3 ); |
| 52 | KERNEL_DO_SYSCALL(res); |
| 53 | if (!VG_(is_kerror)(res) && res > 0) { |
| 54 | make_readable( arg2, res ); |
| 55 | } |
| 56 | break; |
| 57 | |
| 58 | The first thing we do is check that the buffer, which you planned to |
| 59 | have the result written to, really is addressible ("writable", here). |
| 60 | Hence: |
| 61 | |
| 62 | must_be_writable( "read(buf)", arg2, arg3 ); |
| 63 | |
| 64 | which causes Valgrind to issue a warning if the address range |
| 65 | [arg2 .. arg2 + arg3 - 1] is not writable. This is one of those |
| 66 | nice-to-have-but-not-essential checks mentioned above. Note that |
| 67 | the syscall args are always called arg1, arg2, arg3, etc. Here, |
| 68 | arg1 corresponds to "fd" in the prototype, arg2 to "buf", and arg3 |
| 69 | to "count". |
| 70 | |
| 71 | Now Valgrind asks the kernel to do the system call, depositing the |
| 72 | return code in "res": |
| 73 | |
| 74 | KERNEL_DO_SYSCALL(res); |
| 75 | |
| 76 | Finally, the really important bit. If, and only if, the system call |
| 77 | was successful, mark the buffer as readable (ie, as having valid |
| 78 | data), for as many bytes as were actually read: |
| 79 | |
| 80 | if (!VG_(is_kerror)(res) && res > 0) { |
| 81 | make_readable( arg2, res ); |
| 82 | } |
| 83 | |
| 84 | The function VG_(is_kerror) tells you whether or not its argument |
| 85 | represents a Linux kernel return error code. Hence the test. |
| 86 | |
| 87 | |
| 88 | Writing your own syscall wrappers (see below for ioctl wrappers) |
| 89 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 90 | If Valgrind tells you that system call NNN is unimplemented, do the |
| 91 | following: |
| 92 | |
| 93 | 1. Find out the name of the system call: |
| 94 | |
| 95 | grep NNN /usr/include/asm/unistd.h |
| 96 | |
| 97 | This should tell you something like __NR_mysyscallname. |
| 98 | |
| 99 | |
| 100 | 2. Do 'man 2 mysyscallname' to get some idea of what the syscall |
| 101 | does. |
| 102 | |
| 103 | |
| 104 | 3. Add a case to the already-huge collection of wrappers in |
| 105 | vg_syscall_mem.c. For each in-memory parameter which is read |
| 106 | by the syscall, do a must_be_readable or must_be_readable_asciiz |
| 107 | on that parameter. Then do the syscall. Then, if the syscall |
| 108 | succeeds, issue suitable make_readable/writable/noaccess calls |
| 109 | afterwards, so as to update Valgrind's memory maps to reflect |
| 110 | the state change caused by the call. |
| 111 | |
| 112 | If you find this difficult, read the wrappers for other syscalls |
| 113 | for ideas. A good tip is to look for the wrapper for a syscall |
| 114 | which has a similar behaviour to yours, and use it as a |
| 115 | starting point. |
| 116 | |
| 117 | If you have to #include headers for structure definitions, |
| 118 | put your #includes into vg_unsafe.h. |
| 119 | |
| 120 | Test it. |
| 121 | |
| 122 | Note that a common error is to call make_readable or make_writable |
| 123 | with 0 (NULL) as the first (address) argument. This usually means your |
| 124 | logic is slightly inadequate. It's a sufficiently common bug that |
| 125 | there's a built-in check for it, and you'll get a "probably sanity |
| 126 | check failure" for the syscall wrapper you just made, if this is |
| 127 | the case. |
| 128 | |
| 129 | Note that many syscalls are bracketed by #if defined(__NR_mysyscall) |
| 130 | ... #endif, because they exist only in the 2.4 kernel and not |
| 131 | the 2.2 kernel. This enables the same piece of code to serve both |
| 132 | kernels. Please try and stick to this convention. |
| 133 | |
| 134 | |
| 135 | 4. Once happy, send me the patch. Pretty please. |
| 136 | |
| 137 | |
| 138 | |
| 139 | |
| 140 | Writing your own ioctl wrappers |
| 141 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 142 | Is pretty much the same as writing syscall wrappers. |
| 143 | |
| 144 | If you can't be bothered, do a cheap hack: add it (the ioctl number |
| 145 | emitted in Valgrind's panic-message) to the long list of IOCTLs which |
| 146 | are noted but not fully handled by Valgrind (search for the text |
| 147 | "noted but unhandled ioctl" in vg_syscall_mem.c). This will get you |
| 148 | going immediately, at the risk of giving you spurious value errors. |
| 149 | |
| 150 | As above, please do send me the resulting patch. |
| 151 | |
| 152 | |