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