blob: 08abf328116d47349f1e95e77f9c65edc7276b42 [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. */
35static int show_IGNORED = 0;
36
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
111int
112pthread_create (pthread_t *__restrict __thread,
113 __const pthread_attr_t *__restrict __attr,
114 void *(*__start_routine) (void *),
115 void *__restrict __arg)
116{
117 int res;
118 ensure_valgrind("pthread_create");
119 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
120 VG_USERREQ__PTHREAD_CREATE,
121 __thread, __attr, __start_routine, __arg);
122 return res;
123}
124
125
126
127int
128pthread_join (pthread_t __th, void **__thread_return)
129{
130 int res;
131 ensure_valgrind("pthread_join");
132 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
133 VG_USERREQ__PTHREAD_JOIN,
134 __th, __thread_return, 0, 0);
135 return res;
136}
137
138
139/* What are these? Anybody know? I don't. */
140
141void _pthread_cleanup_push_defer ( void )
142{
143 // char* str = "_pthread_cleanup_push_defer\n";
144 // write(2, str, strlen(str));
145}
146
147void _pthread_cleanup_pop_restore ( void )
148{
149 // char* str = "_pthread_cleanup_pop_restore\n";
150 // write(2, str, strlen(str));
151}
152
153
154static int thread_specific_errno[VG_N_THREADS];
155
156int* __errno_location ( void )
157{
158 int tid;
159 ensure_valgrind("__errno_location");
160 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
161 VG_USERREQ__PTHREAD_GET_THREADID,
162 0, 0, 0, 0);
163 /* 'cos I'm paranoid ... */
164 if (tid < 0 || tid >= VG_N_THREADS)
165 barf("__errno_location: invalid ThreadId");
166 return & thread_specific_errno[tid];
167}
168
169
170int pthread_mutexattr_init(pthread_mutexattr_t *attr)
171{
sewardj2a3d28c2002-04-14 13:27:00 +0000172 ignored("pthread_mutexattr_init");
sewardj8937c812002-04-12 20:12:20 +0000173 return 0;
sewardje663cb92002-04-12 10:26:32 +0000174}
175
176int pthread_mutex_init(pthread_mutex_t *mutex,
177 const pthread_mutexattr_t *mutexattr)
178{
179 int res;
sewardj8937c812002-04-12 20:12:20 +0000180 // char* str = "pthread_mutex_init\n";
181 // write(2, str, strlen(str));
sewardje663cb92002-04-12 10:26:32 +0000182 ensure_valgrind("pthread_mutex_init");
183 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
184 VG_USERREQ__PTHREAD_MUTEX_INIT,
185 mutex, mutexattr, 0, 0);
186 return res;
187}
188
189int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
190{
sewardj2a3d28c2002-04-14 13:27:00 +0000191 ignored("pthread_mutexattr_destroy");
sewardje663cb92002-04-12 10:26:32 +0000192 return 0;
193}
194
195int pthread_mutex_lock(pthread_mutex_t *mutex)
196{
197 int res;
198 if (!(RUNNING_ON_VALGRIND)) {
199 char* str = "pthread_mutex_lock-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_LOCK,
205 mutex, 0, 0, 0);
206 return res;
207 }
208}
209
210int pthread_mutex_unlock(pthread_mutex_t *mutex)
211{
212 int res;
213 if (!(RUNNING_ON_VALGRIND)) {
214 char* str = "pthread_mutex_unlock-NOT-INSIDE-VALGRIND\n";
215 write(2, str, strlen(str));
216 return 0;
217 } else {
218 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
219 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
220 mutex, 0, 0, 0);
221 return res;
222 }
223}
224
225pthread_t pthread_self(void)
226{
227 int tid;
228 ensure_valgrind("pthread_self");
229 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
230 VG_USERREQ__PTHREAD_GET_THREADID,
231 0, 0, 0, 0);
232 if (tid < 0 || tid >= VG_N_THREADS)
233 barf("pthread_self: invalid ThreadId");
234 return tid;
235}
236
237int pthread_mutex_destroy(pthread_mutex_t *mutex)
238{
239 int res;
240 if (!(RUNNING_ON_VALGRIND)) {
241 char* str = "pthread_mutex_destroy-NOT-INSIDE-VALGRIND\n";
242 write(2, str, strlen(str));
243 return 0;
244 } else {
245 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
246 VG_USERREQ__PTHREAD_MUTEX_DESTROY,
247 mutex, 0, 0, 0);
248 }
249 return res;
250}
251
252
253int pthread_setcanceltype(int type, int *oldtype)
254{
sewardj2a3d28c2002-04-14 13:27:00 +0000255 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000256 return 0;
257}
258
259
260int pthread_cancel(pthread_t thread)
261{
262 int res;
263 ensure_valgrind("pthread_cancel");
264 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
265 VG_USERREQ__PTHREAD_CANCEL,
266 thread, 0, 0, 0);
267 return res;
268}
269
270
sewardj5e5fa512002-04-14 13:13:05 +0000271
272int pthread_key_create(pthread_key_t *key,
273 void (*destr_function) (void *))
274{
sewardj2a3d28c2002-04-14 13:27:00 +0000275 ignored("pthread_key_create");
sewardj5e5fa512002-04-14 13:13:05 +0000276 return 0;
277}
278
279int pthread_key_delete(pthread_key_t key)
280{
sewardj2a3d28c2002-04-14 13:27:00 +0000281 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000282 return 0;
283}
284
285int pthread_setspecific(pthread_key_t key, const void *pointer)
286{
sewardj2a3d28c2002-04-14 13:27:00 +0000287 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000288 return 0;
289}
290
291void * pthread_getspecific(pthread_key_t key)
292{
sewardj2a3d28c2002-04-14 13:27:00 +0000293 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000294 return NULL;
295}
296
sewardje663cb92002-04-12 10:26:32 +0000297/* ---------------------------------------------------------------------
298 These are here (I think) because they are deemed cancellation
299 points by POSIX. For the moment we'll simply pass the call along
300 to the corresponding thread-unaware (?) libc routine.
301 ------------------------------------------------------------------ */
302
303#include <stdio.h>
304#include <stdlib.h>
305#include <signal.h>
306#include <errno.h>
307#include <sys/types.h>
308#include <sys/socket.h>
309
310extern
311int __libc_sigaction
312 (int signum,
313 const struct sigaction *act,
314 struct sigaction *oldact);
315int sigaction(int signum,
316 const struct sigaction *act,
317 struct sigaction *oldact)
318{
319 // char* str = "sigaction\n";
320 // write(2, str, strlen(str));
321 return __libc_sigaction(signum, act, oldact);
322}
323
324
325extern
326int __libc_connect(int sockfd,
327 const struct sockaddr *serv_addr,
328 socklen_t addrlen);
329int connect(int sockfd,
330 const struct sockaddr *serv_addr,
331 socklen_t addrlen)
332{
333 // char* str = "connect\n";
334 // write(2, str, strlen(str));
335 return __libc_connect(sockfd, serv_addr, addrlen);
336}
337
338
339extern
340int __libc_fcntl(int fd, int cmd, long arg);
341int fcntl(int fd, int cmd, long arg)
342{
343 // char* str = "fcntl\n";
344 // write(2, str, strlen(str));
345 return __libc_fcntl(fd, cmd, arg);
346}
347
348
349extern
350ssize_t __libc_write(int fd, const void *buf, size_t count);
351ssize_t write(int fd, const void *buf, size_t count)
352{
353 // char* str = "write\n";
354 // write(2, str, strlen(str));
355 return __libc_write(fd, buf, count);
356}
357
358
359extern
360ssize_t __libc_read(int fd, void *buf, size_t count);
361ssize_t read(int fd, void *buf, size_t count)
362{
363 // char* str = "read\n";
364 // write(2, str, strlen(str));
365 return __libc_read(fd, buf, count);
366}
367
368
369extern
370int __libc_open(const char *pathname, int flags);
371int open(const char *pathname, int flags)
372{
373 // char* str = "open\n";
374 // write(2, str, strlen(str));
375 return __libc_open(pathname, flags);
376}
377
378
379extern
380int __libc_close(int fd);
381int close(int fd)
382{
383 // char* str = "open\n";
384 // write(2, str, strlen(str));
385 return __libc_close(fd);
386}
387
388
389extern
390int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
391int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
392{
393 // char* str = "accept\n";
394 // write(2, str, strlen(str));
395 return __libc_accept(s, addr, addrlen);
396}
397
398
399extern
400pid_t __libc_fork(void);
401pid_t fork(void)
402{
403 // char* str = "fork\n";
404 // write(2, str, strlen(str));
405 return __libc_fork();
406}
407
408
409extern
410pid_t __libc_waitpid(pid_t pid, int *status, int options);
411pid_t waitpid(pid_t pid, int *status, int options)
412{
413 // char* str = "waitpid\n";
414 // write(2, str, strlen(str));
415 return __libc_waitpid(pid, status, options);
416}
417
418
419extern
420int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
421int nanosleep(const struct timespec *req, struct timespec *rem)
422{
423 return __libc_nanosleep(req, rem);
424}
425
426extern
427int __libc_fsync(int fd);
428int fsync(int fd)
429{
430 return __libc_fsync(fd);
431}
432
sewardj70c75362002-04-13 04:18:32 +0000433extern
434off_t __libc_lseek(int fildes, off_t offset, int whence);
435off_t lseek(int fildes, off_t offset, int whence)
436{
437 return __libc_lseek(fildes, offset, whence);
438}
439
440/*--------------------------------------------------*/
441
sewardje663cb92002-04-12 10:26:32 +0000442/* I've no idea what these are, but they get called quite a lot.
443 Anybody know? */
444
445#undef _IO_flockfile
446void _IO_flockfile ( _IO_FILE * file )
447{
448 // char* str = "_IO_flockfile\n";
449 // write(2, str, strlen(str));
450 // barf("_IO_flockfile");
451}
452
453#undef _IO_funlockfile
454void _IO_funlockfile ( _IO_FILE * file )
455{
456 // char* str = "_IO_funlockfile\n";
457 // write(2, str, strlen(str));
458 //barf("_IO_funlockfile");
459}
460
sewardj08a4c3f2002-04-13 03:45:44 +0000461/*--------------------------------------------------*/
462
463#include "vg_kerneliface.h"
464
465static
466__inline__
467int is_kerror ( int res )
468{
469 if (res >= -4095 && res <= -1)
470 return 1;
471 else
472 return 0;
473}
474
475
476static
477int my_do_syscall1 ( int syscallno, int arg1 )
478{
479 int __res;
480 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
481 : "=a" (__res)
482 : "0" (syscallno),
483 "d" (arg1) );
484 return __res;
485}
486
487static
488int my_do_syscall2 ( int syscallno,
489 int arg1, int arg2 )
490{
491 int __res;
492 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
493 : "=a" (__res)
494 : "0" (syscallno),
495 "d" (arg1),
496 "c" (arg2) );
497 return __res;
498}
499
500static
501int do_syscall_select( int n,
502 vki_fd_set* readfds,
503 vki_fd_set* writefds,
504 vki_fd_set* exceptfds,
505 struct vki_timeval * timeout )
506{
507 int res;
508 int args[5];
509 args[0] = n;
510 args[1] = (int)readfds;
511 args[2] = (int)writefds;
512 args[3] = (int)exceptfds;
513 args[4] = (int)timeout;
514 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
515 if (is_kerror(res)) {
516 * (__errno_location()) = -res;
517 return -1;
518 } else {
519 return res;
520 }
521}
522
523
524/* This is a wrapper round select(), which makes it thread-safe,
525 meaning that only this thread will block, rather than the entire
526 process. This wrapper in turn depends on nanosleep() not to block
527 the entire process, but I think (hope? suspect?) that POSIX
528 pthreads guarantees that to be the case.
529
530 Basic idea is: modify the timeout parameter to select so that it
531 returns immediately. Poll like this until select returns non-zero,
532 indicating something interesting happened, or until our time is up.
533 Space out the polls with nanosleeps of say 20 milliseconds, which
534 is required to be nonblocking; this allows other threads to run.
535*/
536#include <assert.h>
537
538
539int select ( int n,
540 fd_set *rfds,
541 fd_set *wfds,
542 fd_set *xfds,
543 struct timeval *timeout )
544{
545 int res;
546 fd_set rfds_copy;
547 fd_set wfds_copy;
548 fd_set xfds_copy;
549 struct vki_timeval t_now;
550 struct vki_timeval t_end;
551 struct vki_timeval zero_timeout;
552 struct vki_timespec nanosleep_interval;
553
554 ensure_valgrind("select");
555
556 /* We assume that the kernel and libc data layouts are identical
557 for the following types. These asserts provide a crude
558 check. */
559 if (sizeof(fd_set) != sizeof(vki_fd_set)
560 || sizeof(struct timeval) != sizeof(struct vki_timeval))
561 barf("valgrind's hacky non-blocking select(): data sizes error");
562
563 /* If a zero timeout specified, this call is harmless. */
564 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
565 return do_syscall_select( n, (vki_fd_set*)rfds,
566 (vki_fd_set*)wfds,
567 (vki_fd_set*)xfds,
568 (struct vki_timeval*)timeout);
569
570 /* If a timeout was specified, set t_end to be the end wallclock
571 time. */
572 if (timeout) {
573 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
574 assert(res == 0);
575 t_end = t_now;
576 t_end.tv_usec += timeout->tv_usec;
577 t_end.tv_sec += timeout->tv_sec;
578 if (t_end.tv_usec >= 1000000) {
579 t_end.tv_usec -= 1000000;
580 t_end.tv_sec += 1;
581 }
582 /* Stay sane ... */
583 assert (t_end.tv_sec > t_now.tv_sec
584 || (t_end.tv_sec == t_now.tv_sec
585 && t_end.tv_usec >= t_now.tv_usec));
586 }
587
588 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
589
590 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
591 NULL, in which case t_end holds the end time. */
592 while (1) {
593 if (timeout) {
594 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
595 assert(res == 0);
596 if (t_now.tv_sec > t_end.tv_sec
597 || (t_now.tv_sec == t_end.tv_sec
598 && t_now.tv_usec > t_end.tv_usec)) {
599 /* timeout; nothing interesting happened. */
600 if (rfds) FD_ZERO(rfds);
601 if (wfds) FD_ZERO(wfds);
602 if (xfds) FD_ZERO(xfds);
603 return 0;
604 }
605 }
606
607 /* These could be trashed each time round the loop, so restore
608 them each time. */
609 if (rfds) rfds_copy = *rfds;
610 if (wfds) wfds_copy = *wfds;
611 if (xfds) xfds_copy = *xfds;
612
613 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
614
615 res = do_syscall_select( n,
616 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
617 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
618 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
619 & zero_timeout );
620 if (res < 0) {
621 /* some kind of error (including EINTR); errno is set, so just
622 return. The sets are unspecified in this case. */
623 return res;
624 }
625 if (res > 0) {
626 /* one or more fds is ready. Copy out resulting sets and
627 return. */
628 if (rfds) *rfds = rfds_copy;
629 if (wfds) *wfds = wfds_copy;
630 if (xfds) *xfds = xfds_copy;
631 return res;
632 }
633 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
634 /* nanosleep and go round again */
635 nanosleep_interval.tv_sec = 0;
636 nanosleep_interval.tv_nsec = 20 * 1000 * 1000; /* 20 milliseconds */
637 /* It's critical here that valgrind's nanosleep implementation
638 is nonblocking. */
639 (void)my_do_syscall2(__NR_nanosleep,
640 (int)(&nanosleep_interval), (int)NULL);
641 }
642}