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