blob: ca2057a2db0970ee1a6db7ba4df49a988339be6c [file] [log] [blame]
sewardje663cb92002-04-12 10:26:32 +00001
2/* This is a replacement for the standard libpthread.so. It is loaded
3 as part of the client's image (if required) and directs pthread
4 calls through to Valgrind's request mechanism.
5
6 A couple of caveats.
7
8 1. Since it's a binary-compatible replacement for an existing library,
9 we must take care to used exactly the same data layouts, etc, as
10 the standard pthread.so does.
11
12 2. Since this runs as part of the client, there are no specific
13 restrictions on what headers etc we can include, so long as
14 this libpthread.so does not end up having dependencies on .so's
15 which the real one doesn't.
16
17 Later ... it appears we cannot call file-related stuff in libc here,
18 perhaps fair enough. Be careful what you call from here. Even exit()
19 doesn't work (gives infinite recursion and then stack overflow); hence
20 myexit(). Also fprintf doesn't seem safe.
21*/
22
23#include "valgrind.h" /* For the request-passing mechanism */
24#include "vg_include.h" /* For the VG_USERREQ__* constants */
25
26#include <pthread.h>
27#include <unistd.h>
28#include <string.h>
29
30
31/* ---------------------------------------------------------------------
32 Helpers. We have to be pretty self-sufficient.
33 ------------------------------------------------------------------ */
34
35static
36void myexit ( int arg )
37{
38 int __res;
39 __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
40 : "=a" (__res)
41 : "0" (__NR_exit),
42 "c" (arg) );
43 /* We don't bother to mention the fact that this asm trashes %ebx,
44 since it won't return. If you ever do let it return ... fix
45 this! */
46}
47
48
49/* Give up without using printf etc, since they seem to give
50 segfaults. */
51static
52void ensure_valgrind ( char* caller )
53{
54 char* str;
55 int is_valgrind = RUNNING_ON_VALGRIND;
56 if (!is_valgrind) {
57 str = "\nvalgrind-ed process: vg_libpthread.so: "
58 "pthread call when\n";
59 write(2, str, strlen(str));
60 str = "not running on valgrind; aborting! "
61 "This is probably a bug in\n";
62 write(2, str, strlen(str));
63 str = "valgrind. Please report it to me at: "
64 "jseward@acm.org. Thanks.\n";
65 write(2, str, strlen(str));
66 str = "unexpectedly called function is: ";
67 write(2, str, strlen(str));
68 write(2, caller, strlen(caller));
69 str = "\n\n";
70 write(2, str, strlen(str));
71 myexit(1);
72 }
73}
74
75
76static
77void barf ( char* str )
78{
79 char buf[100];
80 buf[0] = 0;
81 strcat(buf, "\nvg_libpthread.so: ");
82 strcat(buf, str);
83 strcat(buf, "\n\n");
84 write(2, buf, strlen(buf));
85 myexit(1);
86}
87
88
89
90/* ---------------------------------------------------------------------
91 Pass pthread_ calls to Valgrind's request mechanism.
92 ------------------------------------------------------------------ */
93
94int
95pthread_create (pthread_t *__restrict __thread,
96 __const pthread_attr_t *__restrict __attr,
97 void *(*__start_routine) (void *),
98 void *__restrict __arg)
99{
100 int res;
101 ensure_valgrind("pthread_create");
102 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
103 VG_USERREQ__PTHREAD_CREATE,
104 __thread, __attr, __start_routine, __arg);
105 return res;
106}
107
108
109
110int
111pthread_join (pthread_t __th, void **__thread_return)
112{
113 int res;
114 ensure_valgrind("pthread_join");
115 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
116 VG_USERREQ__PTHREAD_JOIN,
117 __th, __thread_return, 0, 0);
118 return res;
119}
120
121
122/* What are these? Anybody know? I don't. */
123
124void _pthread_cleanup_push_defer ( void )
125{
126 // char* str = "_pthread_cleanup_push_defer\n";
127 // write(2, str, strlen(str));
128}
129
130void _pthread_cleanup_pop_restore ( void )
131{
132 // char* str = "_pthread_cleanup_pop_restore\n";
133 // write(2, str, strlen(str));
134}
135
136
137static int thread_specific_errno[VG_N_THREADS];
138
139int* __errno_location ( void )
140{
141 int tid;
142 ensure_valgrind("__errno_location");
143 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
144 VG_USERREQ__PTHREAD_GET_THREADID,
145 0, 0, 0, 0);
146 /* 'cos I'm paranoid ... */
147 if (tid < 0 || tid >= VG_N_THREADS)
148 barf("__errno_location: invalid ThreadId");
149 return & thread_specific_errno[tid];
150}
151
152
153int pthread_mutexattr_init(pthread_mutexattr_t *attr)
154{
sewardj8937c812002-04-12 20:12:20 +0000155 char* str = "IGNORED pthread_mutexattr_init\n";
156 write(2, str, strlen(str));
157 return 0;
sewardje663cb92002-04-12 10:26:32 +0000158}
159
160int pthread_mutex_init(pthread_mutex_t *mutex,
161 const pthread_mutexattr_t *mutexattr)
162{
163 int res;
sewardj8937c812002-04-12 20:12:20 +0000164 // char* str = "pthread_mutex_init\n";
165 // write(2, str, strlen(str));
sewardje663cb92002-04-12 10:26:32 +0000166 ensure_valgrind("pthread_mutex_init");
167 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
168 VG_USERREQ__PTHREAD_MUTEX_INIT,
169 mutex, mutexattr, 0, 0);
170 return res;
171}
172
173int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
174{
sewardj8937c812002-04-12 20:12:20 +0000175 char* str = "IGNORED pthread_mutexattr_destroy\n";
sewardje663cb92002-04-12 10:26:32 +0000176 write(2, str, strlen(str));
177 return 0;
178}
179
180int pthread_mutex_lock(pthread_mutex_t *mutex)
181{
182 int res;
183 if (!(RUNNING_ON_VALGRIND)) {
184 char* str = "pthread_mutex_lock-NOT-INSIDE-VALGRIND\n";
185 write(2, str, strlen(str));
186 return 0;
187 } else {
188 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
189 VG_USERREQ__PTHREAD_MUTEX_LOCK,
190 mutex, 0, 0, 0);
191 return res;
192 }
193}
194
195int pthread_mutex_unlock(pthread_mutex_t *mutex)
196{
197 int res;
198 if (!(RUNNING_ON_VALGRIND)) {
199 char* str = "pthread_mutex_unlock-NOT-INSIDE-VALGRIND\n";
200 write(2, str, strlen(str));
201 return 0;
202 } else {
203 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
204 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
205 mutex, 0, 0, 0);
206 return res;
207 }
208}
209
210pthread_t pthread_self(void)
211{
212 int tid;
213 ensure_valgrind("pthread_self");
214 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
215 VG_USERREQ__PTHREAD_GET_THREADID,
216 0, 0, 0, 0);
217 if (tid < 0 || tid >= VG_N_THREADS)
218 barf("pthread_self: invalid ThreadId");
219 return tid;
220}
221
222int pthread_mutex_destroy(pthread_mutex_t *mutex)
223{
224 int res;
225 if (!(RUNNING_ON_VALGRIND)) {
226 char* str = "pthread_mutex_destroy-NOT-INSIDE-VALGRIND\n";
227 write(2, str, strlen(str));
228 return 0;
229 } else {
230 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
231 VG_USERREQ__PTHREAD_MUTEX_DESTROY,
232 mutex, 0, 0, 0);
233 }
234 return res;
235}
236
237
238int pthread_setcanceltype(int type, int *oldtype)
239{
sewardj8937c812002-04-12 20:12:20 +0000240 char* str = "IGNORED pthread_setcanceltype\n";
sewardje663cb92002-04-12 10:26:32 +0000241 write(2, str, strlen(str));
242 return 0;
243}
244
245
246int pthread_cancel(pthread_t thread)
247{
248 int res;
249 ensure_valgrind("pthread_cancel");
250 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
251 VG_USERREQ__PTHREAD_CANCEL,
252 thread, 0, 0, 0);
253 return res;
254}
255
256
257/* ---------------------------------------------------------------------
258 These are here (I think) because they are deemed cancellation
259 points by POSIX. For the moment we'll simply pass the call along
260 to the corresponding thread-unaware (?) libc routine.
261 ------------------------------------------------------------------ */
262
263#include <stdio.h>
264#include <stdlib.h>
265#include <signal.h>
266#include <errno.h>
267#include <sys/types.h>
268#include <sys/socket.h>
269
270extern
271int __libc_sigaction
272 (int signum,
273 const struct sigaction *act,
274 struct sigaction *oldact);
275int sigaction(int signum,
276 const struct sigaction *act,
277 struct sigaction *oldact)
278{
279 // char* str = "sigaction\n";
280 // write(2, str, strlen(str));
281 return __libc_sigaction(signum, act, oldact);
282}
283
284
285extern
286int __libc_connect(int sockfd,
287 const struct sockaddr *serv_addr,
288 socklen_t addrlen);
289int connect(int sockfd,
290 const struct sockaddr *serv_addr,
291 socklen_t addrlen)
292{
293 // char* str = "connect\n";
294 // write(2, str, strlen(str));
295 return __libc_connect(sockfd, serv_addr, addrlen);
296}
297
298
299extern
300int __libc_fcntl(int fd, int cmd, long arg);
301int fcntl(int fd, int cmd, long arg)
302{
303 // char* str = "fcntl\n";
304 // write(2, str, strlen(str));
305 return __libc_fcntl(fd, cmd, arg);
306}
307
308
309extern
310ssize_t __libc_write(int fd, const void *buf, size_t count);
311ssize_t write(int fd, const void *buf, size_t count)
312{
313 // char* str = "write\n";
314 // write(2, str, strlen(str));
315 return __libc_write(fd, buf, count);
316}
317
318
319extern
320ssize_t __libc_read(int fd, void *buf, size_t count);
321ssize_t read(int fd, void *buf, size_t count)
322{
323 // char* str = "read\n";
324 // write(2, str, strlen(str));
325 return __libc_read(fd, buf, count);
326}
327
328
329extern
330int __libc_open(const char *pathname, int flags);
331int open(const char *pathname, int flags)
332{
333 // char* str = "open\n";
334 // write(2, str, strlen(str));
335 return __libc_open(pathname, flags);
336}
337
338
339extern
340int __libc_close(int fd);
341int close(int fd)
342{
343 // char* str = "open\n";
344 // write(2, str, strlen(str));
345 return __libc_close(fd);
346}
347
348
349extern
350int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
351int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
352{
353 // char* str = "accept\n";
354 // write(2, str, strlen(str));
355 return __libc_accept(s, addr, addrlen);
356}
357
358
359extern
360pid_t __libc_fork(void);
361pid_t fork(void)
362{
363 // char* str = "fork\n";
364 // write(2, str, strlen(str));
365 return __libc_fork();
366}
367
368
369extern
370pid_t __libc_waitpid(pid_t pid, int *status, int options);
371pid_t waitpid(pid_t pid, int *status, int options)
372{
373 // char* str = "waitpid\n";
374 // write(2, str, strlen(str));
375 return __libc_waitpid(pid, status, options);
376}
377
378
379extern
380int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
381int nanosleep(const struct timespec *req, struct timespec *rem)
382{
383 return __libc_nanosleep(req, rem);
384}
385
386extern
387int __libc_fsync(int fd);
388int fsync(int fd)
389{
390 return __libc_fsync(fd);
391}
392
393/* I've no idea what these are, but they get called quite a lot.
394 Anybody know? */
395
396#undef _IO_flockfile
397void _IO_flockfile ( _IO_FILE * file )
398{
399 // char* str = "_IO_flockfile\n";
400 // write(2, str, strlen(str));
401 // barf("_IO_flockfile");
402}
403
404#undef _IO_funlockfile
405void _IO_funlockfile ( _IO_FILE * file )
406{
407 // char* str = "_IO_funlockfile\n";
408 // write(2, str, strlen(str));
409 //barf("_IO_funlockfile");
410}
411