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