diff options
Diffstat (limited to 'lldb/examples/interposing/darwin/fd_interposing/FDInterposing.cpp')
-rw-r--r-- | lldb/examples/interposing/darwin/fd_interposing/FDInterposing.cpp | 1533 |
1 files changed, 683 insertions, 850 deletions
diff --git a/lldb/examples/interposing/darwin/fd_interposing/FDInterposing.cpp b/lldb/examples/interposing/darwin/fd_interposing/FDInterposing.cpp index e41dc34038b..105251c9574 100644 --- a/lldb/examples/interposing/darwin/fd_interposing/FDInterposing.cpp +++ b/lldb/examples/interposing/darwin/fd_interposing/FDInterposing.cpp @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This file helps with catching double close calls on unix integer file -// descriptors by interposing functions for all file descriptor create and +// This file helps with catching double close calls on unix integer file +// descriptors by interposing functions for all file descriptor create and // close operations. A stack backtrace for every create and close function is // maintained, and every create and close operation is logged. When a double // file descriptor close is encountered, it will be logged. @@ -18,20 +18,21 @@ // For sh: // DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib /path/to/executable // For tcsh: -// (setenv DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib ; /path/to/executable) +// (setenv DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib ; +// /path/to/executable) // // Other environment variables that can alter the default actions of this // interposing shared library include: // // "FileDescriptorStackLoggingNoCompact" // -// With this environment variable set, all file descriptor create and -// delete operations will be permanantly maintained in the event map. +// With this environment variable set, all file descriptor create and +// delete operations will be permanantly maintained in the event map. // The default action is to compact the create/delete events by removing -// any previous file descriptor create events that are matched with a +// any previous file descriptor create events that are matched with a // corresponding file descriptor delete event when the next valid file // descriptor create event is detected. -// +// // "FileDescriptorMinimalLogging" // // By default every file descriptor create and delete operation is logged @@ -49,39 +50,40 @@ #include <assert.h> #include <dirent.h> #include <errno.h> -#include <fcntl.h> #include <execinfo.h> +#include <fcntl.h> #include <libgen.h> -#include <mach-o/dyld.h> #include <mach-o/dyld-interposing.h> -#include <stdlib.h> +#include <mach-o/dyld.h> +#include <map> #include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <string> #include <sys/event.h> #include <sys/mman.h> #include <sys/socket.h> -#include <sys/types.h> #include <sys/time.h> +#include <sys/types.h> #include <tr1/memory> // for std::tr1::shared_ptr #include <unistd.h> -#include <string> #include <vector> -#include <map> //---------------------------------------------------------------------- /// @def DISALLOW_COPY_AND_ASSIGN(TypeName) /// Macro definition for easily disallowing copy constructor and /// assignment operators in C++ classes. //---------------------------------------------------------------------- -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ -TypeName(const TypeName&); \ -const TypeName& operator=(const TypeName&) +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName &); \ + const TypeName &operator=(const TypeName &) extern "C" { - int accept$NOCANCEL (int, struct sockaddr * __restrict, socklen_t * __restrict); - int close$NOCANCEL(int); - int open$NOCANCEL(const char *, int, ...); - int __open_extended(const char *, int, uid_t, gid_t, int, struct kauth_filesec *); +int accept$NOCANCEL(int, struct sockaddr *__restrict, socklen_t *__restrict); +int close$NOCANCEL(int); +int open$NOCANCEL(const char *, int, ...); +int __open_extended(const char *, int, uid_t, gid_t, int, + struct kauth_filesec *); } namespace fd_interposing { @@ -90,76 +92,55 @@ namespace fd_interposing { // String class so we can get formatted strings without having to worry // about the memory storage since it will allocate the memory it needs. //---------------------------------------------------------------------- -class String -{ +class String { public: - String () : - m_str (NULL) - {} - - String (const char *format, ...) : - m_str (NULL) - { - va_list args; - va_start (args, format); - vprintf (format, args); - va_end (args); - } - - ~String() - { - reset(); - } - - void - reset (char *s = NULL) - { - if (m_str) - ::free (m_str); - m_str = s; - } - - const char * - c_str () const - { - return m_str; - } + String() : m_str(NULL) {} + + String(const char *format, ...) : m_str(NULL) { + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + } + + ~String() { reset(); } + + void reset(char *s = NULL) { + if (m_str) + ::free(m_str); + m_str = s; + } + + const char *c_str() const { return m_str; } + + void printf(const char *format, ...) { + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + } + void vprintf(const char *format, va_list args) { + reset(); + ::vasprintf(&m_str, format, args); + } + + void log(int log_fd) { + if (m_str && log_fd >= 0) { + const int len = strlen(m_str); + if (len > 0) { + write(log_fd, m_str, len); + const char last_char = m_str[len - 1]; + if (!(last_char == '\n' || last_char == '\r')) + write(log_fd, "\n", 1); + } + } + } - void - printf (const char *format, ...) - { - va_list args; - va_start (args, format); - vprintf (format, args); - va_end (args); - } - void - vprintf (const char *format, va_list args) - { - reset(); - ::vasprintf (&m_str, format, args); - } - - void - log (int log_fd) - { - if (m_str && log_fd >= 0) - { - const int len = strlen(m_str); - if (len > 0) - { - write (log_fd, m_str, len); - const char last_char = m_str[len-1]; - if (!(last_char == '\n' || last_char == '\r')) - write (log_fd, "\n", 1); - } - } - } protected: - char *m_str; - + char *m_str; + private: - DISALLOW_COPY_AND_ASSIGN (String); + DISALLOW_COPY_AND_ASSIGN(String); }; //---------------------------------------------------------------------- @@ -171,7 +152,6 @@ typedef std::vector<void *> Frames; typedef std::tr1::shared_ptr<FDEvent> FDEventSP; typedef std::tr1::shared_ptr<String> StringSP; - //---------------------------------------------------------------------- // FDEvent // @@ -180,115 +160,75 @@ typedef std::tr1::shared_ptr<String> StringSP; // File descriptor events fall into one of two categories: create events // and delete events. //---------------------------------------------------------------------- -class FDEvent -{ +class FDEvent { public: - FDEvent (int fd, int err, const StringSP &string_sp, bool is_create, const Frames& frames) : - m_string_sp (string_sp), - m_frames (frames.begin(), frames.end()), - m_fd (fd), - m_err (err), - m_is_create (is_create) - {} - - ~FDEvent () {} - - bool - IsCreateEvent() const - { - return m_is_create; - } + FDEvent(int fd, int err, const StringSP &string_sp, bool is_create, + const Frames &frames) + : m_string_sp(string_sp), m_frames(frames.begin(), frames.end()), + m_fd(fd), m_err(err), m_is_create(is_create) {} - bool - IsDeleteEvent() const - { - return !m_is_create; - } + ~FDEvent() {} - Frames & - GetFrames () - { - return m_frames; - } + bool IsCreateEvent() const { return m_is_create; } - const Frames & - GetFrames () const - { - return m_frames; - } - - int - GetFD () const - { - return m_fd; - } + bool IsDeleteEvent() const { return !m_is_create; } - int - GetError () const - { - return m_err; - } - - void - Dump (int log_fd) const; - - void - SetCreateEvent (FDEventSP &create_event_sp) - { - m_create_event_sp = create_event_sp; - } + Frames &GetFrames() { return m_frames; } + + const Frames &GetFrames() const { return m_frames; } + + int GetFD() const { return m_fd; } + + int GetError() const { return m_err; } + + void Dump(int log_fd) const; + + void SetCreateEvent(FDEventSP &create_event_sp) { + m_create_event_sp = create_event_sp; + } private: - // A shared pointer to a String that describes this event in - // detail (all args and return and error values) - StringSP m_string_sp; - // The frames for the stack backtrace for this event - Frames m_frames; - // If this is a file descriptor delete event, this might contain - // the correspoding file descriptor create event - FDEventSP m_create_event_sp; - // The file descriptor for this event - int m_fd; - // The error code (if any) for this event - int m_err; - // True if this event is a file descriptor create event, false - // if it is a file descriptor delete event - bool m_is_create; + // A shared pointer to a String that describes this event in + // detail (all args and return and error values) + StringSP m_string_sp; + // The frames for the stack backtrace for this event + Frames m_frames; + // If this is a file descriptor delete event, this might contain + // the correspoding file descriptor create event + FDEventSP m_create_event_sp; + // The file descriptor for this event + int m_fd; + // The error code (if any) for this event + int m_err; + // True if this event is a file descriptor create event, false + // if it is a file descriptor delete event + bool m_is_create; }; //---------------------------------------------------------------------- -// Templatized class that will save errno only if the "value" it is -// constructed with is equal to INVALID. When the class goes out of +// Templatized class that will save errno only if the "value" it is +// constructed with is equal to INVALID. When the class goes out of // scope, it will restore errno if it was saved. //---------------------------------------------------------------------- -template <int INVALID> -class Errno -{ +template <int INVALID> class Errno { public: - // Save errno only if we are supposed to - Errno (int value) : - m_saved_errno ((value == INVALID) ? errno : 0), - m_restore (value == INVALID) - { - } - - // Restore errno only if we are supposed to - ~Errno() - { - if (m_restore) - errno = m_saved_errno; - } + // Save errno only if we are supposed to + Errno(int value) + : m_saved_errno((value == INVALID) ? errno : 0), + m_restore(value == INVALID) {} - // Accessor for the saved value of errno - int - get_errno() const - { - return m_saved_errno; - } + // Restore errno only if we are supposed to + ~Errno() { + if (m_restore) + errno = m_saved_errno; + } + + // Accessor for the saved value of errno + int get_errno() const { return m_saved_errno; } protected: - const int m_saved_errno; - const bool m_restore; + const int m_saved_errno; + const bool m_restore; }; typedef Errno<-1> InvalidFDErrno; @@ -303,12 +243,13 @@ typedef std::map<int, FDEventArray> FDEventMap; // descriptor create and close events come in, they will get filled // into this map (protected by g_mutex). When a file descriptor close // event is detected, the open event will be removed and placed into -// the close event so if something tries to double close a file -// descriptor we can show the previous close event and the file +// the close event so if something tries to double close a file +// descriptor we can show the previous close event and the file // desctiptor event that created it. When a new file descriptor create -// event comes in, we will remove the previous one for that file -// desctiptor unless the environment variable "FileDescriptorStackLoggingNoCompact" -// is set. The file desctiptor history can be accessed using the +// event comes in, we will remove the previous one for that file +// desctiptor unless the environment variable +// "FileDescriptorStackLoggingNoCompact" +// is set. The file desctiptor history can be accessed using the // get_fd_history() function. static FDEventMap g_fd_event_map; // A mutex to protect access to our data structures in g_fd_event_map @@ -328,760 +269,662 @@ static bool g_enabled = true; // Mutex class that will lock a mutex when it is constructed, and unlock // it when is goes out of scope //---------------------------------------------------------------------- -class Locker -{ +class Locker { public: - Locker (pthread_mutex_t *mutex_ptr) : - m_mutex_ptr(mutex_ptr) - { - ::pthread_mutex_lock (m_mutex_ptr); - } - - // This allows clients to test try and acquire the mutex... - Locker (pthread_mutex_t *mutex_ptr, bool &lock_acquired) : - m_mutex_ptr(NULL) - { - lock_acquired = ::pthread_mutex_trylock(mutex_ptr) == 0; - if (lock_acquired) - m_mutex_ptr = mutex_ptr; - } + Locker(pthread_mutex_t *mutex_ptr) : m_mutex_ptr(mutex_ptr) { + ::pthread_mutex_lock(m_mutex_ptr); + } + + // This allows clients to test try and acquire the mutex... + Locker(pthread_mutex_t *mutex_ptr, bool &lock_acquired) : m_mutex_ptr(NULL) { + lock_acquired = ::pthread_mutex_trylock(mutex_ptr) == 0; + if (lock_acquired) + m_mutex_ptr = mutex_ptr; + } + + ~Locker() { + if (m_mutex_ptr) + ::pthread_mutex_unlock(m_mutex_ptr); + } - ~Locker () - { - if (m_mutex_ptr) - ::pthread_mutex_unlock (m_mutex_ptr); - } protected: - pthread_mutex_t *m_mutex_ptr; + pthread_mutex_t *m_mutex_ptr; }; -static void -log (const char *format, ...) __attribute__ ((format (printf, 1, 2))); +static void log(const char *format, ...) __attribute__((format(printf, 1, 2))); -static void -log (int log_fd, const FDEvent *event, const char *format, ...) __attribute__ ((format (printf, 3, 4))); +static void log(int log_fd, const FDEvent *event, const char *format, ...) + __attribute__((format(printf, 3, 4))); -static void -backtrace_log (const char *format, ...) __attribute__ ((format (printf, 1, 2))); +static void backtrace_log(const char *format, ...) + __attribute__((format(printf, 1, 2))); -static void -backtrace_error (const char *format, ...) __attribute__ ((format (printf, 1, 2))); +static void backtrace_error(const char *format, ...) + __attribute__((format(printf, 1, 2))); -static void -log_to_fd (int log_fd, const char *format, ...) __attribute__ ((format (printf, 2, 3))); +static void log_to_fd(int log_fd, const char *format, ...) + __attribute__((format(printf, 2, 3))); -static inline size_t -get_backtrace (Frames &frame_buffer, size_t frames_to_remove) -{ - void *frames[2048]; - int count = ::backtrace (&frames[0], sizeof(frames)/sizeof(void*)); - if (count > frames_to_remove) - frame_buffer.assign (&frames[frames_to_remove], &frames[count]); - else - frame_buffer.assign (&frames[0], &frames[count]); - while (frame_buffer.back() < (void *)1024) - frame_buffer.pop_back(); - return frame_buffer.size(); +static inline size_t get_backtrace(Frames &frame_buffer, + size_t frames_to_remove) { + void *frames[2048]; + int count = ::backtrace(&frames[0], sizeof(frames) / sizeof(void *)); + if (count > frames_to_remove) + frame_buffer.assign(&frames[frames_to_remove], &frames[count]); + else + frame_buffer.assign(&frames[0], &frames[count]); + while (frame_buffer.back() < (void *)1024) + frame_buffer.pop_back(); + return frame_buffer.size(); } static int g_log_fd = STDOUT_FILENO; static int g_initialized = 0; -const char * -get_process_fullpath (bool force = false) -{ - static char g_process_fullpath[PATH_MAX] = {0}; - if (force || g_process_fullpath[0] == '\0') - { - // If DST is NULL, then return the number of bytes needed. - uint32_t len = sizeof(g_process_fullpath); - if (_NSGetExecutablePath (g_process_fullpath, &len) != 0) - strncpy (g_process_fullpath, "<error>", sizeof(g_process_fullpath)); - } - return g_process_fullpath; +const char *get_process_fullpath(bool force = false) { + static char g_process_fullpath[PATH_MAX] = {0}; + if (force || g_process_fullpath[0] == '\0') { + // If DST is NULL, then return the number of bytes needed. + uint32_t len = sizeof(g_process_fullpath); + if (_NSGetExecutablePath(g_process_fullpath, &len) != 0) + strncpy(g_process_fullpath, "<error>", sizeof(g_process_fullpath)); + } + return g_process_fullpath; } // Returns the current process ID, or -1 if inserposing not enabled for // this process -static int -get_interposed_pid() -{ - if (!g_enabled) - return -1; - - const pid_t pid = getpid(); - if (g_pid != pid) - { - if (g_pid == -1) - { - g_pid = pid; - log ("Interposing file descriptor create and delete functions for %s (pid=%i)\n", get_process_fullpath (true), pid); - } - else - { - 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); - g_enabled = false; - return -1; - } - // Log when our process changes - } - return g_pid; +static int get_interposed_pid() { + if (!g_enabled) + return -1; + + const pid_t pid = getpid(); + if (g_pid != pid) { + if (g_pid == -1) { + g_pid = pid; + log("Interposing file descriptor create and delete functions for %s " + "(pid=%i)\n", + get_process_fullpath(true), pid); + } else { + 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); + g_enabled = false; + return -1; + } + // Log when our process changes + } + return g_pid; } -static int -get_logging_fd () -{ - if (!g_enabled) - return -1; - - if (!g_initialized) - { - g_initialized = 1; - - const pid_t pid = get_interposed_pid(); - - if (g_enabled) - { - // Keep all stack info around for all fd create and delete calls. - // Otherwise we will remove the fd create call when a corresponding - // fd delete call is received - if (getenv("FileDescriptorStackLoggingNoCompact")) - g_compact = 0; - - if (getenv("FileDescriptorMinimalLogging")) - g_log_all_calls = 0; - - const char *log_path = getenv ("FileDescriptorLogFile"); - if (log_path) - g_log_fd = ::creat (log_path, 0660); - else - g_log_fd = STDOUT_FILENO; - - // Only let this interposing happen on the first time this matches - // and stop this from happening so any child processes don't also - // log their file descriptors - ::unsetenv ("DYLD_INSERT_LIBRARIES"); - } - else - { - log ("pid=%i: logging disabled\n", getpid()); - } - } - return g_log_fd; -} +static int get_logging_fd() { + if (!g_enabled) + return -1; + + if (!g_initialized) { + g_initialized = 1; + + const pid_t pid = get_interposed_pid(); + + if (g_enabled) { + // Keep all stack info around for all fd create and delete calls. + // Otherwise we will remove the fd create call when a corresponding + // fd delete call is received + if (getenv("FileDescriptorStackLoggingNoCompact")) + g_compact = 0; -void -log_to_fd (int log_fd, const char *format, va_list args) -{ - if (format && format[0] && log_fd >= 0) - { - char buffer[PATH_MAX]; - const int count = ::vsnprintf (buffer, sizeof(buffer), format, args); - if (count > 0) - write (log_fd, buffer, count); + if (getenv("FileDescriptorMinimalLogging")) + g_log_all_calls = 0; + + const char *log_path = getenv("FileDescriptorLogFile"); + if (log_path) + g_log_fd = ::creat(log_path, 0660); + else + g_log_fd = STDOUT_FILENO; + + // Only let this interposing happen on the first time this matches + // and stop this from happening so any child processes don't also + // log their file descriptors + ::unsetenv("DYLD_INSERT_LIBRARIES"); + } else { + log("pid=%i: logging disabled\n", getpid()); } + } + return g_log_fd; } -void -log_to_fd (int log_fd, const char *format, ...) -{ - if (format && format[0]) - { - va_list args; - va_start (args, format); - log_to_fd (log_fd, format, args); - va_end (args); - } +void log_to_fd(int log_fd, const char *format, va_list args) { + if (format && format[0] && log_fd >= 0) { + char buffer[PATH_MAX]; + const int count = ::vsnprintf(buffer, sizeof(buffer), format, args); + if (count > 0) + write(log_fd, buffer, count); + } } -void -log (const char *format, va_list args) -{ - log_to_fd (get_logging_fd (), format, args); +void log_to_fd(int log_fd, const char *format, ...) { + if (format && format[0]) { + va_list args; + va_start(args, format); + log_to_fd(log_fd, format, args); + va_end(args); + } } -void -log (const char *format, ...) -{ - if (format && format[0]) - { - va_list args; - va_start (args, format); - log (format, args); - va_end (args); - } +void log(const char *format, va_list args) { + log_to_fd(get_logging_fd(), format, args); } -void -log (int log_fd, const FDEvent *event, const char *format, ...) -{ - if (format && format[0]) - { - va_list args; - va_start (args, format); - log_to_fd (log_fd, format, args); - va_end (args); - } - if (event) - event->Dump(log_fd); +void log(const char *format, ...) { + if (format && format[0]) { + va_list args; + va_start(args, format); + log(format, args); + va_end(args); + } } -void -FDEvent::Dump (int log_fd) const -{ - if (log_fd >= 0) - { - log_to_fd (log_fd, "%s\n", m_string_sp->c_str()); - if (!m_frames.empty()) - ::backtrace_symbols_fd (m_frames.data(), m_frames.size(), log_fd); - - if (m_create_event_sp) - { - log_to_fd (log_fd, "\nfd=%i was created with this event:\n", m_fd); - m_create_event_sp->Dump (log_fd); - log_to_fd (log_fd, "\n"); - } - } +void log(int log_fd, const FDEvent *event, const char *format, ...) { + if (format && format[0]) { + va_list args; + va_start(args, format); + log_to_fd(log_fd, format, args); + va_end(args); + } + if (event) + event->Dump(log_fd); } +void FDEvent::Dump(int log_fd) const { + if (log_fd >= 0) { + log_to_fd(log_fd, "%s\n", m_string_sp->c_str()); + if (!m_frames.empty()) + ::backtrace_symbols_fd(m_frames.data(), m_frames.size(), log_fd); -void -backtrace_log (const char *format, ...) -{ - const int log_fd = get_logging_fd (); - if (log_fd >= 0) - { - if (format && format[0]) - { - va_list args; - va_start (args, format); - log (format, args); - va_end (args); - } - - Frames frames; - if (get_backtrace(frames, 2)) - ::backtrace_symbols_fd (frames.data(), frames.size(), log_fd); + if (m_create_event_sp) { + log_to_fd(log_fd, "\nfd=%i was created with this event:\n", m_fd); + m_create_event_sp->Dump(log_fd); + log_to_fd(log_fd, "\n"); } - + } } -void -backtrace_error (const char *format, ...) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - const int log_fd = get_logging_fd (); - if (log_fd >= 0) - { - log ("\nerror: %s (pid=%i): ", get_process_fullpath (), pid); - - if (format && format[0]) - { - va_list args; - va_start (args, format); - log (format, args); - va_end (args); - } - - Frames frames; - if (get_backtrace(frames, 2)) - ::backtrace_symbols_fd (frames.data(), frames.size(), log_fd); - } +void backtrace_log(const char *format, ...) { + const int log_fd = get_logging_fd(); + if (log_fd >= 0) { + if (format && format[0]) { + va_list args; + va_start(args, format); + log(format, args); + va_end(args); } -} -void -save_backtrace (int fd, int err, const StringSP &string_sp, bool is_create) -{ Frames frames; - get_backtrace(frames, 2); + if (get_backtrace(frames, 2)) + ::backtrace_symbols_fd(frames.data(), frames.size(), log_fd); + } +} - FDEventSP fd_event_sp (new FDEvent (fd, err, string_sp, is_create, frames)); +void backtrace_error(const char *format, ...) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + const int log_fd = get_logging_fd(); + if (log_fd >= 0) { + log("\nerror: %s (pid=%i): ", get_process_fullpath(), pid); - FDEventMap::iterator pos = g_fd_event_map.find (fd); - - if (pos != g_fd_event_map.end()) - { - // We have history for this fd... - - FDEventArray &event_array = g_fd_event_map[fd]; - if (fd_event_sp->IsCreateEvent()) - { - // The current fd event is a function that creates - // a descriptor, check in case last event was - // a create event. - if (event_array.back()->IsCreateEvent()) - { - const int log_fd = get_logging_fd(); - // Two fd create functions in a row, we missed - // a function that closes a fd... - log (log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor create event fd=%i (we missed a file descriptor close event):\n", fd); - } - else if (g_compact) - { - // We are compacting so we remove previous create event - // when we get the correspinding delete event - event_array.pop_back(); - } - } - else - { - // The current fd event is a function that deletes - // a descriptor, check in case last event for this - // fd was a delete event (double close!) - if (event_array.back()->IsDeleteEvent()) - { - const int log_fd = get_logging_fd(); - // Two fd delete functions in a row, we must - // have missed some function that opened a descriptor - 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); - } - else if (g_compact) - { - // Since this is a close event, we want to remember the open event - // that this close if for... - fd_event_sp->SetCreateEvent(event_array.back()); - // We are compacting so we remove previous create event - // when we get the correspinding delete event - event_array.pop_back(); - } - } - - event_array.push_back(fd_event_sp); - } - else - { - g_fd_event_map[fd].push_back(fd_event_sp); + if (format && format[0]) { + va_list args; + va_start(args, format); + log(format, args); + va_end(args); + } + + Frames frames; + if (get_backtrace(frames, 2)) + ::backtrace_symbols_fd(frames.data(), frames.size(), log_fd); } + } +} + +void save_backtrace(int fd, int err, const StringSP &string_sp, + bool is_create) { + Frames frames; + get_backtrace(frames, 2); + + FDEventSP fd_event_sp(new FDEvent(fd, err, string_sp, is_create, frames)); + + FDEventMap::iterator pos = g_fd_event_map.find(fd); + + if (pos != g_fd_event_map.end()) { + // We have history for this fd... + + FDEventArray &event_array = g_fd_event_map[fd]; + if (fd_event_sp->IsCreateEvent()) { + // The current fd event is a function that creates + // a descriptor, check in case last event was + // a create event. + if (event_array.back()->IsCreateEvent()) { + const int log_fd = get_logging_fd(); + // Two fd create functions in a row, we missed + // a function that closes a fd... + log(log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor " + "create event fd=%i (we missed a file " + "descriptor close event):\n", + fd); + } else if (g_compact) { + // We are compacting so we remove previous create event + // when we get the correspinding delete event + event_array.pop_back(); + } + } else { + // The current fd event is a function that deletes + // a descriptor, check in case last event for this + // fd was a delete event (double close!) + if (event_array.back()->IsDeleteEvent()) { + const int log_fd = get_logging_fd(); + // Two fd delete functions in a row, we must + // have missed some function that opened a descriptor + 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); + } else if (g_compact) { + // Since this is a close event, we want to remember the open event + // that this close if for... + fd_event_sp->SetCreateEvent(event_array.back()); + // We are compacting so we remove previous create event + // when we get the correspinding delete event + event_array.pop_back(); + } + } + + event_array.push_back(fd_event_sp); + } else { + g_fd_event_map[fd].push_back(fd_event_sp); + } } //---------------------------------------------------------------------- // socket() interpose function //---------------------------------------------------------------------- -extern "C" int -socket$__interposed__ (int domain, int type, int protocol) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - const int fd = ::socket (domain, type, protocol); - InvalidFDErrno fd_errno(fd); - StringSP description_sp(new String); - if (fd == -1) - 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()); - else - description_sp->printf("pid=%i: socket (domain = %i, type = %i, protocol = %i) => fd=%i", pid, domain, type, protocol, fd); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - if (fd >= 0) - save_backtrace (fd, fd_errno.get_errno(), description_sp, true); - return fd; - } +extern "C" int socket$__interposed__(int domain, int type, int protocol) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::socket(domain, type, protocol); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String); + if (fd == -1) + 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()); else - { - return ::socket (domain, type, protocol); - } + description_sp->printf( + "pid=%i: socket (domain = %i, type = %i, protocol = %i) => fd=%i", + pid, domain, type, protocol, fd); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::socket(domain, type, protocol); + } } //---------------------------------------------------------------------- // socketpair() interpose function //---------------------------------------------------------------------- -extern "C" int -socketpair$__interposed__ (int domain, int type, int protocol, int fds[2]) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - fds[0] = -1; - fds[1] = -1; - const int err = socketpair (domain, type, protocol, fds); - NegativeErrorErrno err_errno(err); - 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)); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - if (fds[0] >= 0) - save_backtrace (fds[0], err_errno.get_errno(), description_sp, true); - if (fds[1] >= 0) - save_backtrace (fds[1], err_errno.get_errno(), description_sp, true); - return err; - } - else - { - return socketpair (domain, type, protocol, fds); - } +extern "C" int socketpair$__interposed__(int domain, int type, int protocol, + int fds[2]) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + fds[0] = -1; + fds[1] = -1; + const int err = socketpair(domain, type, protocol, fds); + NegativeErrorErrno err_errno(err); + 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)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fds[0] >= 0) + save_backtrace(fds[0], err_errno.get_errno(), description_sp, true); + if (fds[1] >= 0) + save_backtrace(fds[1], err_errno.get_errno(), description_sp, true); + return err; + } else { + return socketpair(domain, type, protocol, fds); + } } //---------------------------------------------------------------------- // open() interpose function //---------------------------------------------------------------------- -extern "C" int -open$__interposed__ (const char *path, int oflag, int mode) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - int fd = -2; - StringSP description_sp(new String); - if (oflag & O_CREAT) - { - fd = ::open (path, oflag, mode); - description_sp->printf("pid=%i: open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, path, oflag, mode, fd); - } - else - { - fd = ::open (path, oflag); - description_sp->printf("pid=%i: open (path = '%s', oflag = %i) -> fd=%i", pid, path, oflag, fd); - } - - InvalidFDErrno fd_errno(fd); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - if (fd >= 0) - save_backtrace (fd, fd_errno.get_errno(), description_sp, true); - return fd; - } - else - { - return ::open (path, oflag, mode); - } +extern "C" int open$__interposed__(const char *path, int oflag, int mode) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + int fd = -2; + StringSP description_sp(new String); + if (oflag & O_CREAT) { + fd = ::open(path, oflag, mode); + description_sp->printf( + "pid=%i: open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, + path, oflag, mode, fd); + } else { + fd = ::open(path, oflag); + description_sp->printf("pid=%i: open (path = '%s', oflag = %i) -> fd=%i", + pid, path, oflag, fd); + } + + InvalidFDErrno fd_errno(fd); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::open(path, oflag, mode); + } } //---------------------------------------------------------------------- // open$NOCANCEL() interpose function //---------------------------------------------------------------------- -extern "C" int -open$NOCANCEL$__interposed__ (const char *path, int oflag, int mode) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - const int fd = ::open$NOCANCEL (path, oflag, mode); - InvalidFDErrno fd_errno(fd); - StringSP description_sp(new String ("pid=%i: open$NOCANCEL (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, path, oflag, mode, fd)); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - if (fd >= 0) - save_backtrace (fd, fd_errno.get_errno(), description_sp, true); - return fd; - } - else - { - return ::open$NOCANCEL (path, oflag, mode); - } +extern "C" int open$NOCANCEL$__interposed__(const char *path, int oflag, + int mode) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::open$NOCANCEL(path, oflag, mode); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String( + "pid=%i: open$NOCANCEL (path = '%s', oflag = %i, mode = %i) -> fd=%i", + pid, path, oflag, mode, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::open$NOCANCEL(path, oflag, mode); + } } - //---------------------------------------------------------------------- // __open_extended() interpose function //---------------------------------------------------------------------- -extern "C" int -__open_extended$__interposed__ (const char *path, int oflag, uid_t uid, gid_t gid, int mode, struct kauth_filesec *fsacl) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - const int fd = ::__open_extended (path, oflag, uid, gid, mode, fsacl); - InvalidFDErrno fd_errno(fd); - 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)); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - if (fd >= 0) - save_backtrace (fd, fd_errno.get_errno(), description_sp, true); - return fd; - } - else - { - return ::__open_extended (path, oflag, uid, gid, mode, fsacl); - } +extern "C" int __open_extended$__interposed__(const char *path, int oflag, + uid_t uid, gid_t gid, int mode, + struct kauth_filesec *fsacl) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::__open_extended(path, oflag, uid, gid, mode, fsacl); + InvalidFDErrno fd_errno(fd); + 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)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::__open_extended(path, oflag, uid, gid, mode, fsacl); + } } //---------------------------------------------------------------------- // kqueue() interpose function //---------------------------------------------------------------------- -extern "C" int -kqueue$__interposed__ (void) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - const int fd = ::kqueue (); - InvalidFDErrno fd_errno(fd); - StringSP description_sp(new String ("pid=%i: kqueue () -> fd=%i", pid, fd)); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - if (fd >= 0) - save_backtrace (fd, fd_errno.get_errno(), description_sp, true); - return fd; - } - else - { - return ::kqueue (); - } +extern "C" int kqueue$__interposed__(void) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::kqueue(); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String("pid=%i: kqueue () -> fd=%i", pid, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::kqueue(); + } } //---------------------------------------------------------------------- // shm_open() interpose function //---------------------------------------------------------------------- -extern "C" int -shm_open$__interposed__ (const char *path, int oflag, int mode) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - const int fd = ::shm_open (path, oflag, mode); - InvalidFDErrno fd_errno(fd); - StringSP description_sp(new String ("pid=%i: shm_open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, path, oflag, mode, fd)); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - if (fd >= 0) - save_backtrace (fd, fd_errno.get_errno(), description_sp, true); - return fd; - } - else - { - return ::shm_open (path, oflag, mode); - } +extern "C" int shm_open$__interposed__(const char *path, int oflag, int mode) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::shm_open(path, oflag, mode); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String( + "pid=%i: shm_open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, + path, oflag, mode, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::shm_open(path, oflag, mode); + } } //---------------------------------------------------------------------- // accept() interpose function //---------------------------------------------------------------------- -extern "C" int -accept$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - const int fd = ::accept (socket, address, address_len); - InvalidFDErrno fd_errno(fd); - StringSP description_sp(new String ("pid=%i: accept (socket=%i, ...) -> fd=%i", pid, socket, fd)); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - if (fd >= 0) - save_backtrace (fd, fd_errno.get_errno(), description_sp, true); - return fd; - } - else - { - return ::accept (socket, address, address_len); - } +extern "C" int accept$__interposed__(int socket, struct sockaddr *address, + socklen_t *address_len) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::accept(socket, address, address_len); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String( + "pid=%i: accept (socket=%i, ...) -> fd=%i", pid, socket, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::accept(socket, address, address_len); + } } - //---------------------------------------------------------------------- // accept$NOCANCEL() interpose function //---------------------------------------------------------------------- -extern "C" int -accept$NOCANCEL$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - const int fd = ::accept$NOCANCEL (socket, address, address_len); - InvalidFDErrno fd_errno(fd); - StringSP description_sp(new String ("pid=%i: accept$NOCANCEL (socket=%i, ...) -> fd=%i", pid, socket, fd)); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - if (fd >= 0) - save_backtrace (fd, fd_errno.get_errno(), description_sp, true); - return fd; - } - else - { - return ::accept$NOCANCEL (socket, address, address_len); - } +extern "C" int accept$NOCANCEL$__interposed__(int socket, + struct sockaddr *address, + socklen_t *address_len) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::accept$NOCANCEL(socket, address, address_len); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String( + "pid=%i: accept$NOCANCEL (socket=%i, ...) -> fd=%i", pid, socket, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::accept$NOCANCEL(socket, address, address_len); + } } //---------------------------------------------------------------------- // dup() interpose function //---------------------------------------------------------------------- -extern "C" int -dup$__interposed__ (int fd2) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - const int fd = ::dup (fd2); - InvalidFDErrno fd_errno(fd); - StringSP description_sp(new String ("pid=%i: dup (fd2=%i) -> fd=%i", pid, fd2, fd)); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - if (fd >= 0) - save_backtrace (fd, fd_errno.get_errno(), description_sp, true); - return fd; - } - else - { - return ::dup (fd2); - } +extern "C" int dup$__interposed__(int fd2) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::dup(fd2); + InvalidFDErrno fd_errno(fd); + StringSP description_sp( + new String("pid=%i: dup (fd2=%i) -> fd=%i", pid, fd2, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::dup(fd2); + } } //---------------------------------------------------------------------- // dup2() interpose function //---------------------------------------------------------------------- -extern "C" int -dup2$__interposed__ (int fd1, int fd2) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - // If "fd2" is already opened, it will be closed during the - // dup2 call below, so we need to see if we have fd2 in our - // open map and treat it as a close(fd2) - FDEventMap::iterator pos = g_fd_event_map.find (fd2); - StringSP dup2_close_description_sp(new String ("pid=%i: dup2 (fd1=%i, fd2=%i) -> will close (fd=%i)", pid, fd1, fd2, fd2)); - if (pos != g_fd_event_map.end() && pos->second.back()->IsCreateEvent()) - save_backtrace (fd2, 0, dup2_close_description_sp, false); - - const int fd = ::dup2(fd1, fd2); - InvalidFDErrno fd_errno(fd); - StringSP description_sp(new String ("pid=%i: dup2 (fd1=%i, fd2=%i) -> fd=%i", pid, fd1, fd2, fd)); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - - if (fd >= 0) - save_backtrace (fd, fd_errno.get_errno(), description_sp, true); - return fd; - } - else - { - return ::dup2(fd1, fd2); - } +extern "C" int dup2$__interposed__(int fd1, int fd2) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + // If "fd2" is already opened, it will be closed during the + // dup2 call below, so we need to see if we have fd2 in our + // open map and treat it as a close(fd2) + FDEventMap::iterator pos = g_fd_event_map.find(fd2); + StringSP dup2_close_description_sp( + new String("pid=%i: dup2 (fd1=%i, fd2=%i) -> will close (fd=%i)", pid, + fd1, fd2, fd2)); + if (pos != g_fd_event_map.end() && pos->second.back()->IsCreateEvent()) + save_backtrace(fd2, 0, dup2_close_description_sp, false); + + const int fd = ::dup2(fd1, fd2); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String("pid=%i: dup2 (fd1=%i, fd2=%i) -> fd=%i", + pid, fd1, fd2, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::dup2(fd1, fd2); + } } //---------------------------------------------------------------------- // close() interpose function //---------------------------------------------------------------------- -extern "C" int -close$__interposed__ (int fd) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - const int err = close(fd); - NegativeErrorErrno err_errno(err); - StringSP description_sp (new String); - if (err == -1) - description_sp->printf("pid=%i: close (fd=%i) => %i errno = %i (%s))", pid, fd, err, err_errno.get_errno(), strerror(err_errno.get_errno())); - else - description_sp->printf("pid=%i: close (fd=%i) => %i", pid, fd, err); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - - if (err == 0) - { - if (fd >= 0) - save_backtrace (fd, err, description_sp, false); - } - else if (err == -1) - { - if (err_errno.get_errno() == EBADF && fd != -1) - { - backtrace_error ("close (fd=%d) resulted in EBADF:\n", fd); - - FDEventMap::iterator pos = g_fd_event_map.find (fd); - if (pos != g_fd_event_map.end()) - { - log (get_logging_fd(), pos->second.back().get(), "\nfd=%d was previously %s with this event:\n", fd, pos->second.back()->IsCreateEvent() ? "opened" : "closed"); - } - } - } - return err; - } +extern "C" int close$__interposed__(int fd) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int err = close(fd); + NegativeErrorErrno err_errno(err); + StringSP description_sp(new String); + if (err == -1) + description_sp->printf("pid=%i: close (fd=%i) => %i errno = %i (%s))", + pid, fd, err, err_errno.get_errno(), + strerror(err_errno.get_errno())); else - { - return close (fd); + description_sp->printf("pid=%i: close (fd=%i) => %i", pid, fd, err); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + + if (err == 0) { + if (fd >= 0) + save_backtrace(fd, err, description_sp, false); + } else if (err == -1) { + if (err_errno.get_errno() == EBADF && fd != -1) { + backtrace_error("close (fd=%d) resulted in EBADF:\n", fd); + + FDEventMap::iterator pos = g_fd_event_map.find(fd); + if (pos != g_fd_event_map.end()) { + log(get_logging_fd(), pos->second.back().get(), + "\nfd=%d was previously %s with this event:\n", fd, + pos->second.back()->IsCreateEvent() ? "opened" : "closed"); + } + } } + return err; + } else { + return close(fd); + } } //---------------------------------------------------------------------- // close$NOCANCEL() interpose function //---------------------------------------------------------------------- -extern "C" int -close$NOCANCEL$__interposed__ (int fd) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - const int err = close$NOCANCEL(fd); - NegativeErrorErrno err_errno(err); - StringSP description_sp (new String); - if (err == -1) - 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())); - else - description_sp->printf("pid=%i: close$NOCANCEL (fd=%i) => %i", pid, fd, err); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - - if (err == 0) - { - if (fd >= 0) - save_backtrace (fd, err, description_sp, false); - } - else if (err == -1) - { - if (err_errno.get_errno() == EBADF && fd != -1) - { - backtrace_error ("close$NOCANCEL (fd=%d) resulted in EBADF\n:", fd); - - FDEventMap::iterator pos = g_fd_event_map.find (fd); - if (pos != g_fd_event_map.end()) - { - log (get_logging_fd(), pos->second.back().get(), "\nfd=%d was previously %s with this event:\n", fd, pos->second.back()->IsCreateEvent() ? "opened" : "closed"); - } - } +extern "C" int close$NOCANCEL$__interposed__(int fd) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int err = close$NOCANCEL(fd); + NegativeErrorErrno err_errno(err); + StringSP description_sp(new String); + if (err == -1) + 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())); + else + description_sp->printf("pid=%i: close$NOCANCEL (fd=%i) => %i", pid, fd, + err); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + + if (err == 0) { + if (fd >= 0) + save_backtrace(fd, err, description_sp, false); + } else if (err == -1) { + if (err_errno.get_errno() == EBADF && fd != -1) { + backtrace_error("close$NOCANCEL (fd=%d) resulted in EBADF\n:", fd); + + FDEventMap::iterator pos = g_fd_event_map.find(fd); + if (pos != g_fd_event_map.end()) { + log(get_logging_fd(), pos->second.back().get(), + "\nfd=%d was previously %s with this event:\n", fd, + pos->second.back()->IsCreateEvent() ? "opened" : "closed"); } - return err; + } } - else - { - return close$NOCANCEL(fd); - } + return err; + } else { + return close$NOCANCEL(fd); + } } //---------------------------------------------------------------------- // pipe() interpose function //---------------------------------------------------------------------- -extern "C" int -pipe$__interposed__ (int fds[2]) -{ - const int pid = get_interposed_pid(); - if (pid >= 0) - { - Locker locker (&g_mutex); - fds[0] = -1; - fds[1] = -1; - const int err = pipe (fds); - const int saved_errno = errno; - StringSP description_sp(new String ("pid=%i: pipe ({fd=%i, fd=%i}) -> err=%i", pid, fds[0], fds[1], err)); - if (g_log_all_calls) - description_sp->log (get_logging_fd()); - if (fds[0] >= 0) - save_backtrace (fds[0], saved_errno, description_sp, true); - if (fds[1] >= 0) - save_backtrace (fds[1], saved_errno, description_sp, true); - errno = saved_errno; - return err; - } - else - { - return pipe (fds); - } +extern "C" int pipe$__interposed__(int fds[2]) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + fds[0] = -1; + fds[1] = -1; + const int err = pipe(fds); + const int saved_errno = errno; + StringSP description_sp(new String( + "pid=%i: pipe ({fd=%i, fd=%i}) -> err=%i", pid, fds[0], fds[1], err)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fds[0] >= 0) + save_backtrace(fds[0], saved_errno, description_sp, true); + if (fds[1] >= 0) + save_backtrace(fds[1], saved_errno, description_sp, true); + errno = saved_errno; + return err; + } else { + return pipe(fds); + } } //---------------------------------------------------------------------- @@ -1095,35 +938,27 @@ pipe$__interposed__ (int fds[2]) // @param[in] fd // The file descriptor whose history should be dumped //---------------------------------------------------------------------- -extern "C" void -get_fd_history (int log_fd, int fd) -{ - // "create" below needs to be outside of the mutex locker scope - if (log_fd >= 0) - { - bool got_lock = false; - Locker locker (&g_mutex, got_lock); - if (got_lock) - { - FDEventMap::iterator pos = g_fd_event_map.find (fd); - log_to_fd (log_fd, "Dumping file descriptor history for fd=%i:\n", fd); - if (pos != g_fd_event_map.end()) - { - FDEventArray &event_array = g_fd_event_map[fd]; - const size_t num_events = event_array.size(); - for (size_t i=0; i<num_events; ++i) - event_array[i]->Dump (log_fd); - } - else - { - log_to_fd (log_fd, "error: no file descriptor events found for fd=%i\n", fd); - } - } - else - { - log_to_fd (log_fd, "error: fd event mutex is locked...\n"); - } - } +extern "C" void get_fd_history(int log_fd, int fd) { + // "create" below needs to be outside of the mutex locker scope + if (log_fd >= 0) { + bool got_lock = false; + Locker locker(&g_mutex, got_lock); + if (got_lock) { + FDEventMap::iterator pos = g_fd_event_map.find(fd); + log_to_fd(log_fd, "Dumping file descriptor history for fd=%i:\n", fd); + if (pos != g_fd_event_map.end()) { + FDEventArray &event_array = g_fd_event_map[fd]; + const size_t num_events = event_array.size(); + for (size_t i = 0; i < num_events; ++i) + event_array[i]->Dump(log_fd); + } else { + log_to_fd(log_fd, "error: no file descriptor events found for fd=%i\n", + fd); + } + } else { + log_to_fd(log_fd, "error: fd event mutex is locked...\n"); + } + } } //---------------------------------------------------------------------- @@ -1148,5 +983,3 @@ DYLD_INTERPOSE(close$__interposed__, close); DYLD_INTERPOSE(close$NOCANCEL$__interposed__, close$NOCANCEL); } // namespace fd_interposing - - |