00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "config.h"
00034
00035
00036
00037
00038 #ifdef HAVE_MMAP
00039 # define mremap glibc_mremap
00040 # include <sys/mman.h>
00041 # undef mremap
00042 #endif
00043
00044 #include <google/malloc_hook.h>
00045 #include "base/basictypes.h"
00046 #include "base/logging.h"
00047 #include <google/stacktrace.h>
00048
00049
00050
00051
00052 #ifndef __THROW // I guess we're not on a glibc system
00053 # define __THROW // __THROW is just an optimization, so ok to make it ""
00054 #endif
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 ATTRIBUTE_WEAK
00071 extern void InitialMallocHook_New(const void* ptr, size_t size);
00072
00073 ATTRIBUTE_WEAK
00074 extern void InitialMallocHook_MMap(const void* result,
00075 const void* start,
00076 size_t size,
00077 int protection,
00078 int flags,
00079 int fd,
00080 off_t offset);
00081
00082 ATTRIBUTE_WEAK
00083 extern void InitialMallocHook_Sbrk(const void* result, ptrdiff_t increment);
00084
00085 MallocHook::NewHook MallocHook::new_hook_ = InitialMallocHook_New;
00086 MallocHook::DeleteHook MallocHook::delete_hook_ = NULL;
00087 MallocHook::MmapHook MallocHook::mmap_hook_ = InitialMallocHook_MMap;
00088 MallocHook::MunmapHook MallocHook::munmap_hook_ = NULL;
00089 MallocHook::MremapHook MallocHook::mremap_hook_ = NULL;
00090 MallocHook::SbrkHook MallocHook::sbrk_hook_ = InitialMallocHook_Sbrk;
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 void InitialMallocHook_New(const void* ptr, size_t size) {
00115 if (MallocHook::GetNewHook() == &InitialMallocHook_New)
00116 MallocHook::SetNewHook(NULL);
00117 }
00118
00119 void InitialMallocHook_MMap(const void* result,
00120 const void* start,
00121 size_t size,
00122 int protection,
00123 int flags,
00124 int fd,
00125 off_t offset) {
00126 if (MallocHook::GetMmapHook() == &InitialMallocHook_MMap)
00127 MallocHook::SetMmapHook(NULL);
00128 }
00129
00130 void InitialMallocHook_Sbrk(const void* result, ptrdiff_t increment) {
00131 if (MallocHook::GetSbrkHook() == &InitialMallocHook_Sbrk)
00132 MallocHook::SetSbrkHook(NULL);
00133 }
00134
00135 DEFINE_ATTRIBUTE_SECTION_VARS(google_malloc);
00136 DECLARE_ATTRIBUTE_SECTION_VARS(google_malloc);
00137
00138 DEFINE_ATTRIBUTE_SECTION_VARS(malloc_hook);
00139 DECLARE_ATTRIBUTE_SECTION_VARS(malloc_hook);
00140
00141
00142 #define ADDR_IN_ATTRIBUTE_SECTION(addr, name) \
00143 (reinterpret_cast<uintptr_t>(ATTRIBUTE_SECTION_START(name)) <= \
00144 reinterpret_cast<uintptr_t>(addr) && \
00145 reinterpret_cast<uintptr_t>(addr) < \
00146 reinterpret_cast<uintptr_t>(ATTRIBUTE_SECTION_STOP(name)))
00147
00148
00149
00150
00151 static inline bool InHookCaller(const void* caller) {
00152 return ADDR_IN_ATTRIBUTE_SECTION(caller, google_malloc) ||
00153 ADDR_IN_ATTRIBUTE_SECTION(caller, malloc_hook);
00154
00155
00156 }
00157
00158 #undef ADDR_IN_ATTRIBUTE_SECTION
00159
00160 static bool checked_sections = false;
00161
00162 static inline void CheckInHookCaller() {
00163 if (!checked_sections) {
00164 INIT_ATTRIBUTE_SECTION_VARS(google_malloc);
00165 if (ATTRIBUTE_SECTION_START(google_malloc) ==
00166 ATTRIBUTE_SECTION_STOP(google_malloc)) {
00167 RAW_LOG(ERROR, "google_malloc section is missing, "
00168 "thus InHookCaller is broken!");
00169 }
00170 INIT_ATTRIBUTE_SECTION_VARS(malloc_hook);
00171 if (ATTRIBUTE_SECTION_START(malloc_hook) ==
00172 ATTRIBUTE_SECTION_STOP(malloc_hook)) {
00173 RAW_LOG(ERROR, "malloc_hook section is missing, "
00174 "thus InHookCaller is broken!");
00175 }
00176 checked_sections = true;
00177 }
00178 }
00179
00180
00181
00182
00183 int MallocHook::GetCallerStackTrace(void** result, int max_depth,
00184 int skip_count) {
00185 #ifndef HAVE_ATTRIBUTE_SECTION_START
00186
00187
00188
00189
00190 return GetStackTrace(result, max_depth, skip_count + int(DEBUG_MODE));
00191
00192
00193 #endif
00194 CheckInHookCaller();
00195
00196 static const int kMaxSkip = 32 + 6 + 3;
00197
00198
00199
00200
00201
00202 static const int kStackSize = kMaxSkip + 1;
00203 void* stack[kStackSize];
00204 int depth = GetStackTrace(stack, kStackSize, 1);
00205 if (depth == 0)
00206 return 0;
00207 for (int i = 0; i < depth; ++i) {
00208 if (InHookCaller(stack[i])) {
00209 RAW_VLOG(4, "Found hooked allocator at %d: %p <- %p",
00210 i, stack[i], stack[i+1]);
00211 i += 1;
00212 depth -= i;
00213 if (depth > max_depth) depth = max_depth;
00214 memcpy(result, stack+i, depth * sizeof(stack[0]));
00215 if (depth < max_depth && depth + i == kStackSize) {
00216
00217 depth +=
00218 GetStackTrace(result + depth, max_depth - depth, 1 + kStackSize);
00219 }
00220 return depth;
00221 }
00222 }
00223 RAW_LOG(WARNING, "Hooked allocator frame not found, returning empty trace");
00224
00225 return 0;
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 #if defined(__linux) && (defined(__i386__) || defined(__x86_64__))
00238 #include <unistd.h>
00239 #include <syscall.h>
00240 #include <sys/mman.h>
00241 #include <errno.h>
00242 #include "base/linux_syscall_support.h"
00243
00244
00245
00246
00247 #if defined(__i386__)
00248
00249 static inline void* do_mmap64(void *start, size_t length,
00250 int prot, int flags,
00251 int fd, __off64_t offset) __THROW {
00252 void *result;
00253
00254
00255 static bool have_mmap2 = true;
00256 if (have_mmap2) {
00257 static int pagesize = 0;
00258 if (!pagesize) pagesize = getpagesize();
00259
00260
00261 if (offset & (pagesize - 1)) {
00262 result = MAP_FAILED;
00263 errno = EINVAL;
00264 goto out;
00265 }
00266
00267 result = (void *)syscall(SYS_mmap2,
00268 start, length, prot, flags, fd, offset / pagesize);
00269 if (result != MAP_FAILED || errno != ENOSYS) goto out;
00270
00271
00272 have_mmap2 = false;
00273 }
00274
00275 if (((off_t)offset) != offset) {
00276
00277
00278 result = MAP_FAILED;
00279 errno = EINVAL;
00280 goto out;
00281 }
00282
00283 {
00284
00285
00286 int32 args[6] = { (int32) start, length, prot, flags, fd, (off_t) offset };
00287 result = (void *)syscall(SYS_mmap, args);
00288 }
00289 out:
00290 return result;
00291 }
00292
00293 # elif defined(__x86_64__)
00294
00295 static inline void* do_mmap64(void *start, size_t length,
00296 int prot, int flags,
00297 int fd, __off64_t offset) __THROW {
00298 return (void *)syscall(SYS_mmap, start, length, prot, flags, fd, offset);
00299 }
00300
00301 # endif
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 extern "C" {
00312 void* mmap64(void *start, size_t length, int prot, int flags,
00313 int fd, __off64_t offset ) __THROW
00314 ATTRIBUTE_SECTION(malloc_hook);
00315 void* mmap(void *start, size_t length,int prot, int flags,
00316 int fd, off_t offset) __THROW
00317 ATTRIBUTE_SECTION(malloc_hook);
00318 int munmap(void* start, size_t length) __THROW
00319 ATTRIBUTE_SECTION(malloc_hook);
00320 void* mremap(void* old_addr, size_t old_size, size_t new_size,
00321 int flags, ...) __THROW
00322 ATTRIBUTE_SECTION(malloc_hook);
00323 void* sbrk(ptrdiff_t increment) __THROW
00324 ATTRIBUTE_SECTION(malloc_hook);
00325 }
00326
00327 extern "C" void* mmap64(void *start, size_t length, int prot, int flags,
00328 int fd, __off64_t offset) __THROW {
00329 void *result = do_mmap64(start, length, prot, flags, fd, offset);
00330 MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset);
00331 return result;
00332 }
00333
00334 extern "C" void* mmap(void *start, size_t length, int prot, int flags,
00335 int fd, off_t offset) __THROW {
00336 void *result = do_mmap64(start, length, prot, flags, fd,
00337 static_cast<size_t>(offset));
00338 MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset);
00339 return result;
00340 }
00341
00342 extern "C" int munmap(void* start, size_t length) __THROW {
00343 MallocHook::InvokeMunmapHook(start, length);
00344 return syscall(SYS_munmap, start, length);
00345 }
00346
00347 extern "C" void* mremap(void* old_addr, size_t old_size, size_t new_size,
00348 int flags, ...) __THROW {
00349 va_list ap;
00350 va_start(ap, flags);
00351 void *new_address = va_arg(ap, void *);
00352 va_end(ap);
00353 void* result = sys_mremap(old_addr, old_size, new_size, flags, new_address);
00354 MallocHook::InvokeMremapHook(result, old_addr, old_size, new_size, flags,
00355 new_address);
00356 return result;
00357 }
00358
00359
00360 extern "C" void* __sbrk(ptrdiff_t increment);
00361
00362 extern "C" void* sbrk(ptrdiff_t increment) __THROW {
00363 void *result = __sbrk(increment);
00364 MallocHook::InvokeSbrkHook(result, increment);
00365 return result;
00366 }
00367
00368 #endif