OLD | NEW |
1 // Copyright (c) 2005, Google Inc. | 1 // Copyright (c) 2005, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 void InitialPreMMapHook(const void* start, | 121 void InitialPreMMapHook(const void* start, |
122 size_t size, | 122 size_t size, |
123 int protection, | 123 int protection, |
124 int flags, | 124 int flags, |
125 int fd, | 125 int fd, |
126 off_t offset) { | 126 off_t offset) { |
127 perftools_pthread_once(&once, &RemoveInitialHooksAndCallInitializers); | 127 perftools_pthread_once(&once, &RemoveInitialHooksAndCallInitializers); |
128 MallocHook::InvokePreMmapHook(start, size, protection, flags, fd, offset); | 128 MallocHook::InvokePreMmapHook(start, size, protection, flags, fd, offset); |
129 } | 129 } |
130 | 130 |
131 void InitialPreSbrkHook(std::ptrdiff_t increment) { | 131 void InitialPreSbrkHook(ptrdiff_t increment) { |
132 perftools_pthread_once(&once, &RemoveInitialHooksAndCallInitializers); | 132 perftools_pthread_once(&once, &RemoveInitialHooksAndCallInitializers); |
133 MallocHook::InvokePreSbrkHook(increment); | 133 MallocHook::InvokePreSbrkHook(increment); |
134 } | 134 } |
135 | 135 |
136 // This function is called at most once by one of the above initial malloc | 136 // This function is called at most once by one of the above initial malloc |
137 // hooks. It removes all initial hooks and initializes all other clients that | 137 // hooks. It removes all initial hooks and initializes all other clients that |
138 // want to get control at the very first memory allocation. The initializers | 138 // want to get control at the very first memory allocation. The initializers |
139 // may assume that the initial malloc hooks have been removed. The initializers | 139 // may assume that the initial malloc hooks have been removed. The initializers |
140 // may set up malloc hooks and allocate memory. | 140 // may set up malloc hooks and allocate memory. |
141 void RemoveInitialHooksAndCallInitializers() { | 141 void RemoveInitialHooksAndCallInitializers() { |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 return actual_hooks_end; | 276 return actual_hooks_end; |
277 } | 277 } |
278 | 278 |
279 // Initialize a HookList (optionally with the given initial_value in index 0). | 279 // Initialize a HookList (optionally with the given initial_value in index 0). |
280 #define INIT_HOOK_LIST { 0 } | 280 #define INIT_HOOK_LIST { 0 } |
281 #define INIT_HOOK_LIST_WITH_VALUE(initial_value) \ | 281 #define INIT_HOOK_LIST_WITH_VALUE(initial_value) \ |
282 { 1, { reinterpret_cast<AtomicWord>(initial_value) } } | 282 { 1, { reinterpret_cast<AtomicWord>(initial_value) } } |
283 | 283 |
284 // Explicit instantiation for malloc_hook_test.cc. This ensures all the methods | 284 // Explicit instantiation for malloc_hook_test.cc. This ensures all the methods |
285 // are instantiated. | 285 // are instantiated. |
286 template class HookList<MallocHook::NewHook>; | 286 template struct HookList<MallocHook::NewHook>; |
287 | 287 |
288 HookList<MallocHook::NewHook> new_hooks_ = | 288 HookList<MallocHook::NewHook> new_hooks_ = |
289 INIT_HOOK_LIST_WITH_VALUE(&InitialNewHook); | 289 INIT_HOOK_LIST_WITH_VALUE(&InitialNewHook); |
290 HookList<MallocHook::DeleteHook> delete_hooks_ = INIT_HOOK_LIST; | 290 HookList<MallocHook::DeleteHook> delete_hooks_ = INIT_HOOK_LIST; |
291 HookList<MallocHook::PreMmapHook> premmap_hooks_ = | 291 HookList<MallocHook::PreMmapHook> premmap_hooks_ = |
292 INIT_HOOK_LIST_WITH_VALUE(&InitialPreMMapHook); | 292 INIT_HOOK_LIST_WITH_VALUE(&InitialPreMMapHook); |
293 HookList<MallocHook::MmapHook> mmap_hooks_ = INIT_HOOK_LIST; | 293 HookList<MallocHook::MmapHook> mmap_hooks_ = INIT_HOOK_LIST; |
294 HookList<MallocHook::MunmapHook> munmap_hooks_ = INIT_HOOK_LIST; | 294 HookList<MallocHook::MunmapHook> munmap_hooks_ = INIT_HOOK_LIST; |
295 HookList<MallocHook::MremapHook> mremap_hooks_ = INIT_HOOK_LIST; | 295 HookList<MallocHook::MremapHook> mremap_hooks_ = INIT_HOOK_LIST; |
296 HookList<MallocHook::PreSbrkHook> presbrk_hooks_ = | 296 HookList<MallocHook::PreSbrkHook> presbrk_hooks_ = |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 void MallocHook::InvokeMremapHookSlow(const void* result, | 582 void MallocHook::InvokeMremapHookSlow(const void* result, |
583 const void* old_addr, | 583 const void* old_addr, |
584 size_t old_size, | 584 size_t old_size, |
585 size_t new_size, | 585 size_t new_size, |
586 int flags, | 586 int flags, |
587 const void* new_addr) { | 587 const void* new_addr) { |
588 INVOKE_HOOKS(MremapHook, mremap_hooks_, (result, old_addr, old_size, new_size, | 588 INVOKE_HOOKS(MremapHook, mremap_hooks_, (result, old_addr, old_size, new_size, |
589 flags, new_addr)); | 589 flags, new_addr)); |
590 } | 590 } |
591 | 591 |
592 void MallocHook::InvokePreSbrkHookSlow(std::ptrdiff_t increment) { | 592 void MallocHook::InvokePreSbrkHookSlow(ptrdiff_t increment) { |
593 INVOKE_HOOKS(PreSbrkHook, presbrk_hooks_, (increment)); | 593 INVOKE_HOOKS(PreSbrkHook, presbrk_hooks_, (increment)); |
594 } | 594 } |
595 | 595 |
596 void MallocHook::InvokeSbrkHookSlow(const void* result, std::ptrdiff_t increment
) { | 596 void MallocHook::InvokeSbrkHookSlow(const void* result, ptrdiff_t increment) { |
597 INVOKE_HOOKS(SbrkHook, sbrk_hooks_, (result, increment)); | 597 INVOKE_HOOKS(SbrkHook, sbrk_hooks_, (result, increment)); |
598 } | 598 } |
599 | 599 |
600 #undef INVOKE_HOOKS | 600 #undef INVOKE_HOOKS |
601 | 601 |
602 DEFINE_ATTRIBUTE_SECTION_VARS(google_malloc); | 602 DEFINE_ATTRIBUTE_SECTION_VARS(google_malloc); |
603 DECLARE_ATTRIBUTE_SECTION_VARS(google_malloc); | 603 DECLARE_ATTRIBUTE_SECTION_VARS(google_malloc); |
604 // actual functions are in debugallocation.cc or tcmalloc.cc | 604 // actual functions are in debugallocation.cc or tcmalloc.cc |
605 DEFINE_ATTRIBUTE_SECTION_VARS(malloc_hook); | 605 DEFINE_ATTRIBUTE_SECTION_VARS(malloc_hook); |
606 DECLARE_ATTRIBUTE_SECTION_VARS(malloc_hook); | 606 DECLARE_ATTRIBUTE_SECTION_VARS(malloc_hook); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
691 } | 691 } |
692 RAW_LOG(WARNING, "Hooked allocator frame not found, returning empty trace"); | 692 RAW_LOG(WARNING, "Hooked allocator frame not found, returning empty trace"); |
693 // If this happens try increasing kMaxSkip | 693 // If this happens try increasing kMaxSkip |
694 // or else something must be wrong with InHookCaller, | 694 // or else something must be wrong with InHookCaller, |
695 // e.g. for every section used in InHookCaller | 695 // e.g. for every section used in InHookCaller |
696 // all functions in that section must be inside the same library. | 696 // all functions in that section must be inside the same library. |
697 return 0; | 697 return 0; |
698 #endif | 698 #endif |
699 } | 699 } |
700 | 700 |
701 // On Linux/x86, we override mmap/munmap/mremap/sbrk | 701 // On systems where we know how, we override mmap/munmap/mremap/sbrk |
702 // and provide support for calling the related hooks. | 702 // to provide support for calling the related hooks (in addition, |
703 // | 703 // of course, to doing what these functions normally do). |
704 // We define mmap() and mmap64(), which somewhat reimplements libc's mmap | |
705 // syscall stubs. Unfortunately libc only exports the stubs via weak symbols | |
706 // (which we're overriding with our mmap64() and mmap() wrappers) so we can't | |
707 // just call through to them. | |
708 | 704 |
| 705 #if defined(__linux) |
| 706 # include "malloc_hook_mmap_linux.h" |
709 | 707 |
710 #if defined(__linux) && \ | 708 // This code doesn't even compile on my freebsd 8.1 (x86_64) system, |
711 (defined(__i386__) || defined(__x86_64__) || defined(__PPC__)) | 709 // so comment it out for now. TODO(csilvers): fix this! |
712 #include <unistd.h> | 710 #elif 0 && defined(__FreeBSD__) |
713 #include <syscall.h> | 711 # include "malloc_hook_mmap_freebsd.h" |
714 #include <sys/mman.h> | |
715 #include <errno.h> | |
716 #include "base/linux_syscall_support.h" | |
717 | 712 |
718 // The x86-32 case and the x86-64 case differ: | 713 #else |
719 // 32b has a mmap2() syscall, 64b does not. | |
720 // 64b and 32b have different calling conventions for mmap(). | |
721 #if defined(__x86_64__) || defined(__PPC64__) | |
722 | |
723 static inline void* do_mmap64(void *start, size_t length, | |
724 int prot, int flags, | |
725 int fd, __off64_t offset) __THROW { | |
726 return (void *)syscall(SYS_mmap, start, length, prot, flags, fd, offset); | |
727 } | |
728 | |
729 #elif defined(__i386__) || defined(__PPC__) | |
730 | |
731 static inline void* do_mmap64(void *start, size_t length, | |
732 int prot, int flags, | |
733 int fd, __off64_t offset) __THROW { | |
734 void *result; | |
735 | |
736 // Try mmap2() unless it's not supported | |
737 static bool have_mmap2 = true; | |
738 if (have_mmap2) { | |
739 static int pagesize = 0; | |
740 if (!pagesize) pagesize = getpagesize(); | |
741 | |
742 // Check that the offset is page aligned | |
743 if (offset & (pagesize - 1)) { | |
744 result = MAP_FAILED; | |
745 errno = EINVAL; | |
746 goto out; | |
747 } | |
748 | |
749 result = (void *)syscall(SYS_mmap2, | |
750 start, length, prot, flags, fd, | |
751 (off_t) (offset / pagesize)); | |
752 if (result != MAP_FAILED || errno != ENOSYS) goto out; | |
753 | |
754 // We don't have mmap2() after all - don't bother trying it in future | |
755 have_mmap2 = false; | |
756 } | |
757 | |
758 if (((off_t)offset) != offset) { | |
759 // If we're trying to map a 64-bit offset, fail now since we don't | |
760 // have 64-bit mmap() support. | |
761 result = MAP_FAILED; | |
762 errno = EINVAL; | |
763 goto out; | |
764 } | |
765 | |
766 { | |
767 // Fall back to old 32-bit offset mmap() call | |
768 // Old syscall interface cannot handle six args, so pass in an array | |
769 int32 args[6] = { (int32) start, length, prot, flags, fd, (off_t) offset }; | |
770 result = (void *)syscall(SYS_mmap, args); | |
771 } | |
772 out: | |
773 return result; | |
774 } | |
775 | |
776 # endif // defined(__x86_64__) | |
777 | |
778 // We use do_mmap64 abstraction to put MallocHook::InvokeMmapHook | |
779 // calls right into mmap and mmap64, so that the stack frames in the caller's | |
780 // stack are at the same offsets for all the calls of memory allocating | |
781 // functions. | |
782 | |
783 // Put all callers of MallocHook::Invoke* in this module into | |
784 // malloc_hook section, | |
785 // so that MallocHook::GetCallerStackTrace can function accurately: | |
786 | |
787 // Make sure mmap doesn't get #define'd away by <sys/mman.h> | |
788 #undef mmap | |
789 | |
790 extern "C" { | |
791 void* mmap64(void *start, size_t length, int prot, int flags, | |
792 int fd, __off64_t offset ) __THROW | |
793 ATTRIBUTE_SECTION(malloc_hook); | |
794 void* mmap(void *start, size_t length,int prot, int flags, | |
795 int fd, off_t offset) __THROW | |
796 ATTRIBUTE_SECTION(malloc_hook); | |
797 int munmap(void* start, size_t length) __THROW | |
798 ATTRIBUTE_SECTION(malloc_hook); | |
799 void* mremap(void* old_addr, size_t old_size, size_t new_size, | |
800 int flags, ...) __THROW | |
801 ATTRIBUTE_SECTION(malloc_hook); | |
802 void* sbrk(std::ptrdiff_t increment) __THROW | |
803 ATTRIBUTE_SECTION(malloc_hook); | |
804 } | |
805 | |
806 extern "C" void* mmap64(void *start, size_t length, int prot, int flags, | |
807 int fd, __off64_t offset) __THROW { | |
808 MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset); | |
809 void *result; | |
810 if (!MallocHook::InvokeMmapReplacement( | |
811 start, length, prot, flags, fd, offset, &result)) { | |
812 result = do_mmap64(start, length, prot, flags, fd, offset); | |
813 } | |
814 MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset); | |
815 return result; | |
816 } | |
817 | |
818 #if !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH) | |
819 | |
820 extern "C" void* mmap(void *start, size_t length, int prot, int flags, | |
821 int fd, off_t offset) __THROW { | |
822 MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset); | |
823 void *result; | |
824 if (!MallocHook::InvokeMmapReplacement( | |
825 start, length, prot, flags, fd, offset, &result)) { | |
826 result = do_mmap64(start, length, prot, flags, fd, | |
827 static_cast<size_t>(offset)); // avoid sign extension | |
828 } | |
829 MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset); | |
830 return result; | |
831 } | |
832 | |
833 #endif // !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH) | |
834 | |
835 extern "C" int munmap(void* start, size_t length) __THROW { | |
836 MallocHook::InvokeMunmapHook(start, length); | |
837 int result; | |
838 if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) { | |
839 result = syscall(SYS_munmap, start, length); | |
840 } | |
841 return result; | |
842 } | |
843 | |
844 extern "C" void* mremap(void* old_addr, size_t old_size, size_t new_size, | |
845 int flags, ...) __THROW { | |
846 va_list ap; | |
847 va_start(ap, flags); | |
848 void *new_address = va_arg(ap, void *); | |
849 va_end(ap); | |
850 void* result = sys_mremap(old_addr, old_size, new_size, flags, new_address); | |
851 MallocHook::InvokeMremapHook(result, old_addr, old_size, new_size, flags, | |
852 new_address); | |
853 return result; | |
854 } | |
855 | |
856 // libc's version: | |
857 extern "C" void* __sbrk(std::ptrdiff_t increment); | |
858 | |
859 extern "C" void* sbrk(std::ptrdiff_t increment) __THROW { | |
860 MallocHook::InvokePreSbrkHook(increment); | |
861 void *result = __sbrk(increment); | |
862 MallocHook::InvokeSbrkHook(result, increment); | |
863 return result; | |
864 } | |
865 | |
866 /*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot, | |
867 int flags, int fd, off_t offset) { | |
868 void* result; | |
869 if (!MallocHook::InvokeMmapReplacement( | |
870 start, length, prot, flags, fd, offset, &result)) { | |
871 result = do_mmap64(start, length, prot, flags, fd, offset); | |
872 } | |
873 return result; | |
874 } | |
875 | |
876 /*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) { | |
877 int result; | |
878 if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) { | |
879 result = sys_munmap(start, length); | |
880 } | |
881 return result; | |
882 } | |
883 | |
884 #else // defined(__linux) && | |
885 // (defined(__i386__) || defined(__x86_64__) || defined(__PPC__)) | |
886 | 714 |
887 /*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot, | 715 /*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot, |
888 int flags, int fd, off_t offset) { | 716 int flags, int fd, off_t offset) { |
889 void* result; | 717 void* result; |
890 if (!MallocHook::InvokeMmapReplacement( | 718 if (!MallocHook::InvokeMmapReplacement( |
891 start, length, prot, flags, fd, offset, &result)) { | 719 start, length, prot, flags, fd, offset, &result)) { |
892 result = mmap(start, length, prot, flags, fd, offset); | 720 result = mmap(start, length, prot, flags, fd, offset); |
893 } | 721 } |
894 return result; | 722 return result; |
895 } | 723 } |
896 | 724 |
897 /*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) { | 725 /*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) { |
898 int result; | 726 int result; |
899 if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) { | 727 if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) { |
900 result = munmap(start, length); | 728 result = munmap(start, length); |
901 } | 729 } |
902 return result; | 730 return result; |
903 } | 731 } |
904 | 732 |
905 #endif // defined(__linux) && | 733 #endif |
906 // (defined(__i386__) || defined(__x86_64__) || defined(__PPC__)) | |
OLD | NEW |