blob: 88f97cda7a2d46be29d3c21c440efb397b144f25 [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
sewardj5e5fa512002-04-14 13:13:05 +0000257
258int pthread_key_create(pthread_key_t *key,
259 void (*destr_function) (void *))
260{
261 char* str = "IGNORED pthread_key_create\n";
262 write(2, str, strlen(str));
263 return 0;
264}
265
266int pthread_key_delete(pthread_key_t key)
267{
268 char* str = "IGNORED pthread_key_delete\n";
269 write(2, str, strlen(str));
270 return 0;
271}
272
273int pthread_setspecific(pthread_key_t key, const void *pointer)
274{
275 char* str = "IGNORED pthread_setspecific\n";
276 write(2, str, strlen(str));
277 return 0;
278}
279
280void * pthread_getspecific(pthread_key_t key)
281{
282 char* str = "IGNORED pthread_setspecific\n";
283 write(2, str, strlen(str));
284 return NULL;
285}
286
sewardje663cb92002-04-12 10:26:32 +0000287/* ---------------------------------------------------------------------
288 These are here (I think) because they are deemed cancellation
289 points by POSIX. For the moment we'll simply pass the call along
290 to the corresponding thread-unaware (?) libc routine.
291 ------------------------------------------------------------------ */
292
293#include <stdio.h>
294#include <stdlib.h>
295#include <signal.h>
296#include <errno.h>
297#include <sys/types.h>
298#include <sys/socket.h>
299
300extern
301int __libc_sigaction
302 (int signum,
303 const struct sigaction *act,
304 struct sigaction *oldact);
305int sigaction(int signum,
306 const struct sigaction *act,
307 struct sigaction *oldact)
308{
309 // char* str = "sigaction\n";
310 // write(2, str, strlen(str));
311 return __libc_sigaction(signum, act, oldact);
312}
313
314
315extern
316int __libc_connect(int sockfd,
317 const struct sockaddr *serv_addr,
318 socklen_t addrlen);
319int connect(int sockfd,
320 const struct sockaddr *serv_addr,
321 socklen_t addrlen)
322{
323 // char* str = "connect\n";
324 // write(2, str, strlen(str));
325 return __libc_connect(sockfd, serv_addr, addrlen);
326}
327
328
329extern
330int __libc_fcntl(int fd, int cmd, long arg);
331int fcntl(int fd, int cmd, long arg)
332{
333 // char* str = "fcntl\n";
334 // write(2, str, strlen(str));
335 return __libc_fcntl(fd, cmd, arg);
336}
337
338
339extern
340ssize_t __libc_write(int fd, const void *buf, size_t count);
341ssize_t write(int fd, const void *buf, size_t count)
342{
343 // char* str = "write\n";
344 // write(2, str, strlen(str));
345 return __libc_write(fd, buf, count);
346}
347
348
349extern
350ssize_t __libc_read(int fd, void *buf, size_t count);
351ssize_t read(int fd, void *buf, size_t count)
352{
353 // char* str = "read\n";
354 // write(2, str, strlen(str));
355 return __libc_read(fd, buf, count);
356}
357
358
359extern
360int __libc_open(const char *pathname, int flags);
361int open(const char *pathname, int flags)
362{
363 // char* str = "open\n";
364 // write(2, str, strlen(str));
365 return __libc_open(pathname, flags);
366}
367
368
369extern
370int __libc_close(int fd);
371int close(int fd)
372{
373 // char* str = "open\n";
374 // write(2, str, strlen(str));
375 return __libc_close(fd);
376}
377
378
379extern
380int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
381int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
382{
383 // char* str = "accept\n";
384 // write(2, str, strlen(str));
385 return __libc_accept(s, addr, addrlen);
386}
387
388
389extern
390pid_t __libc_fork(void);
391pid_t fork(void)
392{
393 // char* str = "fork\n";
394 // write(2, str, strlen(str));
395 return __libc_fork();
396}
397
398
399extern
400pid_t __libc_waitpid(pid_t pid, int *status, int options);
401pid_t waitpid(pid_t pid, int *status, int options)
402{
403 // char* str = "waitpid\n";
404 // write(2, str, strlen(str));
405 return __libc_waitpid(pid, status, options);
406}
407
408
409extern
410int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
411int nanosleep(const struct timespec *req, struct timespec *rem)
412{
413 return __libc_nanosleep(req, rem);
414}
415
416extern
417int __libc_fsync(int fd);
418int fsync(int fd)
419{
420 return __libc_fsync(fd);
421}
422
sewardj70c75362002-04-13 04:18:32 +0000423extern
424off_t __libc_lseek(int fildes, off_t offset, int whence);
425off_t lseek(int fildes, off_t offset, int whence)
426{
427 return __libc_lseek(fildes, offset, whence);
428}
429
430/*--------------------------------------------------*/
431
sewardje663cb92002-04-12 10:26:32 +0000432/* I've no idea what these are, but they get called quite a lot.
433 Anybody know? */
434
435#undef _IO_flockfile
436void _IO_flockfile ( _IO_FILE * file )
437{
438 // char* str = "_IO_flockfile\n";
439 // write(2, str, strlen(str));
440 // barf("_IO_flockfile");
441}
442
443#undef _IO_funlockfile
444void _IO_funlockfile ( _IO_FILE * file )
445{
446 // char* str = "_IO_funlockfile\n";
447 // write(2, str, strlen(str));
448 //barf("_IO_funlockfile");
449}
450
sewardj08a4c3f2002-04-13 03:45:44 +0000451/*--------------------------------------------------*/
452
453#include "vg_kerneliface.h"
454
455static
456__inline__
457int is_kerror ( int res )
458{
459 if (res >= -4095 && res <= -1)
460 return 1;
461 else
462 return 0;
463}
464
465
466static
467int my_do_syscall1 ( int syscallno, int arg1 )
468{
469 int __res;
470 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
471 : "=a" (__res)
472 : "0" (syscallno),
473 "d" (arg1) );
474 return __res;
475}
476
477static
478int my_do_syscall2 ( int syscallno,
479 int arg1, int arg2 )
480{
481 int __res;
482 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
483 : "=a" (__res)
484 : "0" (syscallno),
485 "d" (arg1),
486 "c" (arg2) );
487 return __res;
488}
489
490static
491int do_syscall_select( int n,
492 vki_fd_set* readfds,
493 vki_fd_set* writefds,
494 vki_fd_set* exceptfds,
495 struct vki_timeval * timeout )
496{
497 int res;
498 int args[5];
499 args[0] = n;
500 args[1] = (int)readfds;
501 args[2] = (int)writefds;
502 args[3] = (int)exceptfds;
503 args[4] = (int)timeout;
504 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
505 if (is_kerror(res)) {
506 * (__errno_location()) = -res;
507 return -1;
508 } else {
509 return res;
510 }
511}
512
513
514/* This is a wrapper round select(), which makes it thread-safe,
515 meaning that only this thread will block, rather than the entire
516 process. This wrapper in turn depends on nanosleep() not to block
517 the entire process, but I think (hope? suspect?) that POSIX
518 pthreads guarantees that to be the case.
519
520 Basic idea is: modify the timeout parameter to select so that it
521 returns immediately. Poll like this until select returns non-zero,
522 indicating something interesting happened, or until our time is up.
523 Space out the polls with nanosleeps of say 20 milliseconds, which
524 is required to be nonblocking; this allows other threads to run.
525*/
526#include <assert.h>
527
528
529int select ( int n,
530 fd_set *rfds,
531 fd_set *wfds,
532 fd_set *xfds,
533 struct timeval *timeout )
534{
535 int res;
536 fd_set rfds_copy;
537 fd_set wfds_copy;
538 fd_set xfds_copy;
539 struct vki_timeval t_now;
540 struct vki_timeval t_end;
541 struct vki_timeval zero_timeout;
542 struct vki_timespec nanosleep_interval;
543
544 ensure_valgrind("select");
545
546 /* We assume that the kernel and libc data layouts are identical
547 for the following types. These asserts provide a crude
548 check. */
549 if (sizeof(fd_set) != sizeof(vki_fd_set)
550 || sizeof(struct timeval) != sizeof(struct vki_timeval))
551 barf("valgrind's hacky non-blocking select(): data sizes error");
552
553 /* If a zero timeout specified, this call is harmless. */
554 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
555 return do_syscall_select( n, (vki_fd_set*)rfds,
556 (vki_fd_set*)wfds,
557 (vki_fd_set*)xfds,
558 (struct vki_timeval*)timeout);
559
560 /* If a timeout was specified, set t_end to be the end wallclock
561 time. */
562 if (timeout) {
563 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
564 assert(res == 0);
565 t_end = t_now;
566 t_end.tv_usec += timeout->tv_usec;
567 t_end.tv_sec += timeout->tv_sec;
568 if (t_end.tv_usec >= 1000000) {
569 t_end.tv_usec -= 1000000;
570 t_end.tv_sec += 1;
571 }
572 /* Stay sane ... */
573 assert (t_end.tv_sec > t_now.tv_sec
574 || (t_end.tv_sec == t_now.tv_sec
575 && t_end.tv_usec >= t_now.tv_usec));
576 }
577
578 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
579
580 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
581 NULL, in which case t_end holds the end time. */
582 while (1) {
583 if (timeout) {
584 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
585 assert(res == 0);
586 if (t_now.tv_sec > t_end.tv_sec
587 || (t_now.tv_sec == t_end.tv_sec
588 && t_now.tv_usec > t_end.tv_usec)) {
589 /* timeout; nothing interesting happened. */
590 if (rfds) FD_ZERO(rfds);
591 if (wfds) FD_ZERO(wfds);
592 if (xfds) FD_ZERO(xfds);
593 return 0;
594 }
595 }
596
597 /* These could be trashed each time round the loop, so restore
598 them each time. */
599 if (rfds) rfds_copy = *rfds;
600 if (wfds) wfds_copy = *wfds;
601 if (xfds) xfds_copy = *xfds;
602
603 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
604
605 res = do_syscall_select( n,
606 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
607 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
608 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
609 & zero_timeout );
610 if (res < 0) {
611 /* some kind of error (including EINTR); errno is set, so just
612 return. The sets are unspecified in this case. */
613 return res;
614 }
615 if (res > 0) {
616 /* one or more fds is ready. Copy out resulting sets and
617 return. */
618 if (rfds) *rfds = rfds_copy;
619 if (wfds) *wfds = wfds_copy;
620 if (xfds) *xfds = xfds_copy;
621 return res;
622 }
623 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
624 /* nanosleep and go round again */
625 nanosleep_interval.tv_sec = 0;
626 nanosleep_interval.tv_nsec = 20 * 1000 * 1000; /* 20 milliseconds */
627 /* It's critical here that valgrind's nanosleep implementation
628 is nonblocking. */
629 (void)my_do_syscall2(__NR_nanosleep,
630 (int)(&nanosleep_interval), (int)NULL);
631 }
632}