blob: 2f7b5b346439aa403c94f0b7475aa9512443ff84 [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
sewardj08a4c3f2002-04-13 03:45:44 +0000412/*--------------------------------------------------*/
413
414#include "vg_kerneliface.h"
415
416static
417__inline__
418int is_kerror ( int res )
419{
420 if (res >= -4095 && res <= -1)
421 return 1;
422 else
423 return 0;
424}
425
426
427static
428int my_do_syscall1 ( int syscallno, int arg1 )
429{
430 int __res;
431 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
432 : "=a" (__res)
433 : "0" (syscallno),
434 "d" (arg1) );
435 return __res;
436}
437
438static
439int my_do_syscall2 ( int syscallno,
440 int arg1, int arg2 )
441{
442 int __res;
443 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
444 : "=a" (__res)
445 : "0" (syscallno),
446 "d" (arg1),
447 "c" (arg2) );
448 return __res;
449}
450
451static
452int do_syscall_select( int n,
453 vki_fd_set* readfds,
454 vki_fd_set* writefds,
455 vki_fd_set* exceptfds,
456 struct vki_timeval * timeout )
457{
458 int res;
459 int args[5];
460 args[0] = n;
461 args[1] = (int)readfds;
462 args[2] = (int)writefds;
463 args[3] = (int)exceptfds;
464 args[4] = (int)timeout;
465 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
466 if (is_kerror(res)) {
467 * (__errno_location()) = -res;
468 return -1;
469 } else {
470 return res;
471 }
472}
473
474
475/* This is a wrapper round select(), which makes it thread-safe,
476 meaning that only this thread will block, rather than the entire
477 process. This wrapper in turn depends on nanosleep() not to block
478 the entire process, but I think (hope? suspect?) that POSIX
479 pthreads guarantees that to be the case.
480
481 Basic idea is: modify the timeout parameter to select so that it
482 returns immediately. Poll like this until select returns non-zero,
483 indicating something interesting happened, or until our time is up.
484 Space out the polls with nanosleeps of say 20 milliseconds, which
485 is required to be nonblocking; this allows other threads to run.
486*/
487#include <assert.h>
488
489
490int select ( int n,
491 fd_set *rfds,
492 fd_set *wfds,
493 fd_set *xfds,
494 struct timeval *timeout )
495{
496 int res;
497 fd_set rfds_copy;
498 fd_set wfds_copy;
499 fd_set xfds_copy;
500 struct vki_timeval t_now;
501 struct vki_timeval t_end;
502 struct vki_timeval zero_timeout;
503 struct vki_timespec nanosleep_interval;
504
505 ensure_valgrind("select");
506
507 /* We assume that the kernel and libc data layouts are identical
508 for the following types. These asserts provide a crude
509 check. */
510 if (sizeof(fd_set) != sizeof(vki_fd_set)
511 || sizeof(struct timeval) != sizeof(struct vki_timeval))
512 barf("valgrind's hacky non-blocking select(): data sizes error");
513
514 /* If a zero timeout specified, this call is harmless. */
515 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
516 return do_syscall_select( n, (vki_fd_set*)rfds,
517 (vki_fd_set*)wfds,
518 (vki_fd_set*)xfds,
519 (struct vki_timeval*)timeout);
520
521 /* If a timeout was specified, set t_end to be the end wallclock
522 time. */
523 if (timeout) {
524 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
525 assert(res == 0);
526 t_end = t_now;
527 t_end.tv_usec += timeout->tv_usec;
528 t_end.tv_sec += timeout->tv_sec;
529 if (t_end.tv_usec >= 1000000) {
530 t_end.tv_usec -= 1000000;
531 t_end.tv_sec += 1;
532 }
533 /* Stay sane ... */
534 assert (t_end.tv_sec > t_now.tv_sec
535 || (t_end.tv_sec == t_now.tv_sec
536 && t_end.tv_usec >= t_now.tv_usec));
537 }
538
539 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
540
541 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
542 NULL, in which case t_end holds the end time. */
543 while (1) {
544 if (timeout) {
545 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
546 assert(res == 0);
547 if (t_now.tv_sec > t_end.tv_sec
548 || (t_now.tv_sec == t_end.tv_sec
549 && t_now.tv_usec > t_end.tv_usec)) {
550 /* timeout; nothing interesting happened. */
551 if (rfds) FD_ZERO(rfds);
552 if (wfds) FD_ZERO(wfds);
553 if (xfds) FD_ZERO(xfds);
554 return 0;
555 }
556 }
557
558 /* These could be trashed each time round the loop, so restore
559 them each time. */
560 if (rfds) rfds_copy = *rfds;
561 if (wfds) wfds_copy = *wfds;
562 if (xfds) xfds_copy = *xfds;
563
564 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
565
566 res = do_syscall_select( n,
567 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
568 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
569 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
570 & zero_timeout );
571 if (res < 0) {
572 /* some kind of error (including EINTR); errno is set, so just
573 return. The sets are unspecified in this case. */
574 return res;
575 }
576 if (res > 0) {
577 /* one or more fds is ready. Copy out resulting sets and
578 return. */
579 if (rfds) *rfds = rfds_copy;
580 if (wfds) *wfds = wfds_copy;
581 if (xfds) *xfds = xfds_copy;
582 return res;
583 }
584 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
585 /* nanosleep and go round again */
586 nanosleep_interval.tv_sec = 0;
587 nanosleep_interval.tv_nsec = 20 * 1000 * 1000; /* 20 milliseconds */
588 /* It's critical here that valgrind's nanosleep implementation
589 is nonblocking. */
590 (void)my_do_syscall2(__NR_nanosleep,
591 (int)(&nanosleep_interval), (int)NULL);
592 }
593}