133289908SGreg Clayton //===-- FDInterposing.cpp ---------------------------------------*- C++ -*-===//
233289908SGreg Clayton //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
633289908SGreg Clayton //
733289908SGreg Clayton //===----------------------------------------------------------------------===//
833289908SGreg Clayton //
933289908SGreg Clayton // This file helps with catching double close calls on unix integer file
1033289908SGreg Clayton // descriptors by interposing functions for all file descriptor create and
1133289908SGreg Clayton // close operations. A stack backtrace for every create and close function is
1233289908SGreg Clayton // maintained, and every create and close operation is logged. When a double
1333289908SGreg Clayton // file descriptor close is encountered, it will be logged.
1433289908SGreg Clayton //
1533289908SGreg Clayton // To enable the interposing in a darwin program, set the DYLD_INSERT_LIBRARIES
1633289908SGreg Clayton // environment variable as follows:
1733289908SGreg Clayton // For sh:
1833289908SGreg Clayton // DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib /path/to/executable
1933289908SGreg Clayton // For tcsh:
20b9c1b51eSKate Stone // (setenv DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib ;
21b9c1b51eSKate Stone // /path/to/executable)
2233289908SGreg Clayton //
2333289908SGreg Clayton // Other environment variables that can alter the default actions of this
2433289908SGreg Clayton // interposing shared library include:
2533289908SGreg Clayton //
2633289908SGreg Clayton // "FileDescriptorStackLoggingNoCompact"
2733289908SGreg Clayton //
2833289908SGreg Clayton // With this environment variable set, all file descriptor create and
2933289908SGreg Clayton // delete operations will be permanantly maintained in the event map.
3033289908SGreg Clayton // The default action is to compact the create/delete events by removing
3133289908SGreg Clayton // any previous file descriptor create events that are matched with a
3233289908SGreg Clayton // corresponding file descriptor delete event when the next valid file
3333289908SGreg Clayton // descriptor create event is detected.
3433289908SGreg Clayton //
3533289908SGreg Clayton // "FileDescriptorMinimalLogging"
3633289908SGreg Clayton //
3733289908SGreg Clayton // By default every file descriptor create and delete operation is logged
3833289908SGreg Clayton // (to STDOUT by default, see the "FileDescriptorLogFile"). This can be
3933289908SGreg Clayton // suppressed to only show errors and warnings by setting this environment
4033289908SGreg Clayton // variable (the value in not important).
4133289908SGreg Clayton //
4233289908SGreg Clayton // "FileDescriptorLogFile=<path>"
4333289908SGreg Clayton //
4433289908SGreg Clayton // By default logging goes to STDOUT_FILENO, but this can be changed by
4533289908SGreg Clayton // setting FileDescriptorLogFile. The value is a path to a file that
4633289908SGreg Clayton // will be opened and used for logging.
4733289908SGreg Clayton //===----------------------------------------------------------------------===//
4833289908SGreg Clayton
4933289908SGreg Clayton #include <assert.h>
5033289908SGreg Clayton #include <dirent.h>
5133289908SGreg Clayton #include <errno.h>
5233289908SGreg Clayton #include <execinfo.h>
53b9c1b51eSKate Stone #include <fcntl.h>
5433289908SGreg Clayton #include <libgen.h>
5533289908SGreg Clayton #include <mach-o/dyld-interposing.h>
56b9c1b51eSKate Stone #include <mach-o/dyld.h>
57b9c1b51eSKate Stone #include <map>
5833289908SGreg Clayton #include <stdio.h>
59b9c1b51eSKate Stone #include <stdlib.h>
6033289908SGreg Clayton #include <string.h>
61b9c1b51eSKate Stone #include <string>
6233289908SGreg Clayton #include <sys/event.h>
6333289908SGreg Clayton #include <sys/mman.h>
6433289908SGreg Clayton #include <sys/socket.h>
6533289908SGreg Clayton #include <sys/time.h>
66b9c1b51eSKate Stone #include <sys/types.h>
67672d2c12SJonas Devlieghere #include <tr1/memory>
6833289908SGreg Clayton #include <unistd.h>
6933289908SGreg Clayton #include <vector>
7033289908SGreg Clayton
71d5e4edbfSGreg Clayton extern "C" {
72d5e4edbfSGreg Clayton int accept$NOCANCEL(int, struct sockaddr *__restrict, socklen_t *__restrict);
73d5e4edbfSGreg Clayton int close$NOCANCEL(int);
74d5e4edbfSGreg Clayton int open$NOCANCEL(const char *, int, ...);
75b9c1b51eSKate Stone int __open_extended(const char *, int, uid_t, gid_t, int,
76b9c1b51eSKate Stone struct kauth_filesec *);
77d5e4edbfSGreg Clayton }
78d5e4edbfSGreg Clayton
7933289908SGreg Clayton namespace fd_interposing {
8033289908SGreg Clayton
8133289908SGreg Clayton // String class so we can get formatted strings without having to worry
8233289908SGreg Clayton // about the memory storage since it will allocate the memory it needs.
83b9c1b51eSKate Stone class String {
8433289908SGreg Clayton public:
String()85b9c1b51eSKate Stone String() : m_str(NULL) {}
8633289908SGreg Clayton
String(const char * format,...)87b9c1b51eSKate Stone String(const char *format, ...) : m_str(NULL) {
8833289908SGreg Clayton va_list args;
8933289908SGreg Clayton va_start(args, format);
9033289908SGreg Clayton vprintf(format, args);
9133289908SGreg Clayton va_end(args);
9233289908SGreg Clayton }
9333289908SGreg Clayton
~String()94b9c1b51eSKate Stone ~String() { reset(); }
9533289908SGreg Clayton
reset(char * s=NULL)96b9c1b51eSKate Stone void reset(char *s = NULL) {
9733289908SGreg Clayton if (m_str)
9833289908SGreg Clayton ::free(m_str);
9933289908SGreg Clayton m_str = s;
10033289908SGreg Clayton }
10133289908SGreg Clayton
c_str() const102b9c1b51eSKate Stone const char *c_str() const { return m_str; }
10333289908SGreg Clayton
printf(const char * format,...)104b9c1b51eSKate Stone void printf(const char *format, ...) {
10533289908SGreg Clayton va_list args;
10633289908SGreg Clayton va_start(args, format);
10733289908SGreg Clayton vprintf(format, args);
10833289908SGreg Clayton va_end(args);
10933289908SGreg Clayton }
vprintf(const char * format,va_list args)110b9c1b51eSKate Stone void vprintf(const char *format, va_list args) {
11133289908SGreg Clayton reset();
11233289908SGreg Clayton ::vasprintf(&m_str, format, args);
11333289908SGreg Clayton }
11433289908SGreg Clayton
log(int log_fd)115b9c1b51eSKate Stone void log(int log_fd) {
116b9c1b51eSKate Stone if (m_str && log_fd >= 0) {
11733289908SGreg Clayton const int len = strlen(m_str);
118b9c1b51eSKate Stone if (len > 0) {
11933289908SGreg Clayton write(log_fd, m_str, len);
12033289908SGreg Clayton const char last_char = m_str[len - 1];
12133289908SGreg Clayton if (!(last_char == '\n' || last_char == '\r'))
12233289908SGreg Clayton write(log_fd, "\n", 1);
12333289908SGreg Clayton }
12433289908SGreg Clayton }
12533289908SGreg Clayton }
126b9c1b51eSKate Stone
12733289908SGreg Clayton protected:
12833289908SGreg Clayton char *m_str;
12933289908SGreg Clayton
13033289908SGreg Clayton private:
131*eaebcbc6SKonrad Kleine String(const String &) = delete;
132*eaebcbc6SKonrad Kleine const String &operator=(const String &) = delete;
13333289908SGreg Clayton };
13433289908SGreg Clayton
13533289908SGreg Clayton // Type definitions
13633289908SGreg Clayton typedef std::vector<void *> Frames;
13733289908SGreg Clayton class FDEvent;
13833289908SGreg Clayton typedef std::vector<void *> Frames;
1394930dd68SBenjamin Kramer typedef std::tr1::shared_ptr<FDEvent> FDEventSP;
1404930dd68SBenjamin Kramer typedef std::tr1::shared_ptr<String> StringSP;
14133289908SGreg Clayton
14233289908SGreg Clayton // FDEvent
14333289908SGreg Clayton //
144e9264b74SKazuaki Ishizaki // A class that describes a file descriptor event.
14533289908SGreg Clayton //
14633289908SGreg Clayton // File descriptor events fall into one of two categories: create events
14733289908SGreg Clayton // and delete events.
148b9c1b51eSKate Stone class FDEvent {
14933289908SGreg Clayton public:
FDEvent(int fd,int err,const StringSP & string_sp,bool is_create,const Frames & frames)150b9c1b51eSKate Stone FDEvent(int fd, int err, const StringSP &string_sp, bool is_create,
151b9c1b51eSKate Stone const Frames &frames)
152b9c1b51eSKate Stone : m_string_sp(string_sp), m_frames(frames.begin(), frames.end()),
153b9c1b51eSKate Stone m_fd(fd), m_err(err), m_is_create(is_create) {}
15433289908SGreg Clayton
~FDEvent()15533289908SGreg Clayton ~FDEvent() {}
15633289908SGreg Clayton
IsCreateEvent() const157b9c1b51eSKate Stone bool IsCreateEvent() const { return m_is_create; }
15833289908SGreg Clayton
IsDeleteEvent() const159b9c1b51eSKate Stone bool IsDeleteEvent() const { return !m_is_create; }
16033289908SGreg Clayton
GetFrames()161b9c1b51eSKate Stone Frames &GetFrames() { return m_frames; }
16233289908SGreg Clayton
GetFrames() const163b9c1b51eSKate Stone const Frames &GetFrames() const { return m_frames; }
16433289908SGreg Clayton
GetFD() const165b9c1b51eSKate Stone int GetFD() const { return m_fd; }
16633289908SGreg Clayton
GetError() const167b9c1b51eSKate Stone int GetError() const { return m_err; }
16833289908SGreg Clayton
169b9c1b51eSKate Stone void Dump(int log_fd) const;
17033289908SGreg Clayton
SetCreateEvent(FDEventSP & create_event_sp)171b9c1b51eSKate Stone void SetCreateEvent(FDEventSP &create_event_sp) {
17233289908SGreg Clayton m_create_event_sp = create_event_sp;
17333289908SGreg Clayton }
17433289908SGreg Clayton
17533289908SGreg Clayton private:
17633289908SGreg Clayton // A shared pointer to a String that describes this event in
17733289908SGreg Clayton // detail (all args and return and error values)
17833289908SGreg Clayton StringSP m_string_sp;
17933289908SGreg Clayton // The frames for the stack backtrace for this event
18033289908SGreg Clayton Frames m_frames;
18133289908SGreg Clayton // If this is a file descriptor delete event, this might contain
182e9264b74SKazuaki Ishizaki // the corresponding file descriptor create event
18333289908SGreg Clayton FDEventSP m_create_event_sp;
18433289908SGreg Clayton // The file descriptor for this event
18533289908SGreg Clayton int m_fd;
18633289908SGreg Clayton // The error code (if any) for this event
18733289908SGreg Clayton int m_err;
18833289908SGreg Clayton // True if this event is a file descriptor create event, false
18933289908SGreg Clayton // if it is a file descriptor delete event
19033289908SGreg Clayton bool m_is_create;
19133289908SGreg Clayton };
19233289908SGreg Clayton
19333289908SGreg Clayton // Templatized class that will save errno only if the "value" it is
19433289908SGreg Clayton // constructed with is equal to INVALID. When the class goes out of
19533289908SGreg Clayton // scope, it will restore errno if it was saved.
196b9c1b51eSKate Stone template <int INVALID> class Errno {
19733289908SGreg Clayton public:
19833289908SGreg Clayton // Save errno only if we are supposed to
Errno(int value)199b9c1b51eSKate Stone Errno(int value)
200b9c1b51eSKate Stone : m_saved_errno((value == INVALID) ? errno : 0),
201b9c1b51eSKate Stone m_restore(value == INVALID) {}
20233289908SGreg Clayton
20333289908SGreg Clayton // Restore errno only if we are supposed to
~Errno()204b9c1b51eSKate Stone ~Errno() {
20533289908SGreg Clayton if (m_restore)
20633289908SGreg Clayton errno = m_saved_errno;
20733289908SGreg Clayton }
20833289908SGreg Clayton
20933289908SGreg Clayton // Accessor for the saved value of errno
get_errno() const210b9c1b51eSKate Stone int get_errno() const { return m_saved_errno; }
21133289908SGreg Clayton
21233289908SGreg Clayton protected:
21333289908SGreg Clayton const int m_saved_errno;
21433289908SGreg Clayton const bool m_restore;
21533289908SGreg Clayton };
21633289908SGreg Clayton
21733289908SGreg Clayton typedef Errno<-1> InvalidFDErrno;
21833289908SGreg Clayton typedef Errno<-1> NegativeErrorErrno;
21933289908SGreg Clayton typedef std::vector<FDEventSP> FDEventArray;
22033289908SGreg Clayton typedef std::map<int, FDEventArray> FDEventMap;
22133289908SGreg Clayton
22233289908SGreg Clayton // Globals
22333289908SGreg Clayton // Global event map that contains all file descriptor events. As file
22433289908SGreg Clayton // descriptor create and close events come in, they will get filled
22533289908SGreg Clayton // into this map (protected by g_mutex). When a file descriptor close
22633289908SGreg Clayton // event is detected, the open event will be removed and placed into
22733289908SGreg Clayton // the close event so if something tries to double close a file
22833289908SGreg Clayton // descriptor we can show the previous close event and the file
229e9264b74SKazuaki Ishizaki // descriptor event that created it. When a new file descriptor create
23033289908SGreg Clayton // event comes in, we will remove the previous one for that file
231e9264b74SKazuaki Ishizaki // descriptor unless the environment variable
232b9c1b51eSKate Stone // "FileDescriptorStackLoggingNoCompact"
233e9264b74SKazuaki Ishizaki // is set. The file descriptor history can be accessed using the
23433289908SGreg Clayton // get_fd_history() function.
23533289908SGreg Clayton static FDEventMap g_fd_event_map;
23633289908SGreg Clayton // A mutex to protect access to our data structures in g_fd_event_map
23733289908SGreg Clayton // and also our logging messages
23833289908SGreg Clayton static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
23933289908SGreg Clayton // Log all file descriptor create and close events by default. Only log
240e9264b74SKazuaki Ishizaki // warnings and errors if the "FileDescriptorMinimalLogging" environment
24133289908SGreg Clayton // variable is set.
24233289908SGreg Clayton static int g_log_all_calls = 1;
24333289908SGreg Clayton // We compact the file descriptor events by default. Set the environment
24433289908SGreg Clayton // varible "FileDescriptorStackLoggingNoCompact" to keep a full history.
24533289908SGreg Clayton static int g_compact = 1;
246d5e4edbfSGreg Clayton // The current process ID
247d5e4edbfSGreg Clayton static int g_pid = -1;
248d5e4edbfSGreg Clayton static bool g_enabled = true;
24933289908SGreg Clayton // Mutex class that will lock a mutex when it is constructed, and unlock
25033289908SGreg Clayton // it when is goes out of scope
251b9c1b51eSKate Stone class Locker {
25233289908SGreg Clayton public:
Locker(pthread_mutex_t * mutex_ptr)253b9c1b51eSKate Stone Locker(pthread_mutex_t *mutex_ptr) : m_mutex_ptr(mutex_ptr) {
25433289908SGreg Clayton ::pthread_mutex_lock(m_mutex_ptr);
25533289908SGreg Clayton }
25633289908SGreg Clayton
25733289908SGreg Clayton // This allows clients to test try and acquire the mutex...
Locker(pthread_mutex_t * mutex_ptr,bool & lock_acquired)258b9c1b51eSKate Stone Locker(pthread_mutex_t *mutex_ptr, bool &lock_acquired) : m_mutex_ptr(NULL) {
25933289908SGreg Clayton lock_acquired = ::pthread_mutex_trylock(mutex_ptr) == 0;
26033289908SGreg Clayton if (lock_acquired)
26133289908SGreg Clayton m_mutex_ptr = mutex_ptr;
26233289908SGreg Clayton }
26333289908SGreg Clayton
~Locker()264b9c1b51eSKate Stone ~Locker() {
26533289908SGreg Clayton if (m_mutex_ptr)
26633289908SGreg Clayton ::pthread_mutex_unlock(m_mutex_ptr);
26733289908SGreg Clayton }
268b9c1b51eSKate Stone
26933289908SGreg Clayton protected:
27033289908SGreg Clayton pthread_mutex_t *m_mutex_ptr;
27133289908SGreg Clayton };
27233289908SGreg Clayton
273b9c1b51eSKate Stone static void log(const char *format, ...) __attribute__((format(printf, 1, 2)));
27433289908SGreg Clayton
275b9c1b51eSKate Stone static void log(int log_fd, const FDEvent *event, const char *format, ...)
276b9c1b51eSKate Stone __attribute__((format(printf, 3, 4)));
27733289908SGreg Clayton
278b9c1b51eSKate Stone static void backtrace_log(const char *format, ...)
279b9c1b51eSKate Stone __attribute__((format(printf, 1, 2)));
28033289908SGreg Clayton
281b9c1b51eSKate Stone static void backtrace_error(const char *format, ...)
282b9c1b51eSKate Stone __attribute__((format(printf, 1, 2)));
283d5e4edbfSGreg Clayton
284b9c1b51eSKate Stone static void log_to_fd(int log_fd, const char *format, ...)
285b9c1b51eSKate Stone __attribute__((format(printf, 2, 3)));
28633289908SGreg Clayton
get_backtrace(Frames & frame_buffer,size_t frames_to_remove)287b9c1b51eSKate Stone static inline size_t get_backtrace(Frames &frame_buffer,
288b9c1b51eSKate Stone size_t frames_to_remove) {
28933289908SGreg Clayton void *frames[2048];
29033289908SGreg Clayton int count = ::backtrace(&frames[0], sizeof(frames) / sizeof(void *));
29133289908SGreg Clayton if (count > frames_to_remove)
29233289908SGreg Clayton frame_buffer.assign(&frames[frames_to_remove], &frames[count]);
29333289908SGreg Clayton else
29433289908SGreg Clayton frame_buffer.assign(&frames[0], &frames[count]);
29533289908SGreg Clayton while (frame_buffer.back() < (void *)1024)
29633289908SGreg Clayton frame_buffer.pop_back();
29733289908SGreg Clayton return frame_buffer.size();
29833289908SGreg Clayton }
29933289908SGreg Clayton
300d5e4edbfSGreg Clayton static int g_log_fd = STDOUT_FILENO;
301d5e4edbfSGreg Clayton static int g_initialized = 0;
302d5e4edbfSGreg Clayton
get_process_fullpath(bool force=false)303b9c1b51eSKate Stone const char *get_process_fullpath(bool force = false) {
304d5e4edbfSGreg Clayton static char g_process_fullpath[PATH_MAX] = {0};
305b9c1b51eSKate Stone if (force || g_process_fullpath[0] == '\0') {
306d5e4edbfSGreg Clayton // If DST is NULL, then return the number of bytes needed.
307d5e4edbfSGreg Clayton uint32_t len = sizeof(g_process_fullpath);
308d5e4edbfSGreg Clayton if (_NSGetExecutablePath(g_process_fullpath, &len) != 0)
309d5e4edbfSGreg Clayton strncpy(g_process_fullpath, "<error>", sizeof(g_process_fullpath));
310d5e4edbfSGreg Clayton }
311d5e4edbfSGreg Clayton return g_process_fullpath;
312d5e4edbfSGreg Clayton }
313d5e4edbfSGreg Clayton
314d5e4edbfSGreg Clayton // Returns the current process ID, or -1 if inserposing not enabled for
315d5e4edbfSGreg Clayton // this process
get_interposed_pid()316b9c1b51eSKate Stone static int get_interposed_pid() {
317d5e4edbfSGreg Clayton if (!g_enabled)
318d5e4edbfSGreg Clayton return -1;
319d5e4edbfSGreg Clayton
320d5e4edbfSGreg Clayton const pid_t pid = getpid();
321b9c1b51eSKate Stone if (g_pid != pid) {
322b9c1b51eSKate Stone if (g_pid == -1) {
323d5e4edbfSGreg Clayton g_pid = pid;
324b9c1b51eSKate Stone log("Interposing file descriptor create and delete functions for %s "
325b9c1b51eSKate Stone "(pid=%i)\n",
326b9c1b51eSKate Stone get_process_fullpath(true), pid);
327b9c1b51eSKate Stone } else {
328b9c1b51eSKate Stone log("pid=%i: disabling interposing file descriptor create and delete "
329b9c1b51eSKate Stone "functions for child process %s (pid=%i)\n",
330b9c1b51eSKate Stone g_pid, get_process_fullpath(true), pid);
331d5e4edbfSGreg Clayton g_enabled = false;
332d5e4edbfSGreg Clayton return -1;
333d5e4edbfSGreg Clayton }
334d5e4edbfSGreg Clayton // Log when our process changes
335d5e4edbfSGreg Clayton }
336d5e4edbfSGreg Clayton return g_pid;
337d5e4edbfSGreg Clayton }
338d5e4edbfSGreg Clayton
get_logging_fd()339b9c1b51eSKate Stone static int get_logging_fd() {
340d5e4edbfSGreg Clayton if (!g_enabled)
341d5e4edbfSGreg Clayton return -1;
34233289908SGreg Clayton
343b9c1b51eSKate Stone if (!g_initialized) {
344d5e4edbfSGreg Clayton g_initialized = 1;
34533289908SGreg Clayton
346d5e4edbfSGreg Clayton const pid_t pid = get_interposed_pid();
347d5e4edbfSGreg Clayton
348b9c1b51eSKate Stone if (g_enabled) {
34933289908SGreg Clayton // Keep all stack info around for all fd create and delete calls.
35033289908SGreg Clayton // Otherwise we will remove the fd create call when a corresponding
35133289908SGreg Clayton // fd delete call is received
35233289908SGreg Clayton if (getenv("FileDescriptorStackLoggingNoCompact"))
35333289908SGreg Clayton g_compact = 0;
35433289908SGreg Clayton
35533289908SGreg Clayton if (getenv("FileDescriptorMinimalLogging"))
35633289908SGreg Clayton g_log_all_calls = 0;
35733289908SGreg Clayton
358d5e4edbfSGreg Clayton const char *log_path = getenv("FileDescriptorLogFile");
359d5e4edbfSGreg Clayton if (log_path)
360d5e4edbfSGreg Clayton g_log_fd = ::creat(log_path, 0660);
361d5e4edbfSGreg Clayton else
362d5e4edbfSGreg Clayton g_log_fd = STDOUT_FILENO;
363d5e4edbfSGreg Clayton
36433289908SGreg Clayton // Only let this interposing happen on the first time this matches
36533289908SGreg Clayton // and stop this from happening so any child processes don't also
36633289908SGreg Clayton // log their file descriptors
36733289908SGreg Clayton ::unsetenv("DYLD_INSERT_LIBRARIES");
368b9c1b51eSKate Stone } else {
369d5e4edbfSGreg Clayton log("pid=%i: logging disabled\n", getpid());
37033289908SGreg Clayton }
37133289908SGreg Clayton }
37233289908SGreg Clayton return g_log_fd;
37333289908SGreg Clayton }
37433289908SGreg Clayton
log_to_fd(int log_fd,const char * format,va_list args)375b9c1b51eSKate Stone void log_to_fd(int log_fd, const char *format, va_list args) {
376b9c1b51eSKate Stone if (format && format[0] && log_fd >= 0) {
37733289908SGreg Clayton char buffer[PATH_MAX];
37833289908SGreg Clayton const int count = ::vsnprintf(buffer, sizeof(buffer), format, args);
37933289908SGreg Clayton if (count > 0)
38033289908SGreg Clayton write(log_fd, buffer, count);
38133289908SGreg Clayton }
38233289908SGreg Clayton }
38333289908SGreg Clayton
log_to_fd(int log_fd,const char * format,...)384b9c1b51eSKate Stone void log_to_fd(int log_fd, const char *format, ...) {
385b9c1b51eSKate Stone if (format && format[0]) {
38633289908SGreg Clayton va_list args;
38733289908SGreg Clayton va_start(args, format);
38833289908SGreg Clayton log_to_fd(log_fd, format, args);
38933289908SGreg Clayton va_end(args);
39033289908SGreg Clayton }
39133289908SGreg Clayton }
39233289908SGreg Clayton
log(const char * format,va_list args)393b9c1b51eSKate Stone void log(const char *format, va_list args) {
39433289908SGreg Clayton log_to_fd(get_logging_fd(), format, args);
39533289908SGreg Clayton }
39633289908SGreg Clayton
log(const char * format,...)397b9c1b51eSKate Stone void log(const char *format, ...) {
398b9c1b51eSKate Stone if (format && format[0]) {
39933289908SGreg Clayton va_list args;
40033289908SGreg Clayton va_start(args, format);
40133289908SGreg Clayton log(format, args);
40233289908SGreg Clayton va_end(args);
40333289908SGreg Clayton }
40433289908SGreg Clayton }
40533289908SGreg Clayton
log(int log_fd,const FDEvent * event,const char * format,...)406b9c1b51eSKate Stone void log(int log_fd, const FDEvent *event, const char *format, ...) {
407b9c1b51eSKate Stone if (format && format[0]) {
40833289908SGreg Clayton va_list args;
40933289908SGreg Clayton va_start(args, format);
41033289908SGreg Clayton log_to_fd(log_fd, format, args);
41133289908SGreg Clayton va_end(args);
41233289908SGreg Clayton }
41333289908SGreg Clayton if (event)
41433289908SGreg Clayton event->Dump(log_fd);
41533289908SGreg Clayton }
41633289908SGreg Clayton
Dump(int log_fd) const417b9c1b51eSKate Stone void FDEvent::Dump(int log_fd) const {
418b9c1b51eSKate Stone if (log_fd >= 0) {
41933289908SGreg Clayton log_to_fd(log_fd, "%s\n", m_string_sp->c_str());
42033289908SGreg Clayton if (!m_frames.empty())
42133289908SGreg Clayton ::backtrace_symbols_fd(m_frames.data(), m_frames.size(), log_fd);
42233289908SGreg Clayton
423b9c1b51eSKate Stone if (m_create_event_sp) {
42433289908SGreg Clayton log_to_fd(log_fd, "\nfd=%i was created with this event:\n", m_fd);
42533289908SGreg Clayton m_create_event_sp->Dump(log_fd);
42633289908SGreg Clayton log_to_fd(log_fd, "\n");
42733289908SGreg Clayton }
42833289908SGreg Clayton }
42933289908SGreg Clayton }
43033289908SGreg Clayton
backtrace_log(const char * format,...)431b9c1b51eSKate Stone void backtrace_log(const char *format, ...) {
43233289908SGreg Clayton const int log_fd = get_logging_fd();
433b9c1b51eSKate Stone if (log_fd >= 0) {
434b9c1b51eSKate Stone if (format && format[0]) {
43533289908SGreg Clayton va_list args;
43633289908SGreg Clayton va_start(args, format);
43733289908SGreg Clayton log(format, args);
43833289908SGreg Clayton va_end(args);
43933289908SGreg Clayton }
44033289908SGreg Clayton
44133289908SGreg Clayton Frames frames;
442662125aeSGreg Clayton if (get_backtrace(frames, 2))
44333289908SGreg Clayton ::backtrace_symbols_fd(frames.data(), frames.size(), log_fd);
44433289908SGreg Clayton }
44533289908SGreg Clayton }
44633289908SGreg Clayton
backtrace_error(const char * format,...)447b9c1b51eSKate Stone void backtrace_error(const char *format, ...) {
448d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
449b9c1b51eSKate Stone if (pid >= 0) {
450d5e4edbfSGreg Clayton const int log_fd = get_logging_fd();
451b9c1b51eSKate Stone if (log_fd >= 0) {
452d5e4edbfSGreg Clayton log("\nerror: %s (pid=%i): ", get_process_fullpath(), pid);
453d5e4edbfSGreg Clayton
454b9c1b51eSKate Stone if (format && format[0]) {
455d5e4edbfSGreg Clayton va_list args;
456d5e4edbfSGreg Clayton va_start(args, format);
457d5e4edbfSGreg Clayton log(format, args);
458d5e4edbfSGreg Clayton va_end(args);
459d5e4edbfSGreg Clayton }
460d5e4edbfSGreg Clayton
461d5e4edbfSGreg Clayton Frames frames;
462d5e4edbfSGreg Clayton if (get_backtrace(frames, 2))
463d5e4edbfSGreg Clayton ::backtrace_symbols_fd(frames.data(), frames.size(), log_fd);
464d5e4edbfSGreg Clayton }
465d5e4edbfSGreg Clayton }
466d5e4edbfSGreg Clayton }
46733289908SGreg Clayton
save_backtrace(int fd,int err,const StringSP & string_sp,bool is_create)468b9c1b51eSKate Stone void save_backtrace(int fd, int err, const StringSP &string_sp,
469b9c1b51eSKate Stone bool is_create) {
47033289908SGreg Clayton Frames frames;
47133289908SGreg Clayton get_backtrace(frames, 2);
47233289908SGreg Clayton
47333289908SGreg Clayton FDEventSP fd_event_sp(new FDEvent(fd, err, string_sp, is_create, frames));
47433289908SGreg Clayton
47533289908SGreg Clayton FDEventMap::iterator pos = g_fd_event_map.find(fd);
47633289908SGreg Clayton
477b9c1b51eSKate Stone if (pos != g_fd_event_map.end()) {
47833289908SGreg Clayton // We have history for this fd...
47933289908SGreg Clayton
48033289908SGreg Clayton FDEventArray &event_array = g_fd_event_map[fd];
481b9c1b51eSKate Stone if (fd_event_sp->IsCreateEvent()) {
48233289908SGreg Clayton // The current fd event is a function that creates
48333289908SGreg Clayton // a descriptor, check in case last event was
48433289908SGreg Clayton // a create event.
485b9c1b51eSKate Stone if (event_array.back()->IsCreateEvent()) {
48633289908SGreg Clayton const int log_fd = get_logging_fd();
48733289908SGreg Clayton // Two fd create functions in a row, we missed
48833289908SGreg Clayton // a function that closes a fd...
489b9c1b51eSKate Stone log(log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor "
490b9c1b51eSKate Stone "create event fd=%i (we missed a file "
491b9c1b51eSKate Stone "descriptor close event):\n",
492b9c1b51eSKate Stone fd);
493b9c1b51eSKate Stone } else if (g_compact) {
49433289908SGreg Clayton // We are compacting so we remove previous create event
495e9264b74SKazuaki Ishizaki // when we get the corresponding delete event
49633289908SGreg Clayton event_array.pop_back();
49733289908SGreg Clayton }
498b9c1b51eSKate Stone } else {
49933289908SGreg Clayton // The current fd event is a function that deletes
50033289908SGreg Clayton // a descriptor, check in case last event for this
50133289908SGreg Clayton // fd was a delete event (double close!)
502b9c1b51eSKate Stone if (event_array.back()->IsDeleteEvent()) {
50333289908SGreg Clayton const int log_fd = get_logging_fd();
50433289908SGreg Clayton // Two fd delete functions in a row, we must
50533289908SGreg Clayton // have missed some function that opened a descriptor
506b9c1b51eSKate Stone log(log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor "
507b9c1b51eSKate Stone "close event for fd=%d (we missed the "
508b9c1b51eSKate Stone "file descriptor create event):\n",
509b9c1b51eSKate Stone fd);
510b9c1b51eSKate Stone } else if (g_compact) {
51133289908SGreg Clayton // Since this is a close event, we want to remember the open event
51233289908SGreg Clayton // that this close if for...
51333289908SGreg Clayton fd_event_sp->SetCreateEvent(event_array.back());
51433289908SGreg Clayton // We are compacting so we remove previous create event
515e9264b74SKazuaki Ishizaki // when we get the corresponding delete event
51633289908SGreg Clayton event_array.pop_back();
51733289908SGreg Clayton }
51833289908SGreg Clayton }
51933289908SGreg Clayton
52033289908SGreg Clayton event_array.push_back(fd_event_sp);
521b9c1b51eSKate Stone } else {
52233289908SGreg Clayton g_fd_event_map[fd].push_back(fd_event_sp);
52333289908SGreg Clayton }
52433289908SGreg Clayton }
52533289908SGreg Clayton
52633289908SGreg Clayton // socket() interpose function
socket$__interposed__(int domain,int type,int protocol)527b9c1b51eSKate Stone extern "C" int socket$__interposed__(int domain, int type, int protocol) {
528d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
529b9c1b51eSKate Stone if (pid >= 0) {
53033289908SGreg Clayton Locker locker(&g_mutex);
53133289908SGreg Clayton const int fd = ::socket(domain, type, protocol);
53233289908SGreg Clayton InvalidFDErrno fd_errno(fd);
53333289908SGreg Clayton StringSP description_sp(new String);
53433289908SGreg Clayton if (fd == -1)
535b9c1b51eSKate Stone description_sp->printf("pid=%i: socket (domain = %i, type = %i, protocol "
536b9c1b51eSKate Stone "= %i) => fd=%i errno = %i",
537b9c1b51eSKate Stone pid, domain, type, protocol, fd,
538b9c1b51eSKate Stone fd_errno.get_errno());
53933289908SGreg Clayton else
540b9c1b51eSKate Stone description_sp->printf(
541b9c1b51eSKate Stone "pid=%i: socket (domain = %i, type = %i, protocol = %i) => fd=%i",
542b9c1b51eSKate Stone pid, domain, type, protocol, fd);
54333289908SGreg Clayton if (g_log_all_calls)
54433289908SGreg Clayton description_sp->log(get_logging_fd());
54533289908SGreg Clayton if (fd >= 0)
54633289908SGreg Clayton save_backtrace(fd, fd_errno.get_errno(), description_sp, true);
54733289908SGreg Clayton return fd;
548b9c1b51eSKate Stone } else {
549d5e4edbfSGreg Clayton return ::socket(domain, type, protocol);
550d5e4edbfSGreg Clayton }
551d5e4edbfSGreg Clayton }
55233289908SGreg Clayton
55333289908SGreg Clayton // socketpair() interpose function
socketpair$__interposed__(int domain,int type,int protocol,int fds[2])554b9c1b51eSKate Stone extern "C" int socketpair$__interposed__(int domain, int type, int protocol,
555b9c1b51eSKate Stone int fds[2]) {
556d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
557b9c1b51eSKate Stone if (pid >= 0) {
55833289908SGreg Clayton Locker locker(&g_mutex);
55933289908SGreg Clayton fds[0] = -1;
56033289908SGreg Clayton fds[1] = -1;
56133289908SGreg Clayton const int err = socketpair(domain, type, protocol, fds);
56233289908SGreg Clayton NegativeErrorErrno err_errno(err);
563b9c1b51eSKate Stone StringSP description_sp(
564b9c1b51eSKate Stone new String("pid=%i: socketpair (domain=%i, type=%i, protocol=%i, "
565b9c1b51eSKate Stone "{fd=%i, fd=%i}) -> err=%i",
566b9c1b51eSKate Stone pid, domain, type, protocol, fds[0], fds[1], err));
56733289908SGreg Clayton if (g_log_all_calls)
56833289908SGreg Clayton description_sp->log(get_logging_fd());
56933289908SGreg Clayton if (fds[0] >= 0)
57033289908SGreg Clayton save_backtrace(fds[0], err_errno.get_errno(), description_sp, true);
57133289908SGreg Clayton if (fds[1] >= 0)
57233289908SGreg Clayton save_backtrace(fds[1], err_errno.get_errno(), description_sp, true);
57333289908SGreg Clayton return err;
574b9c1b51eSKate Stone } else {
575d5e4edbfSGreg Clayton return socketpair(domain, type, protocol, fds);
576d5e4edbfSGreg Clayton }
577d5e4edbfSGreg Clayton }
57833289908SGreg Clayton
57933289908SGreg Clayton // open() interpose function
open$__interposed__(const char * path,int oflag,int mode)580b9c1b51eSKate Stone extern "C" int open$__interposed__(const char *path, int oflag, int mode) {
581d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
582b9c1b51eSKate Stone if (pid >= 0) {
58333289908SGreg Clayton Locker locker(&g_mutex);
58433289908SGreg Clayton int fd = -2;
58533289908SGreg Clayton StringSP description_sp(new String);
586b9c1b51eSKate Stone if (oflag & O_CREAT) {
587d5e4edbfSGreg Clayton fd = ::open(path, oflag, mode);
588b9c1b51eSKate Stone description_sp->printf(
589b9c1b51eSKate Stone "pid=%i: open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid,
590b9c1b51eSKate Stone path, oflag, mode, fd);
591b9c1b51eSKate Stone } else {
592d5e4edbfSGreg Clayton fd = ::open(path, oflag);
593b9c1b51eSKate Stone description_sp->printf("pid=%i: open (path = '%s', oflag = %i) -> fd=%i",
594b9c1b51eSKate Stone pid, path, oflag, fd);
59533289908SGreg Clayton }
59633289908SGreg Clayton
59733289908SGreg Clayton InvalidFDErrno fd_errno(fd);
59833289908SGreg Clayton if (g_log_all_calls)
59933289908SGreg Clayton description_sp->log(get_logging_fd());
60033289908SGreg Clayton if (fd >= 0)
60133289908SGreg Clayton save_backtrace(fd, fd_errno.get_errno(), description_sp, true);
60233289908SGreg Clayton return fd;
603b9c1b51eSKate Stone } else {
604d5e4edbfSGreg Clayton return ::open(path, oflag, mode);
605d5e4edbfSGreg Clayton }
606d5e4edbfSGreg Clayton }
60733289908SGreg Clayton
60833289908SGreg Clayton // open$NOCANCEL() interpose function
open$NOCANCEL$__interposed__(const char * path,int oflag,int mode)609b9c1b51eSKate Stone extern "C" int open$NOCANCEL$__interposed__(const char *path, int oflag,
610b9c1b51eSKate Stone int mode) {
611d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
612b9c1b51eSKate Stone if (pid >= 0) {
61333289908SGreg Clayton Locker locker(&g_mutex);
614d5e4edbfSGreg Clayton const int fd = ::open$NOCANCEL(path, oflag, mode);
61533289908SGreg Clayton InvalidFDErrno fd_errno(fd);
616b9c1b51eSKate Stone StringSP description_sp(new String(
617b9c1b51eSKate Stone "pid=%i: open$NOCANCEL (path = '%s', oflag = %i, mode = %i) -> fd=%i",
618b9c1b51eSKate Stone pid, path, oflag, mode, fd));
61933289908SGreg Clayton if (g_log_all_calls)
62033289908SGreg Clayton description_sp->log(get_logging_fd());
62133289908SGreg Clayton if (fd >= 0)
62233289908SGreg Clayton save_backtrace(fd, fd_errno.get_errno(), description_sp, true);
62333289908SGreg Clayton return fd;
624b9c1b51eSKate Stone } else {
625d5e4edbfSGreg Clayton return ::open$NOCANCEL(path, oflag, mode);
626d5e4edbfSGreg Clayton }
627d5e4edbfSGreg Clayton }
62833289908SGreg Clayton
62933289908SGreg Clayton // __open_extended() interpose function
__open_extended$__interposed__(const char * path,int oflag,uid_t uid,gid_t gid,int mode,struct kauth_filesec * fsacl)630b9c1b51eSKate Stone extern "C" int __open_extended$__interposed__(const char *path, int oflag,
631b9c1b51eSKate Stone uid_t uid, gid_t gid, int mode,
632b9c1b51eSKate Stone struct kauth_filesec *fsacl) {
633d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
634b9c1b51eSKate Stone if (pid >= 0) {
63533289908SGreg Clayton Locker locker(&g_mutex);
636d5e4edbfSGreg Clayton const int fd = ::__open_extended(path, oflag, uid, gid, mode, fsacl);
63733289908SGreg Clayton InvalidFDErrno fd_errno(fd);
638b9c1b51eSKate Stone StringSP description_sp(
639b9c1b51eSKate Stone new String("pid=%i: __open_extended (path='%s', oflag=%i, uid=%i, "
640b9c1b51eSKate Stone "gid=%i, mode=%i, fsacl=%p) -> fd=%i",
641b9c1b51eSKate Stone pid, path, oflag, uid, gid, mode, fsacl, fd));
64233289908SGreg Clayton if (g_log_all_calls)
64333289908SGreg Clayton description_sp->log(get_logging_fd());
64433289908SGreg Clayton if (fd >= 0)
64533289908SGreg Clayton save_backtrace(fd, fd_errno.get_errno(), description_sp, true);
64633289908SGreg Clayton return fd;
647b9c1b51eSKate Stone } else {
648d5e4edbfSGreg Clayton return ::__open_extended(path, oflag, uid, gid, mode, fsacl);
649d5e4edbfSGreg Clayton }
650d5e4edbfSGreg Clayton }
65133289908SGreg Clayton
65233289908SGreg Clayton // kqueue() interpose function
kqueue$__interposed__(void)653b9c1b51eSKate Stone extern "C" int kqueue$__interposed__(void) {
654d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
655b9c1b51eSKate Stone if (pid >= 0) {
65633289908SGreg Clayton Locker locker(&g_mutex);
65733289908SGreg Clayton const int fd = ::kqueue();
65833289908SGreg Clayton InvalidFDErrno fd_errno(fd);
659d5e4edbfSGreg Clayton StringSP description_sp(new String("pid=%i: kqueue () -> fd=%i", pid, fd));
66033289908SGreg Clayton if (g_log_all_calls)
66133289908SGreg Clayton description_sp->log(get_logging_fd());
66233289908SGreg Clayton if (fd >= 0)
66333289908SGreg Clayton save_backtrace(fd, fd_errno.get_errno(), description_sp, true);
66433289908SGreg Clayton return fd;
665b9c1b51eSKate Stone } else {
666d5e4edbfSGreg Clayton return ::kqueue();
667d5e4edbfSGreg Clayton }
66833289908SGreg Clayton }
66933289908SGreg Clayton
67033289908SGreg Clayton // shm_open() interpose function
shm_open$__interposed__(const char * path,int oflag,int mode)671b9c1b51eSKate Stone extern "C" int shm_open$__interposed__(const char *path, int oflag, int mode) {
672d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
673b9c1b51eSKate Stone if (pid >= 0) {
67433289908SGreg Clayton Locker locker(&g_mutex);
675d5e4edbfSGreg Clayton const int fd = ::shm_open(path, oflag, mode);
67633289908SGreg Clayton InvalidFDErrno fd_errno(fd);
677b9c1b51eSKate Stone StringSP description_sp(new String(
678b9c1b51eSKate Stone "pid=%i: shm_open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid,
679b9c1b51eSKate Stone path, oflag, mode, fd));
68033289908SGreg Clayton if (g_log_all_calls)
68133289908SGreg Clayton description_sp->log(get_logging_fd());
68233289908SGreg Clayton if (fd >= 0)
68333289908SGreg Clayton save_backtrace(fd, fd_errno.get_errno(), description_sp, true);
68433289908SGreg Clayton return fd;
685b9c1b51eSKate Stone } else {
686d5e4edbfSGreg Clayton return ::shm_open(path, oflag, mode);
687d5e4edbfSGreg Clayton }
688d5e4edbfSGreg Clayton }
68933289908SGreg Clayton
69033289908SGreg Clayton // accept() interpose function
accept$__interposed__(int socket,struct sockaddr * address,socklen_t * address_len)691b9c1b51eSKate Stone extern "C" int accept$__interposed__(int socket, struct sockaddr *address,
692b9c1b51eSKate Stone socklen_t *address_len) {
693d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
694b9c1b51eSKate Stone if (pid >= 0) {
69533289908SGreg Clayton Locker locker(&g_mutex);
696d5e4edbfSGreg Clayton const int fd = ::accept(socket, address, address_len);
69733289908SGreg Clayton InvalidFDErrno fd_errno(fd);
698b9c1b51eSKate Stone StringSP description_sp(new String(
699b9c1b51eSKate Stone "pid=%i: accept (socket=%i, ...) -> fd=%i", pid, socket, fd));
70033289908SGreg Clayton if (g_log_all_calls)
70133289908SGreg Clayton description_sp->log(get_logging_fd());
70233289908SGreg Clayton if (fd >= 0)
70333289908SGreg Clayton save_backtrace(fd, fd_errno.get_errno(), description_sp, true);
70433289908SGreg Clayton return fd;
705b9c1b51eSKate Stone } else {
706d5e4edbfSGreg Clayton return ::accept(socket, address, address_len);
707d5e4edbfSGreg Clayton }
708d5e4edbfSGreg Clayton }
70933289908SGreg Clayton
71033289908SGreg Clayton // accept$NOCANCEL() interpose function
accept$NOCANCEL$__interposed__(int socket,struct sockaddr * address,socklen_t * address_len)711b9c1b51eSKate Stone extern "C" int accept$NOCANCEL$__interposed__(int socket,
712b9c1b51eSKate Stone struct sockaddr *address,
713b9c1b51eSKate Stone socklen_t *address_len) {
714d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
715b9c1b51eSKate Stone if (pid >= 0) {
71633289908SGreg Clayton Locker locker(&g_mutex);
717d5e4edbfSGreg Clayton const int fd = ::accept$NOCANCEL(socket, address, address_len);
71833289908SGreg Clayton InvalidFDErrno fd_errno(fd);
719b9c1b51eSKate Stone StringSP description_sp(new String(
720b9c1b51eSKate Stone "pid=%i: accept$NOCANCEL (socket=%i, ...) -> fd=%i", pid, socket, fd));
72133289908SGreg Clayton if (g_log_all_calls)
72233289908SGreg Clayton description_sp->log(get_logging_fd());
72333289908SGreg Clayton if (fd >= 0)
72433289908SGreg Clayton save_backtrace(fd, fd_errno.get_errno(), description_sp, true);
72533289908SGreg Clayton return fd;
726b9c1b51eSKate Stone } else {
727d5e4edbfSGreg Clayton return ::accept$NOCANCEL(socket, address, address_len);
728d5e4edbfSGreg Clayton }
729d5e4edbfSGreg Clayton }
73033289908SGreg Clayton
73133289908SGreg Clayton // dup() interpose function
dup$__interposed__(int fd2)732b9c1b51eSKate Stone extern "C" int dup$__interposed__(int fd2) {
733d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
734b9c1b51eSKate Stone if (pid >= 0) {
73533289908SGreg Clayton Locker locker(&g_mutex);
736d5e4edbfSGreg Clayton const int fd = ::dup(fd2);
73733289908SGreg Clayton InvalidFDErrno fd_errno(fd);
738b9c1b51eSKate Stone StringSP description_sp(
739b9c1b51eSKate Stone new String("pid=%i: dup (fd2=%i) -> fd=%i", pid, fd2, fd));
74033289908SGreg Clayton if (g_log_all_calls)
74133289908SGreg Clayton description_sp->log(get_logging_fd());
74233289908SGreg Clayton if (fd >= 0)
74333289908SGreg Clayton save_backtrace(fd, fd_errno.get_errno(), description_sp, true);
74433289908SGreg Clayton return fd;
745b9c1b51eSKate Stone } else {
746d5e4edbfSGreg Clayton return ::dup(fd2);
747d5e4edbfSGreg Clayton }
748d5e4edbfSGreg Clayton }
74933289908SGreg Clayton
75033289908SGreg Clayton // dup2() interpose function
dup2$__interposed__(int fd1,int fd2)751b9c1b51eSKate Stone extern "C" int dup2$__interposed__(int fd1, int fd2) {
752d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
753b9c1b51eSKate Stone if (pid >= 0) {
75433289908SGreg Clayton Locker locker(&g_mutex);
75533289908SGreg Clayton // If "fd2" is already opened, it will be closed during the
75633289908SGreg Clayton // dup2 call below, so we need to see if we have fd2 in our
75733289908SGreg Clayton // open map and treat it as a close(fd2)
75833289908SGreg Clayton FDEventMap::iterator pos = g_fd_event_map.find(fd2);
759b9c1b51eSKate Stone StringSP dup2_close_description_sp(
760b9c1b51eSKate Stone new String("pid=%i: dup2 (fd1=%i, fd2=%i) -> will close (fd=%i)", pid,
761b9c1b51eSKate Stone fd1, fd2, fd2));
76233289908SGreg Clayton if (pos != g_fd_event_map.end() && pos->second.back()->IsCreateEvent())
763662125aeSGreg Clayton save_backtrace(fd2, 0, dup2_close_description_sp, false);
764662125aeSGreg Clayton
765d5e4edbfSGreg Clayton const int fd = ::dup2(fd1, fd2);
766662125aeSGreg Clayton InvalidFDErrno fd_errno(fd);
767b9c1b51eSKate Stone StringSP description_sp(new String("pid=%i: dup2 (fd1=%i, fd2=%i) -> fd=%i",
768b9c1b51eSKate Stone pid, fd1, fd2, fd));
769662125aeSGreg Clayton if (g_log_all_calls)
770662125aeSGreg Clayton description_sp->log(get_logging_fd());
77133289908SGreg Clayton
77233289908SGreg Clayton if (fd >= 0)
77333289908SGreg Clayton save_backtrace(fd, fd_errno.get_errno(), description_sp, true);
77433289908SGreg Clayton return fd;
775b9c1b51eSKate Stone } else {
776d5e4edbfSGreg Clayton return ::dup2(fd1, fd2);
777d5e4edbfSGreg Clayton }
778d5e4edbfSGreg Clayton }
77933289908SGreg Clayton
78033289908SGreg Clayton // close() interpose function
close$__interposed__(int fd)781b9c1b51eSKate Stone extern "C" int close$__interposed__(int fd) {
782d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
783b9c1b51eSKate Stone if (pid >= 0) {
78433289908SGreg Clayton Locker locker(&g_mutex);
78533289908SGreg Clayton const int err = close(fd);
78633289908SGreg Clayton NegativeErrorErrno err_errno(err);
78733289908SGreg Clayton StringSP description_sp(new String);
78833289908SGreg Clayton if (err == -1)
789b9c1b51eSKate Stone description_sp->printf("pid=%i: close (fd=%i) => %i errno = %i (%s))",
790b9c1b51eSKate Stone pid, fd, err, err_errno.get_errno(),
791b9c1b51eSKate Stone strerror(err_errno.get_errno()));
79233289908SGreg Clayton else
793d5e4edbfSGreg Clayton description_sp->printf("pid=%i: close (fd=%i) => %i", pid, fd, err);
79433289908SGreg Clayton if (g_log_all_calls)
79533289908SGreg Clayton description_sp->log(get_logging_fd());
79633289908SGreg Clayton
797b9c1b51eSKate Stone if (err == 0) {
79833289908SGreg Clayton if (fd >= 0)
79933289908SGreg Clayton save_backtrace(fd, err, description_sp, false);
800b9c1b51eSKate Stone } else if (err == -1) {
801b9c1b51eSKate Stone if (err_errno.get_errno() == EBADF && fd != -1) {
802d5e4edbfSGreg Clayton backtrace_error("close (fd=%d) resulted in EBADF:\n", fd);
80333289908SGreg Clayton
80433289908SGreg Clayton FDEventMap::iterator pos = g_fd_event_map.find(fd);
805b9c1b51eSKate Stone if (pos != g_fd_event_map.end()) {
806b9c1b51eSKate Stone log(get_logging_fd(), pos->second.back().get(),
807b9c1b51eSKate Stone "\nfd=%d was previously %s with this event:\n", fd,
808b9c1b51eSKate Stone pos->second.back()->IsCreateEvent() ? "opened" : "closed");
80933289908SGreg Clayton }
81033289908SGreg Clayton }
81133289908SGreg Clayton }
81233289908SGreg Clayton return err;
813b9c1b51eSKate Stone } else {
814d5e4edbfSGreg Clayton return close(fd);
815d5e4edbfSGreg Clayton }
816d5e4edbfSGreg Clayton }
81733289908SGreg Clayton
81833289908SGreg Clayton // close$NOCANCEL() interpose function
close$NOCANCEL$__interposed__(int fd)819b9c1b51eSKate Stone extern "C" int close$NOCANCEL$__interposed__(int fd) {
820d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
821b9c1b51eSKate Stone if (pid >= 0) {
82233289908SGreg Clayton Locker locker(&g_mutex);
82333289908SGreg Clayton const int err = close$NOCANCEL(fd);
82433289908SGreg Clayton NegativeErrorErrno err_errno(err);
82533289908SGreg Clayton StringSP description_sp(new String);
82633289908SGreg Clayton if (err == -1)
827b9c1b51eSKate Stone description_sp->printf(
828b9c1b51eSKate Stone "pid=%i: close$NOCANCEL (fd=%i) => %i errno = %i (%s))", pid, fd, err,
829b9c1b51eSKate Stone err_errno.get_errno(), strerror(err_errno.get_errno()));
83033289908SGreg Clayton else
831b9c1b51eSKate Stone description_sp->printf("pid=%i: close$NOCANCEL (fd=%i) => %i", pid, fd,
832b9c1b51eSKate Stone err);
83333289908SGreg Clayton if (g_log_all_calls)
83433289908SGreg Clayton description_sp->log(get_logging_fd());
83533289908SGreg Clayton
836b9c1b51eSKate Stone if (err == 0) {
83733289908SGreg Clayton if (fd >= 0)
83833289908SGreg Clayton save_backtrace(fd, err, description_sp, false);
839b9c1b51eSKate Stone } else if (err == -1) {
840b9c1b51eSKate Stone if (err_errno.get_errno() == EBADF && fd != -1) {
841d5e4edbfSGreg Clayton backtrace_error("close$NOCANCEL (fd=%d) resulted in EBADF\n:", fd);
84233289908SGreg Clayton
84333289908SGreg Clayton FDEventMap::iterator pos = g_fd_event_map.find(fd);
844b9c1b51eSKate Stone if (pos != g_fd_event_map.end()) {
845b9c1b51eSKate Stone log(get_logging_fd(), pos->second.back().get(),
846b9c1b51eSKate Stone "\nfd=%d was previously %s with this event:\n", fd,
847b9c1b51eSKate Stone pos->second.back()->IsCreateEvent() ? "opened" : "closed");
84833289908SGreg Clayton }
84933289908SGreg Clayton }
85033289908SGreg Clayton }
85133289908SGreg Clayton return err;
852b9c1b51eSKate Stone } else {
853d5e4edbfSGreg Clayton return close$NOCANCEL(fd);
854d5e4edbfSGreg Clayton }
85533289908SGreg Clayton }
85633289908SGreg Clayton
85733289908SGreg Clayton // pipe() interpose function
pipe$__interposed__(int fds[2])858b9c1b51eSKate Stone extern "C" int pipe$__interposed__(int fds[2]) {
859d5e4edbfSGreg Clayton const int pid = get_interposed_pid();
860b9c1b51eSKate Stone if (pid >= 0) {
86133289908SGreg Clayton Locker locker(&g_mutex);
86233289908SGreg Clayton fds[0] = -1;
86333289908SGreg Clayton fds[1] = -1;
86433289908SGreg Clayton const int err = pipe(fds);
86533289908SGreg Clayton const int saved_errno = errno;
866b9c1b51eSKate Stone StringSP description_sp(new String(
867b9c1b51eSKate Stone "pid=%i: pipe ({fd=%i, fd=%i}) -> err=%i", pid, fds[0], fds[1], err));
86833289908SGreg Clayton if (g_log_all_calls)
86933289908SGreg Clayton description_sp->log(get_logging_fd());
87033289908SGreg Clayton if (fds[0] >= 0)
87133289908SGreg Clayton save_backtrace(fds[0], saved_errno, description_sp, true);
87233289908SGreg Clayton if (fds[1] >= 0)
87333289908SGreg Clayton save_backtrace(fds[1], saved_errno, description_sp, true);
87433289908SGreg Clayton errno = saved_errno;
87533289908SGreg Clayton return err;
876b9c1b51eSKate Stone } else {
877d5e4edbfSGreg Clayton return pipe(fds);
878d5e4edbfSGreg Clayton }
879d5e4edbfSGreg Clayton }
88033289908SGreg Clayton
88133289908SGreg Clayton // get_fd_history()
88233289908SGreg Clayton //
88333289908SGreg Clayton // This function allows runtime access to the file descriptor history.
88433289908SGreg Clayton //
88533289908SGreg Clayton // @param[in] log_fd
88633289908SGreg Clayton // The file descriptor to log to
88733289908SGreg Clayton //
88833289908SGreg Clayton // @param[in] fd
88933289908SGreg Clayton // The file descriptor whose history should be dumped
get_fd_history(int log_fd,int fd)890b9c1b51eSKate Stone extern "C" void get_fd_history(int log_fd, int fd) {
89133289908SGreg Clayton // "create" below needs to be outside of the mutex locker scope
892b9c1b51eSKate Stone if (log_fd >= 0) {
89333289908SGreg Clayton bool got_lock = false;
89433289908SGreg Clayton Locker locker(&g_mutex, got_lock);
895b9c1b51eSKate Stone if (got_lock) {
89633289908SGreg Clayton FDEventMap::iterator pos = g_fd_event_map.find(fd);
89733289908SGreg Clayton log_to_fd(log_fd, "Dumping file descriptor history for fd=%i:\n", fd);
898b9c1b51eSKate Stone if (pos != g_fd_event_map.end()) {
89933289908SGreg Clayton FDEventArray &event_array = g_fd_event_map[fd];
90033289908SGreg Clayton const size_t num_events = event_array.size();
90133289908SGreg Clayton for (size_t i = 0; i < num_events; ++i)
90233289908SGreg Clayton event_array[i]->Dump(log_fd);
903b9c1b51eSKate Stone } else {
904b9c1b51eSKate Stone log_to_fd(log_fd, "error: no file descriptor events found for fd=%i\n",
905b9c1b51eSKate Stone fd);
90633289908SGreg Clayton }
907b9c1b51eSKate Stone } else {
90833289908SGreg Clayton log_to_fd(log_fd, "error: fd event mutex is locked...\n");
90933289908SGreg Clayton }
91033289908SGreg Clayton }
91133289908SGreg Clayton }
91233289908SGreg Clayton
91333289908SGreg Clayton // Interposing
91433289908SGreg Clayton // FD creation routines
91533289908SGreg Clayton DYLD_INTERPOSE(accept$__interposed__, accept);
91633289908SGreg Clayton DYLD_INTERPOSE(accept$NOCANCEL$__interposed__, accept$NOCANCEL);
91733289908SGreg Clayton DYLD_INTERPOSE(dup$__interposed__, dup);
91833289908SGreg Clayton DYLD_INTERPOSE(dup2$__interposed__, dup2);
91933289908SGreg Clayton DYLD_INTERPOSE(kqueue$__interposed__, kqueue);
92033289908SGreg Clayton DYLD_INTERPOSE(open$__interposed__, open);
92133289908SGreg Clayton DYLD_INTERPOSE(open$NOCANCEL$__interposed__, open$NOCANCEL);
92233289908SGreg Clayton DYLD_INTERPOSE(__open_extended$__interposed__, __open_extended);
92333289908SGreg Clayton DYLD_INTERPOSE(pipe$__interposed__, pipe);
92433289908SGreg Clayton DYLD_INTERPOSE(shm_open$__interposed__, shm_open);
92533289908SGreg Clayton DYLD_INTERPOSE(socket$__interposed__, socket);
92633289908SGreg Clayton DYLD_INTERPOSE(socketpair$__interposed__, socketpair);
92733289908SGreg Clayton
92833289908SGreg Clayton // FD deleting routines
92933289908SGreg Clayton DYLD_INTERPOSE(close$__interposed__, close);
93033289908SGreg Clayton DYLD_INTERPOSE(close$NOCANCEL$__interposed__, close$NOCANCEL);
93133289908SGreg Clayton
93233289908SGreg Clayton } // namespace fd_interposing
933