blob: b88e9010b1aab7c7c74bc5e803cb286ed0a036d1 [file] [log] [blame]
Greg Clayton33289902012-01-10 00:29:36 +00001//===-- FDInterposing.cpp ---------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file helps with catching double close calls on unix integer file
11// descriptors by interposing functions for all file descriptor create and
12// close operations. A stack backtrace for every create and close function is
13// maintained, and every create and close operation is logged. When a double
14// file descriptor close is encountered, it will be logged.
15//
16// To enable the interposing in a darwin program, set the DYLD_INSERT_LIBRARIES
17// environment variable as follows:
18// For sh:
19// DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib /path/to/executable
20// For tcsh:
21// (setenv DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib ; /path/to/executable)
22//
23// Other environment variables that can alter the default actions of this
24// interposing shared library include:
25//
26// "FileDescriptorStackLoggingNoCompact"
27//
28// With this environment variable set, all file descriptor create and
29// delete operations will be permanantly maintained in the event map.
30// The default action is to compact the create/delete events by removing
31// any previous file descriptor create events that are matched with a
32// corresponding file descriptor delete event when the next valid file
33// descriptor create event is detected.
34//
35// "FileDescriptorMinimalLogging"
36//
37// By default every file descriptor create and delete operation is logged
38// (to STDOUT by default, see the "FileDescriptorLogFile"). This can be
39// suppressed to only show errors and warnings by setting this environment
40// variable (the value in not important).
41//
42// "FileDescriptorLogFile=<path>"
43//
44// By default logging goes to STDOUT_FILENO, but this can be changed by
45// setting FileDescriptorLogFile. The value is a path to a file that
46// will be opened and used for logging.
47//===----------------------------------------------------------------------===//
48
49#include <assert.h>
50#include <dirent.h>
51#include <errno.h>
52#include <fcntl.h>
53#include <execinfo.h>
54#include <libgen.h>
55#include <mach-o/dyld.h>
56#include <mach-o/dyld-interposing.h>
57#include <stdlib.h>
58#include <stdio.h>
59#include <string.h>
60#include <sys/event.h>
61#include <sys/mman.h>
62#include <sys/socket.h>
63#include <sys/types.h>
64#include <sys/time.h>
65#include <tr1/memory> // for std::tr1::shared_ptr
66#include <unistd.h>
67#include <string>
68#include <vector>
69#include <map>
70
71//----------------------------------------------------------------------
72/// @def DISALLOW_COPY_AND_ASSIGN(TypeName)
73/// Macro definition for easily disallowing copy constructor and
74/// assignment operators in C++ classes.
75//----------------------------------------------------------------------
76#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
77TypeName(const TypeName&); \
78const TypeName& operator=(const TypeName&)
79
80namespace fd_interposing {
81
82//----------------------------------------------------------------------
83// String class so we can get formatted strings without having to worry
84// about the memory storage since it will allocate the memory it needs.
85//----------------------------------------------------------------------
86class String
87{
88public:
89 String () :
90 m_str (NULL)
91 {}
92
93 String (const char *format, ...) :
94 m_str (NULL)
95 {
96 va_list args;
97 va_start (args, format);
98 vprintf (format, args);
99 va_end (args);
100 }
101
102 ~String()
103 {
104 reset();
105 }
106
107 void
108 reset (char *s = NULL)
109 {
110 if (m_str)
111 ::free (m_str);
112 m_str = s;
113 }
114
115 const char *
116 c_str () const
117 {
118 return m_str;
119 }
120
121 void
122 printf (const char *format, ...)
123 {
124 va_list args;
125 va_start (args, format);
126 vprintf (format, args);
127 va_end (args);
128 }
129 void
130 vprintf (const char *format, va_list args)
131 {
132 reset();
133 ::vasprintf (&m_str, format, args);
134 }
135
136 void
137 log (int log_fd)
138 {
139 if (m_str && log_fd >= 0)
140 {
141 const int len = strlen(m_str);
142 if (len > 0)
143 {
144 write (log_fd, m_str, len);
145 const char last_char = m_str[len-1];
146 if (!(last_char == '\n' || last_char == '\r'))
147 write (log_fd, "\n", 1);
148 }
149 }
150 }
151protected:
152 char *m_str;
153
154private:
155 DISALLOW_COPY_AND_ASSIGN (String);
156};
157
158//----------------------------------------------------------------------
159// Type definitions
160//----------------------------------------------------------------------
161typedef std::vector<void *> Frames;
162class FDEvent;
163typedef std::vector<void *> Frames;
164typedef std::tr1::shared_ptr<FDEvent> FDEventSP;
165typedef std::tr1::shared_ptr<String> StringSP;
166
167
168//----------------------------------------------------------------------
169// FDEvent
170//
171// A class that describes a file desciptor event.
172//
173// File descriptor events fall into one of two categories: create events
174// and delete events.
175//----------------------------------------------------------------------
176class FDEvent
177{
178public:
179 FDEvent (int fd, int err, const StringSP &string_sp, bool is_create, const Frames& frames) :
180 m_string_sp (string_sp),
181 m_frames (frames.begin(), frames.end()),
182 m_fd (fd),
183 m_err (err),
184 m_is_create (is_create)
185 {}
186
187 ~FDEvent () {}
188
189 bool
190 IsCreateEvent() const
191 {
192 return m_is_create;
193 }
194
195 bool
196 IsDeleteEvent() const
197 {
198 return !m_is_create;
199 }
200
201 Frames &
202 GetFrames ()
203 {
204 return m_frames;
205 }
206
207 const Frames &
208 GetFrames () const
209 {
210 return m_frames;
211 }
212
213 int
214 GetFD () const
215 {
216 return m_fd;
217 }
218
219 int
220 GetError () const
221 {
222 return m_err;
223 }
224
225 void
226 Dump (int log_fd) const;
227
228 void
229 SetCreateEvent (FDEventSP &create_event_sp)
230 {
231 m_create_event_sp = create_event_sp;
232 }
233
234private:
235 // A shared pointer to a String that describes this event in
236 // detail (all args and return and error values)
237 StringSP m_string_sp;
238 // The frames for the stack backtrace for this event
239 Frames m_frames;
240 // If this is a file descriptor delete event, this might contain
241 // the correspoding file descriptor create event
242 FDEventSP m_create_event_sp;
243 // The file descriptor for this event
244 int m_fd;
245 // The error code (if any) for this event
246 int m_err;
247 // True if this event is a file descriptor create event, false
248 // if it is a file descriptor delete event
249 bool m_is_create;
250};
251
252//----------------------------------------------------------------------
253// Templatized class that will save errno only if the "value" it is
254// constructed with is equal to INVALID. When the class goes out of
255// scope, it will restore errno if it was saved.
256//----------------------------------------------------------------------
257template <int INVALID>
258class Errno
259{
260public:
261 // Save errno only if we are supposed to
262 Errno (int value) :
263 m_saved_errno ((value == INVALID) ? errno : 0),
264 m_restore (value == INVALID)
265 {
266 }
267
268 // Restore errno only if we are supposed to
269 ~Errno()
270 {
271 if (m_restore)
272 errno = m_saved_errno;
273 }
274
275 // Accessor for the saved value of errno
276 int
277 get_errno() const
278 {
279 return m_saved_errno;
280 }
281
282protected:
283 const int m_saved_errno;
284 const bool m_restore;
285};
286
287typedef Errno<-1> InvalidFDErrno;
288typedef Errno<-1> NegativeErrorErrno;
289typedef std::vector<FDEventSP> FDEventArray;
290typedef std::map<int, FDEventArray> FDEventMap;
291
292//----------------------------------------------------------------------
293// Globals
294//----------------------------------------------------------------------
295// Global event map that contains all file descriptor events. As file
296// descriptor create and close events come in, they will get filled
297// into this map (protected by g_mutex). When a file descriptor close
298// event is detected, the open event will be removed and placed into
299// the close event so if something tries to double close a file
300// descriptor we can show the previous close event and the file
301// desctiptor event that created it. When a new file descriptor create
302// event comes in, we will remove the previous one for that file
303// desctiptor unless the environment variable "FileDescriptorStackLoggingNoCompact"
304// is set. The file desctiptor history can be accessed using the
305// get_fd_history() function.
306static FDEventMap g_fd_event_map;
307// A mutex to protect access to our data structures in g_fd_event_map
308// and also our logging messages
309static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
310// Log all file descriptor create and close events by default. Only log
311// warnings and erros if the "FileDescriptorMinimalLogging" environment
312// variable is set.
313static int g_log_all_calls = 1;
314// We compact the file descriptor events by default. Set the environment
315// varible "FileDescriptorStackLoggingNoCompact" to keep a full history.
316static int g_compact = 1;
Greg Clayton662125a2012-01-14 18:18:31 +0000317// The name of the process
318static char g_program_path[PATH_MAX] = {0};
Greg Clayton33289902012-01-10 00:29:36 +0000319//----------------------------------------------------------------------
320// Mutex class that will lock a mutex when it is constructed, and unlock
321// it when is goes out of scope
322//----------------------------------------------------------------------
323class Locker
324{
325public:
326 Locker (pthread_mutex_t *mutex_ptr) :
327 m_mutex_ptr(mutex_ptr)
328 {
329 ::pthread_mutex_lock (m_mutex_ptr);
330 }
331
332 // This allows clients to test try and acquire the mutex...
333 Locker (pthread_mutex_t *mutex_ptr, bool &lock_acquired) :
334 m_mutex_ptr(NULL)
335 {
336 lock_acquired = ::pthread_mutex_trylock(mutex_ptr) == 0;
337 if (lock_acquired)
338 m_mutex_ptr = mutex_ptr;
339 }
340
341 ~Locker ()
342 {
343 if (m_mutex_ptr)
344 ::pthread_mutex_unlock (m_mutex_ptr);
345 }
346protected:
347 pthread_mutex_t *m_mutex_ptr;
348};
349
350static void
351log (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
352
353static void
354log (int log_fd, const FDEvent *event, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
355
356static void
357backtrace_log (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
358
359static void
360log_to_fd (int log_fd, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
361
362static inline size_t
363get_backtrace (Frames &frame_buffer, size_t frames_to_remove)
364{
365 void *frames[2048];
366 int count = ::backtrace (&frames[0], sizeof(frames)/sizeof(void*));
367 if (count > frames_to_remove)
368 frame_buffer.assign (&frames[frames_to_remove], &frames[count]);
369 else
370 frame_buffer.assign (&frames[0], &frames[count]);
371 while (frame_buffer.back() < (void *)1024)
372 frame_buffer.pop_back();
373 return frame_buffer.size();
374}
375
376static int
377get_logging_fd ()
378{
379 static int g_log_fd = STDOUT_FILENO;
Greg Clayton33289902012-01-10 00:29:36 +0000380 static int initialized = 0;
381
Greg Clayton33289902012-01-10 00:29:36 +0000382 if (!initialized)
383 {
384 initialized = 1;
385
386 // Keep all stack info around for all fd create and delete calls.
387 // Otherwise we will remove the fd create call when a corresponding
388 // fd delete call is received
389 if (getenv("FileDescriptorStackLoggingNoCompact"))
390 g_compact = 0;
391
392 if (getenv("FileDescriptorMinimalLogging"))
393 g_log_all_calls = 0;
394
395 char program_basename[PATH_MAX];
396 // If DST is NULL, then return the number of bytes needed.
Greg Clayton662125a2012-01-14 18:18:31 +0000397 uint32_t len = sizeof(g_program_path);
398 if (_NSGetExecutablePath (g_program_path, &len) == 0)
Greg Clayton33289902012-01-10 00:29:36 +0000399 {
Greg Clayton662125a2012-01-14 18:18:31 +0000400 strncpy (program_basename, g_program_path, sizeof(program_basename));
Greg Clayton33289902012-01-10 00:29:36 +0000401 const char *program_basename_cstr = basename(program_basename);
402 if (program_basename_cstr)
403 {
404 // Only let this interposing happen on the first time this matches
405 // and stop this from happening so any child processes don't also
406 // log their file descriptors
407 ::unsetenv ("DYLD_INSERT_LIBRARIES");
408 const char *log_path = getenv ("FileDescriptorLogFile");
409 if (log_path)
410 g_log_fd = ::creat (log_path, 0660);
411 if (g_log_fd >= 0)
Greg Clayton662125a2012-01-14 18:18:31 +0000412 log ("Logging file descriptor functions process '%s' (pid = %i)\n", g_program_path, getpid());
Greg Clayton33289902012-01-10 00:29:36 +0000413 }
414 }
415 }
416 return g_log_fd;
417}
418
419void
420log_to_fd (int log_fd, const char *format, va_list args)
421{
422 if (format && format[0] && log_fd >= 0)
423 {
424 char buffer[PATH_MAX];
425 const int count = ::vsnprintf (buffer, sizeof(buffer), format, args);
426 if (count > 0)
427 write (log_fd, buffer, count);
428 }
429}
430
431void
432log_to_fd (int log_fd, const char *format, ...)
433{
434 if (format && format[0])
435 {
436 va_list args;
437 va_start (args, format);
438 log_to_fd (log_fd, format, args);
439 va_end (args);
440 }
441}
442
443void
444log (const char *format, va_list args)
445{
446 log_to_fd (get_logging_fd (), format, args);
447}
448
449void
450log (const char *format, ...)
451{
452 if (format && format[0])
453 {
454 va_list args;
455 va_start (args, format);
456 log (format, args);
457 va_end (args);
458 }
459}
460
461void
462log (int log_fd, const FDEvent *event, const char *format, ...)
463{
464 if (format && format[0])
465 {
466 va_list args;
467 va_start (args, format);
468 log_to_fd (log_fd, format, args);
469 va_end (args);
470 }
471 if (event)
472 event->Dump(log_fd);
473}
474
475void
476FDEvent::Dump (int log_fd) const
477{
478 if (log_fd >= 0)
479 {
480 log_to_fd (log_fd, "%s\n", m_string_sp->c_str());
481 if (!m_frames.empty())
482 ::backtrace_symbols_fd (m_frames.data(), m_frames.size(), log_fd);
483
484 if (m_create_event_sp)
485 {
486 log_to_fd (log_fd, "\nfd=%i was created with this event:\n", m_fd);
487 m_create_event_sp->Dump (log_fd);
488 log_to_fd (log_fd, "\n");
489 }
490 }
491}
492
493
494void
495backtrace_log (const char *format, ...)
496{
497 const int log_fd = get_logging_fd ();
498 if (log_fd >= 0)
499 {
500 if (format && format[0])
501 {
502 va_list args;
503 va_start (args, format);
504 log (format, args);
505 va_end (args);
506 }
507
508 Frames frames;
Greg Clayton662125a2012-01-14 18:18:31 +0000509 if (get_backtrace(frames, 2))
Greg Clayton33289902012-01-10 00:29:36 +0000510 ::backtrace_symbols_fd (frames.data(), frames.size(), log_fd);
511 }
512
513}
514
515void
516save_backtrace (int fd, int err, const StringSP &string_sp, bool is_create);
517
518void
519save_backtrace (int fd, int err, const StringSP &string_sp, bool is_create)
520{
521 Frames frames;
522 get_backtrace(frames, 2);
523
524 FDEventSP fd_event_sp (new FDEvent (fd, err, string_sp, is_create, frames));
525
526 FDEventMap::iterator pos = g_fd_event_map.find (fd);
527
528 if (pos != g_fd_event_map.end())
529 {
530 // We have history for this fd...
531
532 FDEventArray &event_array = g_fd_event_map[fd];
533 if (fd_event_sp->IsCreateEvent())
534 {
535 // The current fd event is a function that creates
536 // a descriptor, check in case last event was
537 // a create event.
538 if (event_array.back()->IsCreateEvent())
539 {
540 const int log_fd = get_logging_fd();
541 // Two fd create functions in a row, we missed
542 // a function that closes a fd...
543 log (log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor create event fd=%i (we missed a file descriptor close event):\n", fd);
544 }
545 else if (g_compact)
546 {
547 // We are compacting so we remove previous create event
548 // when we get the correspinding delete event
549 event_array.pop_back();
550 }
551 }
552 else
553 {
554 // The current fd event is a function that deletes
555 // a descriptor, check in case last event for this
556 // fd was a delete event (double close!)
557 if (event_array.back()->IsDeleteEvent())
558 {
559 const int log_fd = get_logging_fd();
560 // Two fd delete functions in a row, we must
561 // have missed some function that opened a descriptor
562 log (log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor close event for fd=%d (we missed the file descriptor create event):\n", fd);
563 }
564 else if (g_compact)
565 {
566 // Since this is a close event, we want to remember the open event
567 // that this close if for...
568 fd_event_sp->SetCreateEvent(event_array.back());
569 // We are compacting so we remove previous create event
570 // when we get the correspinding delete event
571 event_array.pop_back();
572 }
573 }
574
575 event_array.push_back(fd_event_sp);
576 }
577 else
578 {
579 g_fd_event_map[fd].push_back(fd_event_sp);
580 }
581}
582
583//----------------------------------------------------------------------
584// socket() interpose function
585//----------------------------------------------------------------------
586extern "C" int
587socket$__interposed__ (int domain, int type, int protocol)
588{
589 Locker locker (&g_mutex);
590 const int fd = ::socket (domain, type, protocol);
591 InvalidFDErrno fd_errno(fd);
592 StringSP description_sp(new String);
593 if (fd == -1)
594 description_sp->printf("socket (domain = %i, type = %i, protocol = %i) => fd=%i errno = %i", domain, type, protocol, fd, fd_errno.get_errno());
595 else
596 description_sp->printf("socket (domain = %i, type = %i, protocol = %i) => fd=%i", domain, type, protocol, fd);
597 if (g_log_all_calls)
598 description_sp->log (get_logging_fd());
599 if (fd >= 0)
600 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
601 return fd;
602}
603
604//----------------------------------------------------------------------
605// socketpair() interpose function
606//----------------------------------------------------------------------
607extern "C" int
608socketpair$__interposed__ (int domain, int type, int protocol, int fds[2])
609{
610 Locker locker (&g_mutex);
611 fds[0] = -1;
612 fds[1] = -1;
613 const int err = socketpair (domain, type, protocol, fds);
614 NegativeErrorErrno err_errno(err);
615 StringSP description_sp(new String ("socketpair (domain=%i, type=%i, protocol=%i, {fd=%i, fd=%i}) -> err=%i", domain, type, protocol, fds[0], fds[1], err));
616 if (g_log_all_calls)
617 description_sp->log (get_logging_fd());
618 if (fds[0] >= 0)
619 save_backtrace (fds[0], err_errno.get_errno(), description_sp, true);
620 if (fds[1] >= 0)
621 save_backtrace (fds[1], err_errno.get_errno(), description_sp, true);
622 return err;
623}
624
625//----------------------------------------------------------------------
626// open() interpose function
627//----------------------------------------------------------------------
628extern "C" int
629open$__interposed__ (const char *path, int oflag, int mode)
630{
631 Locker locker (&g_mutex);
632 int fd = -2;
633 StringSP description_sp(new String);
634 if (oflag & O_CREAT)
635 {
636 fd = open (path, oflag, mode);
637 description_sp->printf("open (path = '%s', oflag = %i, mode = %i) -> fd=%i", path, oflag, mode, fd);
638 }
639 else
640 {
641 fd = open (path, oflag);
642 description_sp->printf("open (path = '%s', oflag = %i) -> fd=%i", path, oflag, fd);
643 }
644
645 InvalidFDErrno fd_errno(fd);
646 if (g_log_all_calls)
647 description_sp->log (get_logging_fd());
648 if (fd >= 0)
649 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
650 return fd;
651}
652
653//----------------------------------------------------------------------
654// open$NOCANCEL() interpose function
655//----------------------------------------------------------------------
656extern "C" int open$NOCANCEL(const char *, int, ...);
657extern "C" int __open_nocancel(const char *, int, ...);
658extern "C" int
659open$NOCANCEL$__interposed__ (const char *path, int oflag, int mode)
660{
661 Locker locker (&g_mutex);
662 const int fd = open$NOCANCEL (path, oflag, mode);
663 InvalidFDErrno fd_errno(fd);
664 StringSP description_sp(new String ("open$NOCANCEL (path = '%s', oflag = %i, mode = %i) -> fd=%i", path, oflag, mode, fd));
665 if (g_log_all_calls)
666 description_sp->log (get_logging_fd());
667 if (fd >= 0)
668 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
669 return fd;
670}
671
672extern "C" int __open_extended(const char *, int, uid_t, gid_t, int, struct kauth_filesec *);
673
674//----------------------------------------------------------------------
675// __open_extended() interpose function
676//----------------------------------------------------------------------
677extern "C" int
678__open_extended$__interposed__ (const char *path, int oflag, uid_t uid, gid_t gid, int mode, struct kauth_filesec *fsacl)
679{
680 Locker locker (&g_mutex);
681 const int fd = __open_extended (path, oflag, uid, gid, mode, fsacl);
682 InvalidFDErrno fd_errno(fd);
683 StringSP description_sp(new String ("__open_extended (path='%s', oflag=%i, uid=%i, gid=%i, mode=%i, fsacl=%p) -> fd=%i", path, oflag, uid, gid, mode, fsacl, fd));
684 if (g_log_all_calls)
685 description_sp->log (get_logging_fd());
686 if (fd >= 0)
687 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
688 return fd;
689}
690
691//----------------------------------------------------------------------
692// kqueue() interpose function
693//----------------------------------------------------------------------
694extern "C" int
695kqueue$__interposed__ (void)
696{
697 Locker locker (&g_mutex);
698 const int fd = ::kqueue ();
699 InvalidFDErrno fd_errno(fd);
700 StringSP description_sp(new String ("kqueue () -> fd=%i", fd));
701 if (g_log_all_calls)
702 description_sp->log (get_logging_fd());
703 if (fd >= 0)
704 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
705 return fd;
706
707}
708
709//----------------------------------------------------------------------
710// shm_open() interpose function
711//----------------------------------------------------------------------
712extern "C" int
713shm_open$__interposed__ (const char *path, int oflag, int mode)
714{
715 Locker locker (&g_mutex);
716 const int fd = shm_open (path, oflag, mode);
717 InvalidFDErrno fd_errno(fd);
718 StringSP description_sp(new String ("shm_open (path = '%s', oflag = %i, mode = %i) -> fd=%i", path, oflag, mode, fd));
719 if (g_log_all_calls)
720 description_sp->log (get_logging_fd());
721 if (fd >= 0)
722 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
723 return fd;
724}
725
726//----------------------------------------------------------------------
727// accept() interpose function
728//----------------------------------------------------------------------
729extern "C" int
730accept$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len)
731{
732 Locker locker (&g_mutex);
733 const int fd = accept (socket, address, address_len);
734 InvalidFDErrno fd_errno(fd);
735 StringSP description_sp(new String ("accept (socket=%i, ...) -> fd=%i", socket, fd));
736 if (g_log_all_calls)
737 description_sp->log (get_logging_fd());
738 if (fd >= 0)
739 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
740 return fd;
741}
742
743
744//----------------------------------------------------------------------
745// accept$NOCANCEL() interpose function
746//----------------------------------------------------------------------
747extern "C" int accept$NOCANCEL (int, struct sockaddr * __restrict, socklen_t * __restrict);
748extern "C" int
749accept$NOCANCEL$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len)
750{
751 Locker locker (&g_mutex);
752 const int fd = accept$NOCANCEL (socket, address, address_len);
753 InvalidFDErrno fd_errno(fd);
754 StringSP description_sp(new String ("accept$NOCANCEL (socket=%i, ...) -> fd=%i", socket, fd));
755 if (g_log_all_calls)
756 description_sp->log (get_logging_fd());
757 if (fd >= 0)
758 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
759 return fd;
760}
761
762//----------------------------------------------------------------------
763// dup() interpose function
764//----------------------------------------------------------------------
765extern "C" int
766dup$__interposed__ (int fd2)
767{
768 Locker locker (&g_mutex);
769 const int fd = dup (fd2);
770 InvalidFDErrno fd_errno(fd);
771 StringSP description_sp(new String ("dup (fd2=%i) -> fd=%i", fd2, fd));
772 if (g_log_all_calls)
773 description_sp->log (get_logging_fd());
774 if (fd >= 0)
775 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
776 return fd;
777}
778
779//----------------------------------------------------------------------
780// dup2() interpose function
781//----------------------------------------------------------------------
782extern "C" int
783dup2$__interposed__ (int fd1, int fd2)
784{
785 Locker locker (&g_mutex);
Greg Clayton33289902012-01-10 00:29:36 +0000786 // If "fd2" is already opened, it will be closed during the
787 // dup2 call below, so we need to see if we have fd2 in our
788 // open map and treat it as a close(fd2)
789 FDEventMap::iterator pos = g_fd_event_map.find (fd2);
Greg Clayton662125a2012-01-14 18:18:31 +0000790 StringSP dup2_close_description_sp(new String ("dup2 (fd1=%i, fd2=%i) -> will close (fd=%i)", fd1, fd2, fd2));
Greg Clayton33289902012-01-10 00:29:36 +0000791 if (pos != g_fd_event_map.end() && pos->second.back()->IsCreateEvent())
Greg Clayton662125a2012-01-14 18:18:31 +0000792 save_backtrace (fd2, 0, dup2_close_description_sp, false);
793
794 const int fd = dup2(fd1, fd2);
795 InvalidFDErrno fd_errno(fd);
796 StringSP description_sp(new String ("dup2 (fd1=%i, fd2=%i) -> fd=%i", fd1, fd2, fd));
797 if (g_log_all_calls)
798 description_sp->log (get_logging_fd());
Greg Clayton33289902012-01-10 00:29:36 +0000799
800 if (fd >= 0)
801 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
802 return fd;
803}
804
805//----------------------------------------------------------------------
806// close() interpose function
807//----------------------------------------------------------------------
808extern "C" int
809close$__interposed__ (int fd)
810{
811 Locker locker (&g_mutex);
812 const int err = close(fd);
813 NegativeErrorErrno err_errno(err);
814 StringSP description_sp (new String);
815 if (err == -1)
816 description_sp->printf("close (fd=%i) => %i errno = %i (%s))", fd, err, err_errno.get_errno(), strerror(err_errno.get_errno()));
817 else
818 description_sp->printf("close (fd=%i) => %i", fd, err);
819 if (g_log_all_calls)
820 description_sp->log (get_logging_fd());
821
822 if (err == 0)
823 {
824 if (fd >= 0)
825 save_backtrace (fd, err, description_sp, false);
826 }
827 else if (err == -1)
828 {
829 if (err_errno.get_errno() == EBADF && fd != -1)
830 {
Greg Clayton662125a2012-01-14 18:18:31 +0000831 backtrace_log ("\nerror: close on fd=%d resulted in EBADF in process %s (pid = %i)\n", fd, g_program_path, getpid());
Greg Clayton33289902012-01-10 00:29:36 +0000832
833 FDEventMap::iterator pos = g_fd_event_map.find (fd);
834 if (pos != g_fd_event_map.end())
835 {
Greg Clayton662125a2012-01-14 18:18:31 +0000836 log (get_logging_fd(), pos->second.back().get(), "\nfd=%d was previously %s with this event:\n", fd, pos->second.back()->IsCreateEvent() ? "opened" : "closed");
Greg Clayton33289902012-01-10 00:29:36 +0000837 }
838 }
839 }
840 return err;
841}
842
843//----------------------------------------------------------------------
844// close$NOCANCEL() interpose function
845//----------------------------------------------------------------------
846extern "C" int close$NOCANCEL(int);
847extern "C" int
848close$NOCANCEL$__interposed__ (int fd)
849{
850 Locker locker (&g_mutex);
851 const int err = close$NOCANCEL(fd);
852 NegativeErrorErrno err_errno(err);
853 StringSP description_sp (new String);
854 if (err == -1)
855 description_sp->printf("close$NOCANCEL (fd=%i) => %i errno = %i (%s))", fd, err, err_errno.get_errno(), strerror(err_errno.get_errno()));
856 else
857 description_sp->printf("close$NOCANCEL (fd=%i) => %i", fd, err);
858 if (g_log_all_calls)
859 description_sp->log (get_logging_fd());
860
861 if (err == 0)
862 {
863 if (fd >= 0)
864 save_backtrace (fd, err, description_sp, false);
865 }
866 else if (err == -1)
867 {
868 if (err_errno.get_errno() == EBADF && fd != -1)
869 {
Greg Clayton662125a2012-01-14 18:18:31 +0000870 backtrace_log ("\nerror: close$NOCANCEL on fd=%d resulted in EBADF in process %s (pid = %i)\n", fd, g_program_path, getpid());
Greg Clayton33289902012-01-10 00:29:36 +0000871
872 FDEventMap::iterator pos = g_fd_event_map.find (fd);
873 if (pos != g_fd_event_map.end())
874 {
Greg Clayton662125a2012-01-14 18:18:31 +0000875 log (get_logging_fd(), pos->second.back().get(), "\nfd=%d was previously %s with this event:\n", fd, pos->second.back()->IsCreateEvent() ? "opened" : "closed");
Greg Clayton33289902012-01-10 00:29:36 +0000876 }
877 }
878 }
879 return err;
880
881}
882
883//----------------------------------------------------------------------
884// pipe() interpose function
885//----------------------------------------------------------------------
886extern "C" int
887pipe$__interposed__ (int fds[2])
888{
889 Locker locker (&g_mutex);
890 fds[0] = -1;
891 fds[1] = -1;
892 const int err = pipe (fds);
893 const int saved_errno = errno;
894 StringSP description_sp(new String ("pipe ({fd=%i, fd=%i}) -> err=%i", fds[0], fds[1], err));
895 if (g_log_all_calls)
896 description_sp->log (get_logging_fd());
897 if (fds[0] >= 0)
898 save_backtrace (fds[0], saved_errno, description_sp, true);
899 if (fds[1] >= 0)
900 save_backtrace (fds[1], saved_errno, description_sp, true);
901 errno = saved_errno;
902 return err;
903}
904
905//----------------------------------------------------------------------
906// get_fd_history()
907//
908// This function allows runtime access to the file descriptor history.
909//
910// @param[in] log_fd
911// The file descriptor to log to
912//
913// @param[in] fd
914// The file descriptor whose history should be dumped
915//----------------------------------------------------------------------
916extern "C" void
917get_fd_history (int log_fd, int fd)
918{
919 // "create" below needs to be outside of the mutex locker scope
920 if (log_fd >= 0)
921 {
922 bool got_lock = false;
923 Locker locker (&g_mutex, got_lock);
924 if (got_lock)
925 {
926 FDEventMap::iterator pos = g_fd_event_map.find (fd);
927 log_to_fd (log_fd, "Dumping file descriptor history for fd=%i:\n", fd);
928 if (pos != g_fd_event_map.end())
929 {
930 FDEventArray &event_array = g_fd_event_map[fd];
931 const size_t num_events = event_array.size();
932 for (size_t i=0; i<num_events; ++i)
933 event_array[i]->Dump (log_fd);
934 }
935 else
936 {
937 log_to_fd (log_fd, "error: no file descriptor events found for fd=%i\n", fd);
938 }
939 }
940 else
941 {
942 log_to_fd (log_fd, "error: fd event mutex is locked...\n");
943 }
944 }
945}
946
947//----------------------------------------------------------------------
948// Interposing
949//----------------------------------------------------------------------
950// FD creation routines
951DYLD_INTERPOSE(accept$__interposed__, accept);
952DYLD_INTERPOSE(accept$NOCANCEL$__interposed__, accept$NOCANCEL);
953DYLD_INTERPOSE(dup$__interposed__, dup);
954DYLD_INTERPOSE(dup2$__interposed__, dup2);
955DYLD_INTERPOSE(kqueue$__interposed__, kqueue);
956DYLD_INTERPOSE(open$__interposed__, open);
957DYLD_INTERPOSE(open$NOCANCEL$__interposed__, open$NOCANCEL);
958DYLD_INTERPOSE(open$NOCANCEL$__interposed__, __open_nocancel);
959DYLD_INTERPOSE(__open_extended$__interposed__, __open_extended);
960DYLD_INTERPOSE(pipe$__interposed__, pipe);
961DYLD_INTERPOSE(shm_open$__interposed__, shm_open);
962DYLD_INTERPOSE(socket$__interposed__, socket);
963DYLD_INTERPOSE(socketpair$__interposed__, socketpair);
964
965// FD deleting routines
966DYLD_INTERPOSE(close$__interposed__, close);
967DYLD_INTERPOSE(close$NOCANCEL$__interposed__, close$NOCANCEL);
968
969} // namespace fd_interposing
970
971