/* Initializes memory allocation framework once per process. */ static void malloc_init_impl(void) { const char* so_name = NULL; MallocDebugInit malloc_debug_initialize = NULL; unsigned int qemu_running = 0; unsigned int debug_level = 0; unsigned int memcheck_enabled = 0; char env[PROP_VALUE_MAX]; char memcheck_tracing[PROP_VALUE_MAX]; // added by zmj mspace_malloc_stat = NULL; mspace_free_stat = NULL; #ifdef _MTK_ENG_ debug_level = 15; #else debug_level = 0; #endif /* Get custom malloc debug level. Note that emulator started with * memory checking option will have priority over debug level set in * libc.debug.malloc system property. */ if (__system_property_get("ro.kernel.qemu", env) && atoi(env)) { qemu_running = 1; if (__system_property_get("ro.kernel.memcheck", memcheck_tracing)) { if (memcheck_tracing[0] != '0') { // Emulator has started with memory tracing enabled. Enforce it. debug_level = 20; memcheck_enabled = 1; } } } /* If debug level has not been set by memcheck option in the emulator, * lets grab it from libc.debug.malloc system property. */ if ((debug_level != 20) && __system_property_get("libc.debug.malloc", env)) { debug_level = atoi(env); } if ((debug_level != 20) && __system_property_get("persist.libc.debug.malloc", env)) { debug_level = atoi(env); } if (__system_property_get("ro.build.type", env)) { if(strncmp(env, "eng", 3)) debug_level = 0; } /* Debug level 0 means that we should use dlxxx allocation * routines (default). */ if (!debug_level) { return; } // Lets see which .so must be loaded for the requested debug level switch (debug_level) { case 1: case 5: case 10: so_name = "/system/lib/libc_malloc_debug_leak.so"; break; case 15: case 16: so_name = "/system/lib/libc_malloc_debug_mtk.so"; break; case 20: // Quick check: debug level 20 can only be handled in emulator. if (!qemu_running) { error_log("%s: Debug level %d can only be set in emulator\n", __progname, debug_level); return; } // Make sure that memory checking has been enabled in emulator. if (!memcheck_enabled) { error_log("%s: Memory checking is not enabled in the emulator\n", __progname); return; } so_name = "/system/lib/libc_malloc_debug_qemu.so"; break; default: error_log("%s: Debug level %d is unknown\n", __progname, debug_level); return; } // Load .so that implements the required malloc debugging functionality. libc_malloc_impl_handle = dlopen(so_name, RTLD_LAZY); if (libc_malloc_impl_handle == NULL) { error_log("%s: Missing module %s required for malloc debug level %d\n", __progname, so_name, debug_level); return; } // Initialize malloc debugging in the loaded module. malloc_debug_initialize = dlsym(libc_malloc_impl_handle, "malloc_debug_initialize"); if (malloc_debug_initialize == NULL) { error_log("%s: Initialization routine is not found in %s\n", __progname, so_name); dlclose(libc_malloc_impl_handle); return; } if (malloc_debug_initialize()) { dlclose(libc_malloc_impl_handle); return; } if (debug_level == 20) { // For memory checker we need to do extra initialization. int (*memcheck_initialize)(int, const char*) = dlsym(libc_malloc_impl_handle, "memcheck_initialize"); if (memcheck_initialize == NULL) { error_log("%s: memcheck_initialize routine is not found in %s\n", __progname, so_name); dlclose(libc_malloc_impl_handle); return; } if (memcheck_initialize(MALLOC_ALIGNMENT, memcheck_tracing)) { dlclose(libc_malloc_impl_handle); return; } } if (debug_level == 15) { int sig = 0; // For debug 15 we need to do extra initialization. int (*debug15_extra_initialize)(int) = dlsym(libc_malloc_impl_handle, "debug15_extra_initialize"); if (debug15_extra_initialize == NULL) { error_log("%s: malloc_debug_extra_initialize routine is not found in %s\n", __progname, so_name); dlclose(libc_malloc_impl_handle); return; } if (__system_property_get("persist.debug15.sig", env)) { sig = atoi(env); } if (debug15_extra_initialize(sig)) { dlclose(libc_malloc_impl_handle); return; } // to indicate that debug 15 is on. __system_property_set("libc.debug15.status", "on"); } // Initialize malloc dispatch table with appropriate routines. switch (debug_level) { case 1: __libc_android_log_print(ANDROID_LOG_INFO, "libc", "%s using MALLOC_DEBUG = %d (leak checker)\n", __progname, debug_level); gMallocUse.malloc = dlsym(libc_malloc_impl_handle, "leak_malloc"); gMallocUse.free = dlsym(libc_malloc_impl_handle, "leak_free"); gMallocUse.calloc = dlsym(libc_malloc_impl_handle, "leak_calloc"); gMallocUse.realloc = dlsym(libc_malloc_impl_handle, "leak_realloc"); gMallocUse.memalign = dlsym(libc_malloc_impl_handle, "leak_memalign"); break; case 5: __libc_android_log_print(ANDROID_LOG_INFO, "libc", "%s using MALLOC_DEBUG = %d (fill)\n", __progname, debug_level); gMallocUse.malloc = dlsym(libc_malloc_impl_handle, "fill_malloc"); gMallocUse.free = dlsym(libc_malloc_impl_handle, "fill_free"); gMallocUse.calloc = dlcalloc; gMallocUse.realloc = dlsym(libc_malloc_impl_handle, "fill_realloc"); gMallocUse.memalign = dlsym(libc_malloc_impl_handle, "fill_memalign"); break; case 10: __libc_android_log_print(ANDROID_LOG_INFO, "libc", "%s using MALLOC_DEBUG = %d (sentinels, fill)\n", __progname, debug_level); gMallocUse.malloc = dlsym(libc_malloc_impl_handle, "chk_malloc"); gMallocUse.free = dlsym(libc_malloc_impl_handle, "chk_free"); gMallocUse.calloc = dlsym(libc_malloc_impl_handle, "chk_calloc"); gMallocUse.realloc = dlsym(libc_malloc_impl_handle, "chk_realloc"); gMallocUse.memalign = dlsym(libc_malloc_impl_handle, "chk_memalign"); break; case 15: __libc_android_log_print(ANDROID_LOG_INFO, "libc", "%s using MALLOC_DEBUG = %d(dlmalloc, BT)\n", __progname, debug_level); gMallocUse.malloc = dlsym(libc_malloc_impl_handle, "mtk_malloc"); gMallocUse.free = dlsym(libc_malloc_impl_handle, "mtk_free"); gMallocUse.calloc = dlsym(libc_malloc_impl_handle, "mtk_calloc"); gMallocUse.realloc = dlsym(libc_malloc_impl_handle, "mtk_realloc"); gMallocUse.memalign = dlsym(libc_malloc_impl_handle, "mtk_memalign"); gpMallocFullBacktrace = dlsym(libc_malloc_impl_handle, "mtk_malloc_full_backtrace"); gpFreeFullBacktrace = dlsym(libc_malloc_impl_handle, "mtk_free_full_backtrace"); break; case 16: __libc_android_log_print(ANDROID_LOG_INFO, "libc", "%s using MALLOC_DEBUG = %d (dlmalloc, mspace, BT)\n", __progname, debug_level); gMallocUse.malloc = dlsym(libc_malloc_impl_handle, "mtk_malloc"); gMallocUse.free = dlsym(libc_malloc_impl_handle, "mtk_free"); gMallocUse.calloc = dlsym(libc_malloc_impl_handle, "mtk_calloc"); gMallocUse.realloc = dlsym(libc_malloc_impl_handle, "mtk_realloc"); gMallocUse.memalign = dlsym(libc_malloc_impl_handle, "mtk_memalign"); mspace_malloc_stat = dlsym(libc_malloc_impl_handle, "mtk_mspace_malloc_stat"); mspace_free_stat = dlsym(libc_malloc_impl_handle, "mtk_mspace_free_stat"); break; case 20: __libc_android_log_print(ANDROID_LOG_INFO, "libc", "%s[%u] using MALLOC_DEBUG = %d (instrumented for emulator)\n", __progname, getpid(), debug_level); gMallocUse.malloc = dlsym(libc_malloc_impl_handle, "qemu_instrumented_malloc"); gMallocUse.free = dlsym(libc_malloc_impl_handle, "qemu_instrumented_free"); gMallocUse.calloc = dlsym(libc_malloc_impl_handle, "qemu_instrumented_calloc"); gMallocUse.realloc = dlsym(libc_malloc_impl_handle, "qemu_instrumented_realloc"); gMallocUse.memalign = dlsym(libc_malloc_impl_handle, "qemu_instrumented_memalign"); break; default: break; } // Make sure dispatch table is initialized if ((gMallocUse.malloc == NULL) || (gMallocUse.free == NULL) || (gMallocUse.calloc == NULL) || (gMallocUse.realloc == NULL) || (gMallocUse.memalign == NULL)) { error_log("%s: Cannot initialize malloc dispatch table for debug level" " %d: %p, %p, %p, %p, %p\n", __progname, debug_level, gMallocUse.malloc, gMallocUse.free, gMallocUse.calloc, gMallocUse.realloc, gMallocUse.memalign); dlclose(libc_malloc_impl_handle); libc_malloc_impl_handle = NULL; } else { __libc_malloc_dispatch = &gMallocUse; } }
/* Initializes memory allocation framework once per process. */ static void malloc_init_impl() { const char* so_name = NULL; MallocDebugInit malloc_debug_initialize = NULL; unsigned int qemu_running = 0; unsigned int debug_level = 0; unsigned int memcheck_enabled = 0; char env[PROP_VALUE_MAX]; char memcheck_tracing[PROP_VALUE_MAX]; char debug_program[PROP_VALUE_MAX]; /* BEGIN mtk-added: */ /* * since there are NO libc_malloc_debug_leak.so, libc_malloc_debug_qemu.so and * libc_malloc_debug_xxx.so on user load, * speed up the malloc initialization. */ #ifdef IS_USER_BUILD /* Debug level 0 means that we should use dlxxx allocation * routines (default). */ if (debug_level == 0) { return; } #endif /* * debug 15 is enable by default ONLY when: * 1. MTK ENG load -> frame pointer, apcs, arm * 2. malloc debug feature is on. */ #if defined(HAVE_MALLOC_DEBUG_FEATURE) && defined(_MTK_ENG_) debug_level = 15; #else debug_level = 0; #endif // TODO: temp solution. need optimize. #if defined(DISABLE_MALLOC_DEBUG) debug_level = 0; #endif #ifdef HAVE_MALLOC_DEBUG_FEATURE /* debug level priority * 0 < (15, 16) < (1, 5, 10) < 20 */ if (__system_property_get("persist.libc.debug.malloc", env)) { debug_level = atoi(env); // overwrite initial value(0, or 15) } #endif /* END mtk-added. */ /* Get custom malloc debug level. Note that emulator started with * memory checking option will have priority over debug level set in * libc.debug.malloc system property. */ if (__system_property_get("ro.kernel.qemu", env) && atoi(env)) { qemu_running = 1; if (__system_property_get("ro.kernel.memcheck", memcheck_tracing)) { if (memcheck_tracing[0] != '0') { // Emulator has started with memory tracing enabled. Enforce it. debug_level = 20; memcheck_enabled = 1; } } } /* BEGIN mtk-modified: libc.debug.malloc will overwrite persist.libc.debug.malloc */ /* If debug level has not been set by memcheck option in the emulator, * lets grab it from libc.debug.malloc system property. */ if ((debug_level == 0 || debug_level == 15 || debug_level == 16) && __system_property_get("libc.debug.malloc", env)) { debug_level = atoi(env); // overwrite previous value(0, 15 or 16) } /* END mtk-modified: */ /* Debug level 0 means that we should use dlxxx allocation * routines (default). */ if (debug_level == 0) { return; } /* If libc.debug.malloc.program is set and is not a substring of progname, * then exit. */ if (__system_property_get("libc.debug.malloc.program", debug_program)) { if (!strstr(__progname, debug_program)) { return; } } // Lets see which .so must be loaded for the requested debug level switch (debug_level) { case 1: case 5: case 10: { char debug_backlog[PROP_VALUE_MAX]; if (__system_property_get("libc.debug.malloc.backlog", debug_backlog)) { malloc_double_free_backlog = atoi(debug_backlog); info_log("%s: setting backlog length to %d\n", __progname, malloc_double_free_backlog); } so_name = "/system/lib/libc_malloc_debug_leak.so"; break; } /* BEGIN mtk-added: */ #if defined(HAVE_MALLOC_DEBUG_FEATURE) || defined(HAVE_MSPACE_DEBUG_FEATURE) case 15: case 16: so_name = "/system/lib/libc_malloc_debug_mtk.so"; break; #endif /* END mtk-added. */ case 20: // Quick check: debug level 20 can only be handled in emulator. if (!qemu_running) { error_log("%s: Debug level %d can only be set in emulator\n", __progname, debug_level); return; } // Make sure that memory checking has been enabled in emulator. if (!memcheck_enabled) { error_log("%s: Memory checking is not enabled in the emulator\n", __progname); return; } so_name = "/system/lib/libc_malloc_debug_qemu.so"; break; default: error_log("%s: Debug level %d is unknown\n", __progname, debug_level); return; } // Load .so that implements the required malloc debugging functionality. libc_malloc_impl_handle = dlopen(so_name, RTLD_LAZY); if (libc_malloc_impl_handle == NULL) { error_log("%s: Missing module %s required for malloc debug level %d: %s", __progname, so_name, debug_level, dlerror()); return; } // Initialize malloc debugging in the loaded module. malloc_debug_initialize = reinterpret_cast<MallocDebugInit>(dlsym(libc_malloc_impl_handle, "malloc_debug_initialize")); if (malloc_debug_initialize == NULL) { error_log("%s: Initialization routine is not found in %s\n", __progname, so_name); dlclose(libc_malloc_impl_handle); return; } if (malloc_debug_initialize()) { dlclose(libc_malloc_impl_handle); return; } if (debug_level == 20) { // For memory checker we need to do extra initialization. typedef int (*MemCheckInit)(int, const char*); MemCheckInit memcheck_initialize = reinterpret_cast<MemCheckInit>(dlsym(libc_malloc_impl_handle, "memcheck_initialize")); if (memcheck_initialize == NULL) { error_log("%s: memcheck_initialize routine is not found in %s\n", __progname, so_name); dlclose(libc_malloc_impl_handle); return; } if (memcheck_initialize(MALLOC_ALIGNMENT, memcheck_tracing)) { dlclose(libc_malloc_impl_handle); return; } } /* BEGIN mtk-added: */ #if defined(HAVE_MALLOC_DEBUG_FEATURE) || defined(HAVE_MSPACE_DEBUG_FEATURE) if (debug_level == 15) { int sig = 0; int backtrace_method = -1, backtrace_size = -1; // For debug 15 we need to do extra initialization. Debug15ExtraInitialize debug15_extra_initialize = reinterpret_cast<Debug15ExtraInitialize>(dlsym(libc_malloc_impl_handle, "debug15_extra_initialize")); if (debug15_extra_initialize == NULL) { error_log("%s: malloc_debug_extra_initialize routine is not found in %s\n", __progname, so_name); dlclose(libc_malloc_impl_handle); return; } // NOTICE: // have to read property in this stage. // reading in debug15_extra_initialize does not work, while reson is unclear. if (__system_property_get("persist.debug15.sig", env)) { sig = atoi(env); } if (__system_property_get("persist.debug15.prog", env)) { if (strncmp("ALL", env, sizeof("ALL")) == 0 || strstr(__progname, env)) { error_log("gcc 20 bt for: %s\n", __progname); backtrace_method = 1; // gcc unwind backtrace_size = 20; // back trace depth: 20 } } if (debug15_extra_initialize(sig, backtrace_method, backtrace_size)) { dlclose(libc_malloc_impl_handle); return; } // to indicate that debug 15 is on. // NOTICE: This function does not exist on GB. if (__system_property_get("libc.debug15.status", env)) { if (strncmp("off", env, sizeof("off")) == 0) __system_property_set("libc.debug15.status", "on"); } else __system_property_set("libc.debug15.status", "on"); } #endif /* END mtk-added. */ // Initialize malloc dispatch table with appropriate routines. switch (debug_level) { case 1: InitMalloc(&gMallocUse, debug_level, "leak"); break; case 5: InitMalloc(&gMallocUse, debug_level, "fill"); break; case 10: InitMalloc(&gMallocUse, debug_level, "chk"); break; /* BEGIN mtk-added: */ #if defined(HAVE_MALLOC_DEBUG_FEATURE) case 15: InitMalloc(&gMallocUse, debug_level, "mtk"); break; #if defined(HAVE_MSPACE_DEBUG_FEATURE) case 16: if(mspace_stat_init() == 0) InitMalloc(&gMallocUse, debug_level, "mtk"); break; #endif //#if defined(HAVE_MSPACE_DEBUG_FEATURE) #endif // #if defined(HAVE_MALLOC_DEBUG_FEATURE) /* END mtk-added. */ case 20: InitMalloc(&gMallocUse, debug_level, "qemu_instrumented"); break; default: break; } // Make sure dispatch table is initialized if ((gMallocUse.malloc == NULL) || (gMallocUse.free == NULL) || (gMallocUse.calloc == NULL) || (gMallocUse.realloc == NULL) || (gMallocUse.memalign == NULL)) { error_log("%s: some symbols for libc.debug.malloc level %d were not found (see above)", __progname, debug_level); dlclose(libc_malloc_impl_handle); libc_malloc_impl_handle = NULL; } else { __libc_malloc_dispatch = &gMallocUse; } }