blob: ab397457de2ed08bb54093b5fcf0fb4ab33adc96 [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
sewardj2a3d28c2002-04-14 13:27:00 +000030/* ---------------------------------------------------------------------
31 Mini-configuration.
32 ------------------------------------------------------------------ */
33
34/* Set to 1 to see IGNORED debugging messages. */
sewardj6af4b5d2002-04-16 04:40:49 +000035static int show_IGNORED = 1;
sewardj2a3d28c2002-04-14 13:27:00 +000036
sewardje663cb92002-04-12 10:26:32 +000037
38/* ---------------------------------------------------------------------
39 Helpers. We have to be pretty self-sufficient.
40 ------------------------------------------------------------------ */
41
42static
43void myexit ( int arg )
44{
45 int __res;
46 __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
47 : "=a" (__res)
48 : "0" (__NR_exit),
49 "c" (arg) );
50 /* We don't bother to mention the fact that this asm trashes %ebx,
51 since it won't return. If you ever do let it return ... fix
52 this! */
53}
54
55
56/* Give up without using printf etc, since they seem to give
57 segfaults. */
58static
59void ensure_valgrind ( char* caller )
60{
61 char* str;
62 int is_valgrind = RUNNING_ON_VALGRIND;
63 if (!is_valgrind) {
64 str = "\nvalgrind-ed process: vg_libpthread.so: "
65 "pthread call when\n";
66 write(2, str, strlen(str));
67 str = "not running on valgrind; aborting! "
68 "This is probably a bug in\n";
69 write(2, str, strlen(str));
70 str = "valgrind. Please report it to me at: "
71 "jseward@acm.org. Thanks.\n";
72 write(2, str, strlen(str));
73 str = "unexpectedly called function is: ";
74 write(2, str, strlen(str));
75 write(2, caller, strlen(caller));
76 str = "\n\n";
77 write(2, str, strlen(str));
78 myexit(1);
79 }
80}
81
82
83static
84void barf ( char* str )
85{
86 char buf[100];
87 buf[0] = 0;
88 strcat(buf, "\nvg_libpthread.so: ");
89 strcat(buf, str);
90 strcat(buf, "\n\n");
91 write(2, buf, strlen(buf));
92 myexit(1);
93}
94
95
sewardj2a3d28c2002-04-14 13:27:00 +000096static void ignored ( char* msg )
97{
98 char* ig = "vg_libpthread.so: IGNORED call to: ";
99 if (!show_IGNORED) return;
100 write(2, ig, strlen(ig));
101 write(2, msg, strlen(msg));
102 ig = "\n";
103 write(2, ig, strlen(ig));
104}
105
sewardje663cb92002-04-12 10:26:32 +0000106
107/* ---------------------------------------------------------------------
108 Pass pthread_ calls to Valgrind's request mechanism.
109 ------------------------------------------------------------------ */
110
sewardj6af4b5d2002-04-16 04:40:49 +0000111int pthread_attr_init(pthread_attr_t *attr)
112{
113 ignored("pthread_attr_init");
114 return 0;
115}
116
117int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
118{
119 ignored("pthread_attr_setdetachstate");
120 return 0;
121}
122
123
sewardje663cb92002-04-12 10:26:32 +0000124int
125pthread_create (pthread_t *__restrict __thread,
126 __const pthread_attr_t *__restrict __attr,
127 void *(*__start_routine) (void *),
128 void *__restrict __arg)
129{
130 int res;
131 ensure_valgrind("pthread_create");
132 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
133 VG_USERREQ__PTHREAD_CREATE,
134 __thread, __attr, __start_routine, __arg);
135 return res;
136}
137
138
139
140int
141pthread_join (pthread_t __th, void **__thread_return)
142{
143 int res;
144 ensure_valgrind("pthread_join");
145 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
146 VG_USERREQ__PTHREAD_JOIN,
147 __th, __thread_return, 0, 0);
148 return res;
149}
150
151
152/* What are these? Anybody know? I don't. */
153
154void _pthread_cleanup_push_defer ( void )
155{
156 // char* str = "_pthread_cleanup_push_defer\n";
157 // write(2, str, strlen(str));
158}
159
160void _pthread_cleanup_pop_restore ( void )
161{
162 // char* str = "_pthread_cleanup_pop_restore\n";
163 // write(2, str, strlen(str));
164}
165
166
167static int thread_specific_errno[VG_N_THREADS];
168
169int* __errno_location ( void )
170{
171 int tid;
172 ensure_valgrind("__errno_location");
173 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
174 VG_USERREQ__PTHREAD_GET_THREADID,
175 0, 0, 0, 0);
176 /* 'cos I'm paranoid ... */
177 if (tid < 0 || tid >= VG_N_THREADS)
178 barf("__errno_location: invalid ThreadId");
179 return & thread_specific_errno[tid];
180}
181
182
183int pthread_mutexattr_init(pthread_mutexattr_t *attr)
184{
sewardj2a3d28c2002-04-14 13:27:00 +0000185 ignored("pthread_mutexattr_init");
sewardj8937c812002-04-12 20:12:20 +0000186 return 0;
sewardje663cb92002-04-12 10:26:32 +0000187}
188
189int pthread_mutex_init(pthread_mutex_t *mutex,
190 const pthread_mutexattr_t *mutexattr)
191{
192 int res;
sewardj8937c812002-04-12 20:12:20 +0000193 // char* str = "pthread_mutex_init\n";
194 // write(2, str, strlen(str));
sewardje663cb92002-04-12 10:26:32 +0000195 ensure_valgrind("pthread_mutex_init");
196 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
197 VG_USERREQ__PTHREAD_MUTEX_INIT,
198 mutex, mutexattr, 0, 0);
199 return res;
200}
201
202int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
203{
sewardj6af4b5d2002-04-16 04:40:49 +0000204 ignored("pthread_mutexattr_destroy");
205 return 0;
206}
207
208int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
209{
210 ignored("pthread_mutexattr_settype");
211 return 0;
sewardje663cb92002-04-12 10:26:32 +0000212}
213
214int pthread_mutex_lock(pthread_mutex_t *mutex)
215{
216 int res;
217 if (!(RUNNING_ON_VALGRIND)) {
218 char* str = "pthread_mutex_lock-NOT-INSIDE-VALGRIND\n";
219 write(2, str, strlen(str));
220 return 0;
221 } else {
222 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
223 VG_USERREQ__PTHREAD_MUTEX_LOCK,
224 mutex, 0, 0, 0);
225 return res;
226 }
227}
228
229int pthread_mutex_unlock(pthread_mutex_t *mutex)
230{
231 int res;
232 if (!(RUNNING_ON_VALGRIND)) {
233 char* str = "pthread_mutex_unlock-NOT-INSIDE-VALGRIND\n";
234 write(2, str, strlen(str));
235 return 0;
236 } else {
237 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
238 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
239 mutex, 0, 0, 0);
240 return res;
241 }
242}
243
244pthread_t pthread_self(void)
245{
246 int tid;
247 ensure_valgrind("pthread_self");
248 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
249 VG_USERREQ__PTHREAD_GET_THREADID,
250 0, 0, 0, 0);
251 if (tid < 0 || tid >= VG_N_THREADS)
252 barf("pthread_self: invalid ThreadId");
253 return tid;
254}
255
256int pthread_mutex_destroy(pthread_mutex_t *mutex)
257{
258 int res;
259 if (!(RUNNING_ON_VALGRIND)) {
260 char* str = "pthread_mutex_destroy-NOT-INSIDE-VALGRIND\n";
261 write(2, str, strlen(str));
262 return 0;
263 } else {
264 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
265 VG_USERREQ__PTHREAD_MUTEX_DESTROY,
266 mutex, 0, 0, 0);
267 }
268 return res;
269}
270
271
272int pthread_setcanceltype(int type, int *oldtype)
273{
sewardj2a3d28c2002-04-14 13:27:00 +0000274 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000275 return 0;
276}
277
278
279int pthread_cancel(pthread_t thread)
280{
281 int res;
282 ensure_valgrind("pthread_cancel");
283 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
284 VG_USERREQ__PTHREAD_CANCEL,
285 thread, 0, 0, 0);
286 return res;
287}
288
289
sewardj5e5fa512002-04-14 13:13:05 +0000290
291int pthread_key_create(pthread_key_t *key,
292 void (*destr_function) (void *))
293{
sewardj2a3d28c2002-04-14 13:27:00 +0000294 ignored("pthread_key_create");
sewardj5e5fa512002-04-14 13:13:05 +0000295 return 0;
296}
297
298int pthread_key_delete(pthread_key_t key)
299{
sewardj2a3d28c2002-04-14 13:27:00 +0000300 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000301 return 0;
302}
303
304int pthread_setspecific(pthread_key_t key, const void *pointer)
305{
sewardj2a3d28c2002-04-14 13:27:00 +0000306 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000307 return 0;
308}
309
310void * pthread_getspecific(pthread_key_t key)
311{
sewardj2a3d28c2002-04-14 13:27:00 +0000312 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000313 return NULL;
314}
315
sewardje663cb92002-04-12 10:26:32 +0000316/* ---------------------------------------------------------------------
317 These are here (I think) because they are deemed cancellation
318 points by POSIX. For the moment we'll simply pass the call along
319 to the corresponding thread-unaware (?) libc routine.
320 ------------------------------------------------------------------ */
321
322#include <stdio.h>
323#include <stdlib.h>
324#include <signal.h>
325#include <errno.h>
326#include <sys/types.h>
327#include <sys/socket.h>
328
329extern
330int __libc_sigaction
331 (int signum,
332 const struct sigaction *act,
333 struct sigaction *oldact);
334int sigaction(int signum,
335 const struct sigaction *act,
336 struct sigaction *oldact)
337{
338 // char* str = "sigaction\n";
339 // write(2, str, strlen(str));
340 return __libc_sigaction(signum, act, oldact);
341}
342
343
344extern
345int __libc_connect(int sockfd,
346 const struct sockaddr *serv_addr,
347 socklen_t addrlen);
348int connect(int sockfd,
349 const struct sockaddr *serv_addr,
350 socklen_t addrlen)
351{
352 // char* str = "connect\n";
353 // write(2, str, strlen(str));
354 return __libc_connect(sockfd, serv_addr, addrlen);
355}
356
357
358extern
359int __libc_fcntl(int fd, int cmd, long arg);
360int fcntl(int fd, int cmd, long arg)
361{
362 // char* str = "fcntl\n";
363 // write(2, str, strlen(str));
364 return __libc_fcntl(fd, cmd, arg);
365}
366
367
368extern
369ssize_t __libc_write(int fd, const void *buf, size_t count);
370ssize_t write(int fd, const void *buf, size_t count)
371{
372 // char* str = "write\n";
373 // write(2, str, strlen(str));
374 return __libc_write(fd, buf, count);
375}
376
377
378extern
379ssize_t __libc_read(int fd, void *buf, size_t count);
380ssize_t read(int fd, void *buf, size_t count)
381{
382 // char* str = "read\n";
383 // write(2, str, strlen(str));
384 return __libc_read(fd, buf, count);
385}
386
387
388extern
389int __libc_open(const char *pathname, int flags);
390int open(const char *pathname, int flags)
391{
392 // char* str = "open\n";
393 // write(2, str, strlen(str));
394 return __libc_open(pathname, flags);
395}
396
397
398extern
399int __libc_close(int fd);
400int close(int fd)
401{
402 // char* str = "open\n";
403 // write(2, str, strlen(str));
404 return __libc_close(fd);
405}
406
407
408extern
409int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
410int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
411{
412 // char* str = "accept\n";
413 // write(2, str, strlen(str));
414 return __libc_accept(s, addr, addrlen);
415}
416
417
418extern
419pid_t __libc_fork(void);
420pid_t fork(void)
421{
422 // char* str = "fork\n";
423 // write(2, str, strlen(str));
424 return __libc_fork();
425}
426
427
428extern
429pid_t __libc_waitpid(pid_t pid, int *status, int options);
430pid_t waitpid(pid_t pid, int *status, int options)
431{
432 // char* str = "waitpid\n";
433 // write(2, str, strlen(str));
434 return __libc_waitpid(pid, status, options);
435}
436
437
438extern
439int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
440int nanosleep(const struct timespec *req, struct timespec *rem)
441{
442 return __libc_nanosleep(req, rem);
443}
444
445extern
446int __libc_fsync(int fd);
447int fsync(int fd)
448{
449 return __libc_fsync(fd);
450}
451
sewardj70c75362002-04-13 04:18:32 +0000452extern
453off_t __libc_lseek(int fildes, off_t offset, int whence);
454off_t lseek(int fildes, off_t offset, int whence)
455{
456 return __libc_lseek(fildes, offset, whence);
457}
458
sewardj6af4b5d2002-04-16 04:40:49 +0000459extern
460void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
461void longjmp(jmp_buf env, int val)
462{
463 __libc_longjmp(env, val);
464}
465
466extern
467int __libc_send(int s, const void *msg, size_t len, int flags);
468int send(int s, const void *msg, size_t len, int flags)
469{
470 return __libc_send(s, msg, len, flags);
471}
472
sewardj70c75362002-04-13 04:18:32 +0000473/*--------------------------------------------------*/
474
sewardje663cb92002-04-12 10:26:32 +0000475/* I've no idea what these are, but they get called quite a lot.
476 Anybody know? */
477
478#undef _IO_flockfile
479void _IO_flockfile ( _IO_FILE * file )
480{
481 // char* str = "_IO_flockfile\n";
482 // write(2, str, strlen(str));
483 // barf("_IO_flockfile");
484}
485
486#undef _IO_funlockfile
487void _IO_funlockfile ( _IO_FILE * file )
488{
489 // char* str = "_IO_funlockfile\n";
490 // write(2, str, strlen(str));
491 //barf("_IO_funlockfile");
492}
493
sewardj08a4c3f2002-04-13 03:45:44 +0000494/*--------------------------------------------------*/
495
496#include "vg_kerneliface.h"
497
498static
499__inline__
500int is_kerror ( int res )
501{
502 if (res >= -4095 && res <= -1)
503 return 1;
504 else
505 return 0;
506}
507
508
509static
510int my_do_syscall1 ( int syscallno, int arg1 )
511{
512 int __res;
513 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
514 : "=a" (__res)
515 : "0" (syscallno),
516 "d" (arg1) );
517 return __res;
518}
519
520static
521int my_do_syscall2 ( int syscallno,
522 int arg1, int arg2 )
523{
524 int __res;
525 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
526 : "=a" (__res)
527 : "0" (syscallno),
528 "d" (arg1),
529 "c" (arg2) );
530 return __res;
531}
532
533static
534int do_syscall_select( int n,
535 vki_fd_set* readfds,
536 vki_fd_set* writefds,
537 vki_fd_set* exceptfds,
538 struct vki_timeval * timeout )
539{
540 int res;
541 int args[5];
542 args[0] = n;
543 args[1] = (int)readfds;
544 args[2] = (int)writefds;
545 args[3] = (int)exceptfds;
546 args[4] = (int)timeout;
547 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
548 if (is_kerror(res)) {
549 * (__errno_location()) = -res;
550 return -1;
551 } else {
552 return res;
553 }
554}
555
556
557/* This is a wrapper round select(), which makes it thread-safe,
558 meaning that only this thread will block, rather than the entire
559 process. This wrapper in turn depends on nanosleep() not to block
560 the entire process, but I think (hope? suspect?) that POSIX
561 pthreads guarantees that to be the case.
562
563 Basic idea is: modify the timeout parameter to select so that it
564 returns immediately. Poll like this until select returns non-zero,
565 indicating something interesting happened, or until our time is up.
566 Space out the polls with nanosleeps of say 20 milliseconds, which
567 is required to be nonblocking; this allows other threads to run.
568*/
569#include <assert.h>
570
571
572int select ( int n,
573 fd_set *rfds,
574 fd_set *wfds,
575 fd_set *xfds,
576 struct timeval *timeout )
577{
578 int res;
579 fd_set rfds_copy;
580 fd_set wfds_copy;
581 fd_set xfds_copy;
582 struct vki_timeval t_now;
583 struct vki_timeval t_end;
584 struct vki_timeval zero_timeout;
585 struct vki_timespec nanosleep_interval;
586
587 ensure_valgrind("select");
588
589 /* We assume that the kernel and libc data layouts are identical
590 for the following types. These asserts provide a crude
591 check. */
592 if (sizeof(fd_set) != sizeof(vki_fd_set)
593 || sizeof(struct timeval) != sizeof(struct vki_timeval))
594 barf("valgrind's hacky non-blocking select(): data sizes error");
595
596 /* If a zero timeout specified, this call is harmless. */
597 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
598 return do_syscall_select( n, (vki_fd_set*)rfds,
599 (vki_fd_set*)wfds,
600 (vki_fd_set*)xfds,
601 (struct vki_timeval*)timeout);
602
603 /* If a timeout was specified, set t_end to be the end wallclock
604 time. */
605 if (timeout) {
606 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
607 assert(res == 0);
608 t_end = t_now;
609 t_end.tv_usec += timeout->tv_usec;
610 t_end.tv_sec += timeout->tv_sec;
611 if (t_end.tv_usec >= 1000000) {
612 t_end.tv_usec -= 1000000;
613 t_end.tv_sec += 1;
614 }
615 /* Stay sane ... */
616 assert (t_end.tv_sec > t_now.tv_sec
617 || (t_end.tv_sec == t_now.tv_sec
618 && t_end.tv_usec >= t_now.tv_usec));
619 }
620
621 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
622
623 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
624 NULL, in which case t_end holds the end time. */
625 while (1) {
626 if (timeout) {
627 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
628 assert(res == 0);
629 if (t_now.tv_sec > t_end.tv_sec
630 || (t_now.tv_sec == t_end.tv_sec
631 && t_now.tv_usec > t_end.tv_usec)) {
632 /* timeout; nothing interesting happened. */
633 if (rfds) FD_ZERO(rfds);
634 if (wfds) FD_ZERO(wfds);
635 if (xfds) FD_ZERO(xfds);
636 return 0;
637 }
638 }
639
640 /* These could be trashed each time round the loop, so restore
641 them each time. */
642 if (rfds) rfds_copy = *rfds;
643 if (wfds) wfds_copy = *wfds;
644 if (xfds) xfds_copy = *xfds;
645
646 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
647
648 res = do_syscall_select( n,
649 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
650 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
651 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
652 & zero_timeout );
653 if (res < 0) {
654 /* some kind of error (including EINTR); errno is set, so just
655 return. The sets are unspecified in this case. */
656 return res;
657 }
658 if (res > 0) {
659 /* one or more fds is ready. Copy out resulting sets and
660 return. */
661 if (rfds) *rfds = rfds_copy;
662 if (wfds) *wfds = wfds_copy;
663 if (xfds) *xfds = xfds_copy;
664 return res;
665 }
666 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
667 /* nanosleep and go round again */
668 nanosleep_interval.tv_sec = 0;
669 nanosleep_interval.tv_nsec = 20 * 1000 * 1000; /* 20 milliseconds */
670 /* It's critical here that valgrind's nanosleep implementation
671 is nonblocking. */
672 (void)my_do_syscall2(__NR_nanosleep,
673 (int)(&nanosleep_interval), (int)NULL);
674 }
675}