blob: 88130f5a4ab0e934505de3aee2d1aa4b0b9396dc [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;
317
318//----------------------------------------------------------------------
319// Mutex class that will lock a mutex when it is constructed, and unlock
320// it when is goes out of scope
321//----------------------------------------------------------------------
322class Locker
323{
324public:
325 Locker (pthread_mutex_t *mutex_ptr) :
326 m_mutex_ptr(mutex_ptr)
327 {
328 ::pthread_mutex_lock (m_mutex_ptr);
329 }
330
331 // This allows clients to test try and acquire the mutex...
332 Locker (pthread_mutex_t *mutex_ptr, bool &lock_acquired) :
333 m_mutex_ptr(NULL)
334 {
335 lock_acquired = ::pthread_mutex_trylock(mutex_ptr) == 0;
336 if (lock_acquired)
337 m_mutex_ptr = mutex_ptr;
338 }
339
340 ~Locker ()
341 {
342 if (m_mutex_ptr)
343 ::pthread_mutex_unlock (m_mutex_ptr);
344 }
345protected:
346 pthread_mutex_t *m_mutex_ptr;
347};
348
349static void
350log (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
351
352static void
353log (int log_fd, const FDEvent *event, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
354
355static void
356backtrace_log (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
357
358static void
359log_to_fd (int log_fd, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
360
361static inline size_t
362get_backtrace (Frames &frame_buffer, size_t frames_to_remove)
363{
364 void *frames[2048];
365 int count = ::backtrace (&frames[0], sizeof(frames)/sizeof(void*));
366 if (count > frames_to_remove)
367 frame_buffer.assign (&frames[frames_to_remove], &frames[count]);
368 else
369 frame_buffer.assign (&frames[0], &frames[count]);
370 while (frame_buffer.back() < (void *)1024)
371 frame_buffer.pop_back();
372 return frame_buffer.size();
373}
374
375static int
376get_logging_fd ()
377{
378 static int g_log_fd = STDOUT_FILENO;
379 static char program_fullpath[PATH_MAX];
380 static int initialized = 0;
381
382 const int pid = getpid();
383
384 if (!initialized)
385 {
386 initialized = 1;
387
388 // Keep all stack info around for all fd create and delete calls.
389 // Otherwise we will remove the fd create call when a corresponding
390 // fd delete call is received
391 if (getenv("FileDescriptorStackLoggingNoCompact"))
392 g_compact = 0;
393
394 if (getenv("FileDescriptorMinimalLogging"))
395 g_log_all_calls = 0;
396
397 char program_basename[PATH_MAX];
398 // If DST is NULL, then return the number of bytes needed.
399 uint32_t len = sizeof(program_fullpath);
400 if (_NSGetExecutablePath (program_fullpath, &len) == 0)
401 {
402 strncpy (program_basename, program_fullpath, sizeof(program_basename));
403 const char *program_basename_cstr = basename(program_basename);
404 if (program_basename_cstr)
405 {
406 // Only let this interposing happen on the first time this matches
407 // and stop this from happening so any child processes don't also
408 // log their file descriptors
409 ::unsetenv ("DYLD_INSERT_LIBRARIES");
410 const char *log_path = getenv ("FileDescriptorLogFile");
411 if (log_path)
412 g_log_fd = ::creat (log_path, 0660);
413 if (g_log_fd >= 0)
414 log ("Logging file descriptor functions process '%s' (pid = %i)\n", program_fullpath, pid);
415 }
416 }
417 }
418 return g_log_fd;
419}
420
421void
422log_to_fd (int log_fd, const char *format, va_list args)
423{
424 if (format && format[0] && log_fd >= 0)
425 {
426 char buffer[PATH_MAX];
427 const int count = ::vsnprintf (buffer, sizeof(buffer), format, args);
428 if (count > 0)
429 write (log_fd, buffer, count);
430 }
431}
432
433void
434log_to_fd (int log_fd, const char *format, ...)
435{
436 if (format && format[0])
437 {
438 va_list args;
439 va_start (args, format);
440 log_to_fd (log_fd, format, args);
441 va_end (args);
442 }
443}
444
445void
446log (const char *format, va_list args)
447{
448 log_to_fd (get_logging_fd (), format, args);
449}
450
451void
452log (const char *format, ...)
453{
454 if (format && format[0])
455 {
456 va_list args;
457 va_start (args, format);
458 log (format, args);
459 va_end (args);
460 }
461}
462
463void
464log (int log_fd, const FDEvent *event, const char *format, ...)
465{
466 if (format && format[0])
467 {
468 va_list args;
469 va_start (args, format);
470 log_to_fd (log_fd, format, args);
471 va_end (args);
472 }
473 if (event)
474 event->Dump(log_fd);
475}
476
477void
478FDEvent::Dump (int log_fd) const
479{
480 if (log_fd >= 0)
481 {
482 log_to_fd (log_fd, "%s\n", m_string_sp->c_str());
483 if (!m_frames.empty())
484 ::backtrace_symbols_fd (m_frames.data(), m_frames.size(), log_fd);
485
486 if (m_create_event_sp)
487 {
488 log_to_fd (log_fd, "\nfd=%i was created with this event:\n", m_fd);
489 m_create_event_sp->Dump (log_fd);
490 log_to_fd (log_fd, "\n");
491 }
492 }
493}
494
495
496void
497backtrace_log (const char *format, ...)
498{
499 const int log_fd = get_logging_fd ();
500 if (log_fd >= 0)
501 {
502 if (format && format[0])
503 {
504 va_list args;
505 va_start (args, format);
506 log (format, args);
507 va_end (args);
508 }
509
510 Frames frames;
511 if (get_backtrace(frames, 3))
512 ::backtrace_symbols_fd (frames.data(), frames.size(), log_fd);
513 }
514
515}
516
517void
518save_backtrace (int fd, int err, const StringSP &string_sp, bool is_create);
519
520void
521save_backtrace (int fd, int err, const StringSP &string_sp, bool is_create)
522{
523 Frames frames;
524 get_backtrace(frames, 2);
525
526 FDEventSP fd_event_sp (new FDEvent (fd, err, string_sp, is_create, frames));
527
528 FDEventMap::iterator pos = g_fd_event_map.find (fd);
529
530 if (pos != g_fd_event_map.end())
531 {
532 // We have history for this fd...
533
534 FDEventArray &event_array = g_fd_event_map[fd];
535 if (fd_event_sp->IsCreateEvent())
536 {
537 // The current fd event is a function that creates
538 // a descriptor, check in case last event was
539 // a create event.
540 if (event_array.back()->IsCreateEvent())
541 {
542 const int log_fd = get_logging_fd();
543 // Two fd create functions in a row, we missed
544 // a function that closes a fd...
545 log (log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor create event fd=%i (we missed a file descriptor close event):\n", fd);
546 }
547 else if (g_compact)
548 {
549 // We are compacting so we remove previous create event
550 // when we get the correspinding delete event
551 event_array.pop_back();
552 }
553 }
554 else
555 {
556 // The current fd event is a function that deletes
557 // a descriptor, check in case last event for this
558 // fd was a delete event (double close!)
559 if (event_array.back()->IsDeleteEvent())
560 {
561 const int log_fd = get_logging_fd();
562 // Two fd delete functions in a row, we must
563 // have missed some function that opened a descriptor
564 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);
565 }
566 else if (g_compact)
567 {
568 // Since this is a close event, we want to remember the open event
569 // that this close if for...
570 fd_event_sp->SetCreateEvent(event_array.back());
571 // We are compacting so we remove previous create event
572 // when we get the correspinding delete event
573 event_array.pop_back();
574 }
575 }
576
577 event_array.push_back(fd_event_sp);
578 }
579 else
580 {
581 g_fd_event_map[fd].push_back(fd_event_sp);
582 }
583}
584
585//----------------------------------------------------------------------
586// socket() interpose function
587//----------------------------------------------------------------------
588extern "C" int
589socket$__interposed__ (int domain, int type, int protocol)
590{
591 Locker locker (&g_mutex);
592 const int fd = ::socket (domain, type, protocol);
593 InvalidFDErrno fd_errno(fd);
594 StringSP description_sp(new String);
595 if (fd == -1)
596 description_sp->printf("socket (domain = %i, type = %i, protocol = %i) => fd=%i errno = %i", domain, type, protocol, fd, fd_errno.get_errno());
597 else
598 description_sp->printf("socket (domain = %i, type = %i, protocol = %i) => fd=%i", domain, type, protocol, fd);
599 if (g_log_all_calls)
600 description_sp->log (get_logging_fd());
601 if (fd >= 0)
602 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
603 return fd;
604}
605
606//----------------------------------------------------------------------
607// socketpair() interpose function
608//----------------------------------------------------------------------
609extern "C" int
610socketpair$__interposed__ (int domain, int type, int protocol, int fds[2])
611{
612 Locker locker (&g_mutex);
613 fds[0] = -1;
614 fds[1] = -1;
615 const int err = socketpair (domain, type, protocol, fds);
616 NegativeErrorErrno err_errno(err);
617 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));
618 if (g_log_all_calls)
619 description_sp->log (get_logging_fd());
620 if (fds[0] >= 0)
621 save_backtrace (fds[0], err_errno.get_errno(), description_sp, true);
622 if (fds[1] >= 0)
623 save_backtrace (fds[1], err_errno.get_errno(), description_sp, true);
624 return err;
625}
626
627//----------------------------------------------------------------------
628// open() interpose function
629//----------------------------------------------------------------------
630extern "C" int
631open$__interposed__ (const char *path, int oflag, int mode)
632{
633 Locker locker (&g_mutex);
634 int fd = -2;
635 StringSP description_sp(new String);
636 if (oflag & O_CREAT)
637 {
638 fd = open (path, oflag, mode);
639 description_sp->printf("open (path = '%s', oflag = %i, mode = %i) -> fd=%i", path, oflag, mode, fd);
640 }
641 else
642 {
643 fd = open (path, oflag);
644 description_sp->printf("open (path = '%s', oflag = %i) -> fd=%i", path, oflag, fd);
645 }
646
647 InvalidFDErrno fd_errno(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}
654
655//----------------------------------------------------------------------
656// open$NOCANCEL() interpose function
657//----------------------------------------------------------------------
658extern "C" int open$NOCANCEL(const char *, int, ...);
659extern "C" int __open_nocancel(const char *, int, ...);
660extern "C" int
661open$NOCANCEL$__interposed__ (const char *path, int oflag, int mode)
662{
663 Locker locker (&g_mutex);
664 const int fd = open$NOCANCEL (path, oflag, mode);
665 InvalidFDErrno fd_errno(fd);
666 StringSP description_sp(new String ("open$NOCANCEL (path = '%s', oflag = %i, mode = %i) -> fd=%i", path, oflag, mode, fd));
667 if (g_log_all_calls)
668 description_sp->log (get_logging_fd());
669 if (fd >= 0)
670 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
671 return fd;
672}
673
674extern "C" int __open_extended(const char *, int, uid_t, gid_t, int, struct kauth_filesec *);
675
676//----------------------------------------------------------------------
677// __open_extended() interpose function
678//----------------------------------------------------------------------
679extern "C" int
680__open_extended$__interposed__ (const char *path, int oflag, uid_t uid, gid_t gid, int mode, struct kauth_filesec *fsacl)
681{
682 Locker locker (&g_mutex);
683 const int fd = __open_extended (path, oflag, uid, gid, mode, fsacl);
684 InvalidFDErrno fd_errno(fd);
685 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));
686 if (g_log_all_calls)
687 description_sp->log (get_logging_fd());
688 if (fd >= 0)
689 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
690 return fd;
691}
692
693//----------------------------------------------------------------------
694// kqueue() interpose function
695//----------------------------------------------------------------------
696extern "C" int
697kqueue$__interposed__ (void)
698{
699 Locker locker (&g_mutex);
700 const int fd = ::kqueue ();
701 InvalidFDErrno fd_errno(fd);
702 StringSP description_sp(new String ("kqueue () -> fd=%i", fd));
703 if (g_log_all_calls)
704 description_sp->log (get_logging_fd());
705 if (fd >= 0)
706 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
707 return fd;
708
709}
710
711//----------------------------------------------------------------------
712// shm_open() interpose function
713//----------------------------------------------------------------------
714extern "C" int
715shm_open$__interposed__ (const char *path, int oflag, int mode)
716{
717 Locker locker (&g_mutex);
718 const int fd = shm_open (path, oflag, mode);
719 InvalidFDErrno fd_errno(fd);
720 StringSP description_sp(new String ("shm_open (path = '%s', oflag = %i, mode = %i) -> fd=%i", path, oflag, mode, fd));
721 if (g_log_all_calls)
722 description_sp->log (get_logging_fd());
723 if (fd >= 0)
724 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
725 return fd;
726}
727
728//----------------------------------------------------------------------
729// accept() interpose function
730//----------------------------------------------------------------------
731extern "C" int
732accept$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len)
733{
734 Locker locker (&g_mutex);
735 const int fd = accept (socket, address, address_len);
736 InvalidFDErrno fd_errno(fd);
737 StringSP description_sp(new String ("accept (socket=%i, ...) -> fd=%i", socket, fd));
738 if (g_log_all_calls)
739 description_sp->log (get_logging_fd());
740 if (fd >= 0)
741 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
742 return fd;
743}
744
745
746//----------------------------------------------------------------------
747// accept$NOCANCEL() interpose function
748//----------------------------------------------------------------------
749extern "C" int accept$NOCANCEL (int, struct sockaddr * __restrict, socklen_t * __restrict);
750extern "C" int
751accept$NOCANCEL$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len)
752{
753 Locker locker (&g_mutex);
754 const int fd = accept$NOCANCEL (socket, address, address_len);
755 InvalidFDErrno fd_errno(fd);
756 StringSP description_sp(new String ("accept$NOCANCEL (socket=%i, ...) -> fd=%i", socket, fd));
757 if (g_log_all_calls)
758 description_sp->log (get_logging_fd());
759 if (fd >= 0)
760 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
761 return fd;
762}
763
764//----------------------------------------------------------------------
765// dup() interpose function
766//----------------------------------------------------------------------
767extern "C" int
768dup$__interposed__ (int fd2)
769{
770 Locker locker (&g_mutex);
771 const int fd = dup (fd2);
772 InvalidFDErrno fd_errno(fd);
773 StringSP description_sp(new String ("dup (fd2=%i) -> fd=%i", fd2, fd));
774 if (g_log_all_calls)
775 description_sp->log (get_logging_fd());
776 if (fd >= 0)
777 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
778 return fd;
779}
780
781//----------------------------------------------------------------------
782// dup2() interpose function
783//----------------------------------------------------------------------
784extern "C" int
785dup2$__interposed__ (int fd1, int fd2)
786{
787 Locker locker (&g_mutex);
788
789 const int fd = dup2(fd1, fd2);
790 InvalidFDErrno fd_errno(fd);
791 StringSP description_sp(new String ("dup2 fd1=%i, fd2=%i) -> fd=%i", fd1, fd2, fd));
792 if (g_log_all_calls)
793 description_sp->log (get_logging_fd());
794 // If "fd2" is already opened, it will be closed during the
795 // dup2 call below, so we need to see if we have fd2 in our
796 // open map and treat it as a close(fd2)
797 FDEventMap::iterator pos = g_fd_event_map.find (fd2);
798 if (pos != g_fd_event_map.end() && pos->second.back()->IsCreateEvent())
799 save_backtrace (fd2, 0, description_sp, false);
800
801 if (fd >= 0)
802 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
803 return fd;
804}
805
806//----------------------------------------------------------------------
807// close() interpose function
808//----------------------------------------------------------------------
809extern "C" int
810close$__interposed__ (int fd)
811{
812 Locker locker (&g_mutex);
813 const int err = close(fd);
814 NegativeErrorErrno err_errno(err);
815 StringSP description_sp (new String);
816 if (err == -1)
817 description_sp->printf("close (fd=%i) => %i errno = %i (%s))", fd, err, err_errno.get_errno(), strerror(err_errno.get_errno()));
818 else
819 description_sp->printf("close (fd=%i) => %i", fd, err);
820 if (g_log_all_calls)
821 description_sp->log (get_logging_fd());
822
823 if (err == 0)
824 {
825 if (fd >= 0)
826 save_backtrace (fd, err, description_sp, false);
827 }
828 else if (err == -1)
829 {
830 if (err_errno.get_errno() == EBADF && fd != -1)
831 {
832 backtrace_log ("\nerror: close on fd=%d resulted in EBADF in process %i\n", fd, getpid());
833
834 FDEventMap::iterator pos = g_fd_event_map.find (fd);
835 if (pos != g_fd_event_map.end())
836 {
837 log (get_logging_fd(), pos->second.back().get(), "\nfd=%d was previously closed with this event:\n", fd);
838 }
839 }
840 }
841 return err;
842}
843
844//----------------------------------------------------------------------
845// close$NOCANCEL() interpose function
846//----------------------------------------------------------------------
847extern "C" int close$NOCANCEL(int);
848extern "C" int
849close$NOCANCEL$__interposed__ (int fd)
850{
851 Locker locker (&g_mutex);
852 const int err = close$NOCANCEL(fd);
853 NegativeErrorErrno err_errno(err);
854 StringSP description_sp (new String);
855 if (err == -1)
856 description_sp->printf("close$NOCANCEL (fd=%i) => %i errno = %i (%s))", fd, err, err_errno.get_errno(), strerror(err_errno.get_errno()));
857 else
858 description_sp->printf("close$NOCANCEL (fd=%i) => %i", fd, err);
859 if (g_log_all_calls)
860 description_sp->log (get_logging_fd());
861
862 if (err == 0)
863 {
864 if (fd >= 0)
865 save_backtrace (fd, err, description_sp, false);
866 }
867 else if (err == -1)
868 {
869 if (err_errno.get_errno() == EBADF && fd != -1)
870 {
871 backtrace_log ("\nInvoking close$NOCANCEL (fd=%d) in process %i resulted in %i %s\n", fd, getpid(), err_errno.get_errno(), err_errno.get_errno() ? strerror (err_errno.get_errno()) : "");
872
873 FDEventMap::iterator pos = g_fd_event_map.find (fd);
874 if (pos != g_fd_event_map.end())
875 {
876 log (get_logging_fd(), pos->second.back().get(), "\nPrevious close(fd=%d) was done here:\n", fd);
877 }
878 }
879 }
880 return err;
881
882}
883
884//----------------------------------------------------------------------
885// pipe() interpose function
886//----------------------------------------------------------------------
887extern "C" int
888pipe$__interposed__ (int fds[2])
889{
890 Locker locker (&g_mutex);
891 fds[0] = -1;
892 fds[1] = -1;
893 const int err = pipe (fds);
894 const int saved_errno = errno;
895 StringSP description_sp(new String ("pipe ({fd=%i, fd=%i}) -> err=%i", fds[0], fds[1], err));
896 if (g_log_all_calls)
897 description_sp->log (get_logging_fd());
898 if (fds[0] >= 0)
899 save_backtrace (fds[0], saved_errno, description_sp, true);
900 if (fds[1] >= 0)
901 save_backtrace (fds[1], saved_errno, description_sp, true);
902 errno = saved_errno;
903 return err;
904}
905
906//----------------------------------------------------------------------
907// get_fd_history()
908//
909// This function allows runtime access to the file descriptor history.
910//
911// @param[in] log_fd
912// The file descriptor to log to
913//
914// @param[in] fd
915// The file descriptor whose history should be dumped
916//----------------------------------------------------------------------
917extern "C" void
918get_fd_history (int log_fd, int fd)
919{
920 // "create" below needs to be outside of the mutex locker scope
921 if (log_fd >= 0)
922 {
923 bool got_lock = false;
924 Locker locker (&g_mutex, got_lock);
925 if (got_lock)
926 {
927 FDEventMap::iterator pos = g_fd_event_map.find (fd);
928 log_to_fd (log_fd, "Dumping file descriptor history for fd=%i:\n", fd);
929 if (pos != g_fd_event_map.end())
930 {
931 FDEventArray &event_array = g_fd_event_map[fd];
932 const size_t num_events = event_array.size();
933 for (size_t i=0; i<num_events; ++i)
934 event_array[i]->Dump (log_fd);
935 }
936 else
937 {
938 log_to_fd (log_fd, "error: no file descriptor events found for fd=%i\n", fd);
939 }
940 }
941 else
942 {
943 log_to_fd (log_fd, "error: fd event mutex is locked...\n");
944 }
945 }
946}
947
948//----------------------------------------------------------------------
949// Interposing
950//----------------------------------------------------------------------
951// FD creation routines
952DYLD_INTERPOSE(accept$__interposed__, accept);
953DYLD_INTERPOSE(accept$NOCANCEL$__interposed__, accept$NOCANCEL);
954DYLD_INTERPOSE(dup$__interposed__, dup);
955DYLD_INTERPOSE(dup2$__interposed__, dup2);
956DYLD_INTERPOSE(kqueue$__interposed__, kqueue);
957DYLD_INTERPOSE(open$__interposed__, open);
958DYLD_INTERPOSE(open$NOCANCEL$__interposed__, open$NOCANCEL);
959DYLD_INTERPOSE(open$NOCANCEL$__interposed__, __open_nocancel);
960DYLD_INTERPOSE(__open_extended$__interposed__, __open_extended);
961DYLD_INTERPOSE(pipe$__interposed__, pipe);
962DYLD_INTERPOSE(shm_open$__interposed__, shm_open);
963DYLD_INTERPOSE(socket$__interposed__, socket);
964DYLD_INTERPOSE(socketpair$__interposed__, socketpair);
965
966// FD deleting routines
967DYLD_INTERPOSE(close$__interposed__, close);
968DYLD_INTERPOSE(close$NOCANCEL$__interposed__, close$NOCANCEL);
969
970} // namespace fd_interposing
971
972