summaryrefslogtreecommitdiff
path: root/README_MISSING_SYSCALL_OR_IOCTL
blob: 5488f59218de5ff11ce18e0a18d852b6123c4027 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170

Dealing with missing system call or ioctl wrappers in Valgrind
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You're probably reading this because Valgrind bombed out whilst
running your program, and advised you to read this file.  The good
news is that, in general, it's easy to write the missing syscall or
ioctl wrappers you need, so that you can continue your debugging.  If
you send the resulting patches to me, then you'll be doing a favour to
all future Valgrind users too.

Note that an "ioctl" is just a special kind of system call, really; so
there's not a lot of need to distinguish them (at least conceptually)
in the discussion that follows.

All this machinery is in coregrind/vg_syscalls.c.


What are syscall/ioctl wrappers?  What do they do?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Valgrind does what it does, in part, by keeping track of everything your
program does.  When a system call happens, for example a request to read
part of a file, control passes to the Linux kernel, which fulfills the
request, and returns control to your program.  The problem is that the
kernel will often change the status of some part of your program's memory
as a result, and tools (instrumentation plug-ins) may need to know about
this.

Syscall and ioctl wrappers have two jobs: 

1. Tell a tool what's about to happen, before the syscall takes place.  A
   tool could perform checks beforehand, eg. if memory about to be written
   is actually writeable.  This part is useful, but not strictly
   essential.

2. Tell a tool what just happened, after a syscall takes place.  This is
   so it can update its view of the program's state, eg. that memory has
   just been written to.  This step is essential.

The "happenings" mostly involve reading/writing of memory.

So, let's look at an example of a wrapper for a system call which
should be familiar to many Unix programmers.


The syscall wrapper for time()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Removing the debug printing clutter, it looks like this:

  PRE(time)
  {
     /* time_t time(time_t *t); */
     PRINT("time ( %p )",arg1);
     if (arg1 != (UWord)NULL) {
        PRE_MEM_WRITE( "time", arg1, sizeof(time_t) );
     }
  }

  POST(time)
  {  
     if (arg1 != (UWord)NULL) {
        POST_MEM_WRITE( arg1, sizeof(vki_time_t) );
     }
  }

The first thing we do happens before the syscall occurs, in the PRE() function:
if a non-NULL buffer is passed in as the argument, tell the tool that the
buffer is about to be written to:

     if (arg1 != (UWord)NULL) {
        PRE_MEM_WRITE( "time", arg1, sizeof(vki_time_t) );
     }

Finally, the really important bit, after the syscall occurs, in the POST()
function:  if, and only if, the system call was successful, tell the tool that
the memory was written:

     if (arg1 != (UInt)NULL) {
        POST_MEM_WRITE( arg1, sizeof(vki_time_t) );
     }

The POST() function won't be called if the syscall failed, so you
don't need to worry about checking that in the POST() function.
(Note: this is sometimes a bug; some syscalls do return results when
they "fail" - for example, nanosleep returns the amount of unslept
time if interrupted. TODO: add another per-syscall flag for this
case.)

Note that we use the type 'vki_time_t'.  This is a copy of the kernel
type, with 'vki_' prefixed.  Our copies of such types are kept in the
appropriate vki*.h file(s).  We don't include kernel headers or glibc headers
directly.


Writing your own syscall wrappers (see below for ioctl wrappers)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If Valgrind tells you that system call NNN is unimplemented, do the 
following:

1.  Find out the name of the system call:

       grep NNN /usr/include/asm/unistd.h

    This should tell you something like  __NR_mysyscallname.
    Copy this entry to coregrind/$(VG_PLATFORM)/vki_unistd.h.


2.  Do 'man 2 mysyscallname' to get some idea of what the syscall
    does.  Note that the actual kernel interface can differ from this,
    so you might also want to check a version of the Linux kernel
    source.

    NOTE: any syscall which has something to do with signals or
    threads is probably "special", and needs more careful handling.
    Post something to valgrind-developers if you aren't sure.


3.  Add a case to the already-huge collection of wrappers in 
    coregrind/vg_syscalls.c.  For each in-memory parameter which is 
    read or written by the syscall, do one of
    
      PRE_MEM_READ( ... )
      PRE_MEM_RASCIIZ( ... ) 
      PRE_MEM_WRITE( ... ) 
      
    for  that parameter.  Then do the syscall.  Then, if the syscall
    succeeds, issue suitable POST_MEM_WRITE( ... ) calls.
    (There's no need for POST_MEM_READ calls.)

    Also, add it to the sys_info[] array; use SYSBA if it requires a
    PRE() and POST() function, and SYSB_ if it only requires a PRE()
    function.  The 2nd arg of these macros indicate if the syscall
    could possibly block.
    
    If you find this difficult, read the wrappers for other syscalls
    for ideas.  A good tip is to look for the wrapper for a syscall
    which has a similar behaviour to yours, and use it as a 
    starting point.

    If you need structure definitions and/or constants for your syscall,
    copy them from the kernel headers into include/vki.h and co., with
    the appropriate vki_*/VKI_* name mangling.  Don't #include any
    kernel headers.  And certainly don't #include any glibc headers.

    Test it.

    Note that a common error is to call POST_MEM_WRITE( ... )
    with 0 (NULL) as the first (address) argument.  This usually means
    your logic is slightly inadequate.  It's a sufficiently common bug
    that there's a built-in check for it, and you'll get a "probably
    sanity check failure" for the syscall wrapper you just made, if this
    is the case.


4.  Once happy, send us the patch.  Pretty please.




Writing your own ioctl wrappers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Is pretty much the same as writing syscall wrappers, except that all
the action happens within PRE(ioctl) and POST(ioctl).

There's a default case, sometimes it isn't correct and you have to write a
more specific case to get the right behaviour.

As above, please create a bug report and attach the patch as described
on http://www.valgrind.org.