|  | /* | 
|  | * Copyright (C) 2009 The Android Open Source Project | 
|  | * All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions | 
|  | * are met: | 
|  | *  * Redistributions of source code must retain the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer. | 
|  | *  * Redistributions in binary form must reproduce the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer in | 
|  | *    the documentation and/or other materials provided with the | 
|  | *    distribution. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 
|  | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 
|  | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 
|  | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 
|  | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | 
|  | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 
|  | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
|  | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | 
|  | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
|  | * SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * Contains implementation of memory allocation routines instrumented for | 
|  | * usage in the emulator to detect memory allocation violations, such as | 
|  | * memory leaks, buffer overruns, etc. | 
|  | * Code, implemented here is intended to run in the emulated environment only, | 
|  | * and serves simply as hooks into memory allocation routines. Main job of this | 
|  | * code is to notify the emulator about memory being allocated/deallocated, | 
|  | * providing information about each allocation. The idea is that emulator will | 
|  | * keep list of currently allocated blocks, and, knowing boundaries of each | 
|  | * block it will be able to verify that ld/st access to these blocks don't step | 
|  | * over boundaries set for the user. To enforce that, each memory block | 
|  | * allocated by this code is guarded with "prefix" and "suffix" areas, so | 
|  | * every time emulator detects access to any of these guarding areas, it can be | 
|  | * considered as access violation. | 
|  | */ | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <stddef.h> | 
|  | #include <stdio.h> | 
|  | #include <fcntl.h> | 
|  | #include <sys/mman.h> | 
|  | #include <sys/param.h> | 
|  | #include <pthread.h> | 
|  | #include <unistd.h> | 
|  | #include <errno.h> | 
|  | #include "malloc_debug_common.h" | 
|  | #include "private/bionic_macros.h" | 
|  | #include "private/libc_logging.h" | 
|  |  | 
|  | /* This file should be included into the build only when | 
|  | * MALLOC_QEMU_INSTRUMENT macro is defined. */ | 
|  | #ifndef MALLOC_QEMU_INSTRUMENT | 
|  | #error MALLOC_QEMU_INSTRUMENT is not defined. | 
|  | #endif  // !MALLOC_QEMU_INSTRUMENT | 
|  |  | 
|  | /* Controls access violation test performed to make sure that we catch AVs | 
|  | * all the time they occur. See test_access_violation for more info. This macro | 
|  | * is used for internal testing purposes and should always be set to zero for | 
|  | * the production builds. */ | 
|  | #define TEST_ACCESS_VIOLATIONS  0 | 
|  |  | 
|  | // ============================================================================= | 
|  | // Communication structures | 
|  | // ============================================================================= | 
|  |  | 
|  | /* Describes memory block allocated from the heap. This structure is passed | 
|  | * along with TRACE_DEV_REG_MALLOC event. This descriptor is used to inform | 
|  | * the emulator about new memory block being allocated from the heap. The entire | 
|  | * structure is initialized by the guest system before event is fired up. It is | 
|  | * important to remember that same structure (an exact copy, except for | 
|  | * replacing pointers with target_ulong) is also declared in the emulator's | 
|  | * sources (file memcheck/memcheck_common.h). So, every time a change is made to | 
|  | * any of these two declaration, another one must be also updated accordingly. | 
|  | */ | 
|  | struct MallocDesc { | 
|  | /* Pointer to the memory block actually allocated from the heap. Note that | 
|  | * this is not the pointer that is returned to the malloc's caller. Pointer | 
|  | * returned to the caller is calculated by adding value stored in this field | 
|  | * to the value stored in prefix_size field of this structure. | 
|  | */ | 
|  | void*       ptr; | 
|  |  | 
|  | /* Number of bytes requested by the malloc's caller. */ | 
|  | uint32_t    requested_bytes; | 
|  |  | 
|  | /* Byte size of the prefix data. Actual pointer returned to the malloc's | 
|  | * caller is calculated by adding value stored in this field to the value | 
|  | * stored in in the ptr field of this structure. | 
|  | */ | 
|  | uint32_t    prefix_size; | 
|  |  | 
|  | /* Byte size of the suffix data. */ | 
|  | uint32_t    suffix_size; | 
|  |  | 
|  | /* Id of the process that initialized libc instance, in which allocation | 
|  | * has occurred. This field is used by the emulator to report errors in | 
|  | * the course of TRACE_DEV_REG_MALLOC event handling. In case of an error, | 
|  | * emulator sets this field to zero (invalid value for a process ID). | 
|  | */ | 
|  | uint32_t    libc_pid; | 
|  |  | 
|  | /* Id of the process in context of which allocation has occurred. | 
|  | * Value in this field may differ from libc_pid value, if process that | 
|  | * is doing allocation has been forked from the process that initialized | 
|  | * libc instance. | 
|  | */ | 
|  | uint32_t    allocator_pid; | 
|  |  | 
|  | /* Number of access violations detected on this allocation. */ | 
|  | uint32_t    av_count; | 
|  | }; | 
|  |  | 
|  | /* Describes memory block info queried from emulator. This structure is passed | 
|  | * along with TRACE_DEV_REG_QUERY_MALLOC event. When handling free and realloc | 
|  | * calls, it is required that we have information about memory blocks that were | 
|  | * actually allocated in previous calls to malloc, calloc, memalign, or realloc. | 
|  | * Since we don't keep this information directly in the allocated block, but | 
|  | * rather we keep it in the emulator, we need to query emulator for that | 
|  | * information with TRACE_DEV_REG_QUERY_MALLOC query. The entire structure is | 
|  | * initialized by the guest system before event is fired up. It is important to | 
|  | * remember that same structure (an exact copy, except for replacing pointers | 
|  | * with target_ulong) is also declared in the emulator's sources (file | 
|  | * memcheck/memecheck_common.h). So, every time a change is made to any of these | 
|  | * two declaration, another one must be also updated accordingly. | 
|  | */ | 
|  | struct MallocDescQuery { | 
|  | /* Pointer, for which information is queried. Note that this pointer doesn't | 
|  | * have to be exact pointer returned to malloc's caller, but can point | 
|  | * anywhere inside an allocated block, including guarding areas. Emulator | 
|  | * will respond with information about allocated block that contains this | 
|  | * pointer. | 
|  | */ | 
|  | const void*       ptr; | 
|  |  | 
|  | /* Id of the process that initialized libc instance, in which this query | 
|  | * is called. This field is used by the emulator to report errors in | 
|  | * the course of TRACE_DEV_REG_QUERY_MALLOC event handling. In case of an | 
|  | * error, emulator sets this field to zero (invalid value for a process ID). | 
|  | */ | 
|  | uint32_t    libc_pid; | 
|  |  | 
|  | /* Process ID in context of which query is made. */ | 
|  | uint32_t    query_pid; | 
|  |  | 
|  | /* Code of the allocation routine, in context of which query has been made: | 
|  | *  1 - free | 
|  | *  2 - realloc | 
|  | */ | 
|  | uint32_t    routine; | 
|  |  | 
|  | /* Address of memory allocation descriptor for the queried pointer. | 
|  | * Descriptor, addressed by this field is initialized by the emulator in | 
|  | * response to the query. | 
|  | */ | 
|  | MallocDesc*  desc; | 
|  | }; | 
|  |  | 
|  | /* Describes memory block that is being freed back to the heap. This structure | 
|  | * is passed along with TRACE_DEV_REG_FREE_PTR event. The entire structure is | 
|  | * initialized by the guest system before event is fired up. It is important to | 
|  | * remember that same structure (an exact copy, except for replacing pointers | 
|  | * with target_ulong) is also declared in the emulator's sources (file | 
|  | * memcheck/memecheck_common.h). So, every time a change is made to any of these | 
|  | * two declaration, another one must be also updated accordingly. | 
|  | */ | 
|  | struct MallocFree { | 
|  | /* Pointer to be freed. */ | 
|  | void*       ptr; | 
|  |  | 
|  | /* Id of the process that initialized libc instance, in which this free | 
|  | * is called. This field is used by the emulator to report errors in | 
|  | * the course of TRACE_DEV_REG_FREE_PTR event handling. In case of an | 
|  | * error, emulator sets this field to zero (invalid value for a process ID). | 
|  | */ | 
|  | uint32_t    libc_pid; | 
|  |  | 
|  | /* Process ID in context of which memory is being freed. */ | 
|  | uint32_t    free_pid; | 
|  | }; | 
|  |  | 
|  | // ============================================================================= | 
|  | // Communication events | 
|  | // ============================================================================= | 
|  |  | 
|  | /* Notifies the emulator that libc has been initialized for a process. | 
|  | * Event's value parameter is PID for the process in context of which libc has | 
|  | * been initialized. | 
|  | */ | 
|  | #define TRACE_DEV_REG_LIBC_INIT             1536 | 
|  |  | 
|  | /* Notifies the emulator about new memory block been allocated. | 
|  | * Event's value parameter points to MallocDesc instance that contains | 
|  | * allocated block information. Note that 'libc_pid' field of the descriptor | 
|  | * is used by emulator to report failure in handling this event. In case | 
|  | * of a failure emulator will zero that field before completing this event. | 
|  | */ | 
|  | #define TRACE_DEV_REG_MALLOC                1537 | 
|  |  | 
|  | /* Notifies the emulator about memory block being freed. | 
|  | * Event's value parameter points to MallocFree descriptor that contains | 
|  | * information about block that's being freed. Note that 'libc_pid' field | 
|  | * of the descriptor is used by emulator to report failure in handling this | 
|  | * event. In case of a failure emulator will zero that field before completing | 
|  | * this event. | 
|  | */ | 
|  | #define TRACE_DEV_REG_FREE_PTR              1538 | 
|  |  | 
|  | /* Queries the emulator about allocated memory block information. | 
|  | * Event's value parameter points to MallocDescQuery descriptor that contains | 
|  | * query parameters. Note that 'libc_pid' field of the descriptor is used by | 
|  | * emulator to report failure in handling this event. In case of a failure | 
|  | * emulator will zero that field before completing this event. | 
|  | */ | 
|  | #define TRACE_DEV_REG_QUERY_MALLOC          1539 | 
|  |  | 
|  | /* Queries the emulator to print a string to its stdout. | 
|  | * Event's value parameter points to a zero-terminated string to be printed. | 
|  | */ | 
|  | #define TRACE_DEV_REG_PRINT_USER_STR        1540 | 
|  |  | 
|  | static void notify_qemu_string(const char* str); | 
|  | static void qemu_log(int prio, const char* fmt, ...); | 
|  | static void dump_malloc_descriptor(char* str, | 
|  | size_t str_buf_size, | 
|  | const MallocDesc* desc); | 
|  |  | 
|  | // ============================================================================= | 
|  | // Macros | 
|  | // ============================================================================= | 
|  |  | 
|  | /* Defines default size of allocation prefix. | 
|  | * Note that we make prefix area quite large in order to increase chances of | 
|  | * catching buffer overflow. */ | 
|  | #define DEFAULT_PREFIX_SIZE     (malloc_alignment * 4) | 
|  |  | 
|  | /* Defines default size of allocation suffix. | 
|  | * Note that we make suffix area quite large in order to increase chances of | 
|  | * catching buffer overflow. */ | 
|  | #define DEFAULT_SUFFIX_SIZE     (malloc_alignment * 4) | 
|  |  | 
|  | /* Debug tracing has been enabled by the emulator. */ | 
|  | #define DEBUG_TRACING_ENABLED   0x00000001 | 
|  | /* Error tracing has been enabled by the emulator. */ | 
|  | #define ERROR_TRACING_ENABLED   0x00000002 | 
|  | /* Info tracing has been enabled by the emulator. */ | 
|  | #define INFO_TRACING_ENABLED    0x00000004 | 
|  | /* All tracing flags combined. */ | 
|  | #define ALL_TRACING_ENABLED (DEBUG_TRACING_ENABLED |    \ | 
|  | ERROR_TRACING_ENABLED |    \ | 
|  | INFO_TRACING_ENABLED) | 
|  |  | 
|  | /* Prints a string to the emulator's stdout. | 
|  | * In early stages of system loading, logging messages to logcat | 
|  | * is not available, because ADB API has not been | 
|  | * hooked up yet. So, in order to see such messages we need to print them to | 
|  | * the emulator's stdout. | 
|  | * Parameters passed to this macro are the same as parameters for printf | 
|  | * routine. | 
|  | */ | 
|  | #define TR(...)                                         \ | 
|  | do {                                                \ | 
|  | char tr_str[4096];                              \ | 
|  | snprintf(tr_str, sizeof(tr_str), __VA_ARGS__);  \ | 
|  | tr_str[sizeof(tr_str) - 1] = '\0';              \ | 
|  | notify_qemu_string(&tr_str[0]);                 \ | 
|  | } while (0) | 
|  |  | 
|  | // ============================================================================= | 
|  | // Logging macros. Note that we simultaneously log messages to ADB and emulator. | 
|  | // ============================================================================= | 
|  |  | 
|  | /* | 
|  | * Helper macros for checking if particular trace level is enabled. | 
|  | */ | 
|  | #define debug_LOG_ENABLED       ((tracing_flags & DEBUG_TRACING_ENABLED) != 0) | 
|  | #define error_LOG_ENABLED       ((tracing_flags & ERROR_TRACING_ENABLED) != 0) | 
|  | #define info_LOG_ENABLED        ((tracing_flags & INFO_TRACING_ENABLED)  != 0) | 
|  | #define tracing_enabled(type)   (type##_LOG_ENABLED) | 
|  |  | 
|  | /* | 
|  | * Logging helper macros. | 
|  | */ | 
|  | #define qemu_debug_log(format, ...)                                         \ | 
|  | do {                                                                    \ | 
|  | __libc_format_log(ANDROID_LOG_DEBUG, "memcheck", (format), ##__VA_ARGS__); \ | 
|  | if (tracing_flags & DEBUG_TRACING_ENABLED) {                        \ | 
|  | qemu_log(ANDROID_LOG_DEBUG, (format), ##__VA_ARGS__);           \ | 
|  | }                                                                   \ | 
|  | } while (0) | 
|  |  | 
|  | #define qemu_error_log(format, ...)                                         \ | 
|  | do {                                                                    \ | 
|  | __libc_format_log(ANDROID_LOG_ERROR, "memcheck", (format), ##__VA_ARGS__); \ | 
|  | if (tracing_flags & ERROR_TRACING_ENABLED) {                        \ | 
|  | qemu_log(ANDROID_LOG_ERROR, (format), ##__VA_ARGS__);           \ | 
|  | }                                                                   \ | 
|  | } while (0) | 
|  |  | 
|  | #define qemu_info_log(format, ...)                                          \ | 
|  | do {                                                                    \ | 
|  | __libc_format_log(ANDROID_LOG_INFO, "memcheck", (format), ##__VA_ARGS__); \ | 
|  | if (tracing_flags & INFO_TRACING_ENABLED) {                         \ | 
|  | qemu_log(ANDROID_LOG_INFO, (format), ##__VA_ARGS__);            \ | 
|  | }                                                                   \ | 
|  | } while (0) | 
|  |  | 
|  | /* Logs message dumping MallocDesc instance at the end of the message. | 
|  | * Param: | 
|  | *  type - Message type: debug, error, or info | 
|  | *  desc - MallocDesc instance to dump. | 
|  | *  fmt + rest - Formats message preceding dumped descriptor. | 
|  | */ | 
|  | #define log_mdesc(type, desc, fmt, ...)                                    \ | 
|  | do {                                                                    \ | 
|  | if (tracing_enabled(type)) {                                        \ | 
|  | char log_str[4096];                                             \ | 
|  | __libc_format_buffer(log_str, sizeof(log_str), fmt, ##__VA_ARGS__); \ | 
|  | log_str[sizeof(log_str) - 1] = '\0';                            \ | 
|  | size_t str_len = strlen(log_str);                               \ | 
|  | dump_malloc_descriptor(log_str + str_len,                       \ | 
|  | sizeof(log_str) - str_len,               \ | 
|  | (desc));                                 \ | 
|  | type##_log("%s", log_str);                                      \ | 
|  | }                                                                   \ | 
|  | } while (0) | 
|  |  | 
|  | // ============================================================================= | 
|  | // Static data | 
|  | // ============================================================================= | 
|  |  | 
|  | // The underlying malloc implementation to use to get memory. | 
|  | static const MallocDebug* g_malloc_dispatch = NULL; | 
|  |  | 
|  | /* Emulator's magic page address. | 
|  | * This page (mapped on /dev/qemu_trace device) is used to fire up events | 
|  | * in the emulator. */ | 
|  | static volatile void* qtrace = NULL; | 
|  |  | 
|  | /* Cached PID of the process in context of which this libc instance | 
|  | * has been initialized. */ | 
|  | static uint32_t malloc_pid = 0; | 
|  |  | 
|  | /* Memory allocation alignment that is used in the malloc implementation. | 
|  | * This variable is updated by memcheck_initialize routine. */ | 
|  | static uint32_t malloc_alignment = 8; | 
|  |  | 
|  | /* Tracing flags. These flags control which types of logging messages are | 
|  | * enabled by the emulator. See XXX_TRACING_ENABLED for the values of flags | 
|  | * stored in this variable. This variable is updated by memcheck_initialize | 
|  | * routine. */ | 
|  | static uint32_t tracing_flags = 0; | 
|  |  | 
|  | // ============================================================================= | 
|  | // Static routines | 
|  | // ============================================================================= | 
|  |  | 
|  | /* Gets pointer, returned to malloc caller for the given allocation decriptor. | 
|  | * Param: | 
|  | *  desc - Allocation descriptor. | 
|  | * Return: | 
|  | *  Pointer to the allocated memory returned to the malloc caller. | 
|  | */ | 
|  | static inline void* mallocdesc_user_ptr(const MallocDesc* desc) { | 
|  | return static_cast<char*>(desc->ptr) + desc->prefix_size; | 
|  | } | 
|  |  | 
|  | /* Gets size of memory block actually allocated from the heap for the given | 
|  | * allocation decriptor. | 
|  | * Param: | 
|  | *  desc - Allocation descriptor. | 
|  | * Return: | 
|  | *  Size of memory block actually allocated from the heap. | 
|  | */ | 
|  | static inline uint32_t mallocdesc_alloc_size(const MallocDesc* desc) { | 
|  | return desc->prefix_size + desc->requested_bytes + desc->suffix_size; | 
|  | } | 
|  |  | 
|  | /* Gets pointer to the end of the allocated block for the given descriptor. | 
|  | * Param: | 
|  | *  desc - Descriptor for the memory block, allocated in malloc handler. | 
|  | * Return: | 
|  | *  Pointer to the end of (one byte past) the allocated block. | 
|  | */ | 
|  | static inline void* mallocdesc_alloc_end(const MallocDesc* desc) { | 
|  | return static_cast<char*>(desc->ptr) + mallocdesc_alloc_size(desc); | 
|  | } | 
|  |  | 
|  | /* Fires up an event in the emulator. | 
|  | * Param: | 
|  | *  code - Event code (one of the TRACE_DEV_XXX). | 
|  | *  val  - Event's value parameter. | 
|  | */ | 
|  | static inline void notify_qemu(uint32_t code, uintptr_t val) { | 
|  | if (NULL != qtrace) { | 
|  | *(volatile uintptr_t*)((uintptr_t)qtrace + ((code - 1024) << 2)) = val; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Prints a zero-terminated string to the emulator's stdout (fires up | 
|  | * TRACE_DEV_REG_PRINT_USER_STR event in the emulator). | 
|  | * Param: | 
|  | *  str - Zero-terminated string to print. | 
|  | */ | 
|  | static void notify_qemu_string(const char* str) { | 
|  | if (str != NULL) { | 
|  | notify_qemu(TRACE_DEV_REG_PRINT_USER_STR, reinterpret_cast<uintptr_t>(str)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Fires up TRACE_DEV_REG_LIBC_INIT event in the emulator. | 
|  | * Param: | 
|  | *  pid - ID of the process that initialized libc. | 
|  | */ | 
|  | static void notify_qemu_libc_initialized(uint32_t pid) { | 
|  | notify_qemu(TRACE_DEV_REG_LIBC_INIT, pid); | 
|  | } | 
|  |  | 
|  | /* Fires up TRACE_DEV_REG_MALLOC event in the emulator. | 
|  | * Param: | 
|  | *  desc - Pointer to MallocDesc instance containing allocated block | 
|  | *      information. | 
|  | * Return: | 
|  | *  Zero on success, or -1 on failure. Note that on failure libc_pid field of | 
|  | *  the desc parameter passed to this routine has been zeroed out by the | 
|  | *  emulator. | 
|  | */ | 
|  | static inline int notify_qemu_malloc(volatile MallocDesc* desc) { | 
|  | desc->libc_pid = malloc_pid; | 
|  | desc->allocator_pid = getpid(); | 
|  | desc->av_count = 0; | 
|  | notify_qemu(TRACE_DEV_REG_MALLOC, reinterpret_cast<uintptr_t>(desc)); | 
|  |  | 
|  | /* Emulator reports failure by zeroing libc_pid field of the | 
|  | * descriptor. */ | 
|  | return desc->libc_pid != 0 ? 0 : -1; | 
|  | } | 
|  |  | 
|  | /* Fires up TRACE_DEV_REG_FREE_PTR event in the emulator. | 
|  | * Param: | 
|  | *  ptr - Pointer to the memory block that's being freed. | 
|  | * Return: | 
|  | *  Zero on success, or -1 on failure. | 
|  | */ | 
|  | static inline int notify_qemu_free(void* ptr_to_free) { | 
|  | volatile MallocFree free_desc; | 
|  |  | 
|  | free_desc.ptr = ptr_to_free; | 
|  | free_desc.libc_pid = malloc_pid; | 
|  | free_desc.free_pid = getpid(); | 
|  | notify_qemu(TRACE_DEV_REG_FREE_PTR, reinterpret_cast<uintptr_t>(&free_desc)); | 
|  |  | 
|  | /* Emulator reports failure by zeroing libc_pid field of the | 
|  | * descriptor. */ | 
|  | return free_desc.libc_pid != 0 ? 0 : -1; | 
|  | } | 
|  |  | 
|  | /* Fires up TRACE_DEV_REG_QUERY_MALLOC event in the emulator. | 
|  | * Param: | 
|  | *  ptr - Pointer to request allocation information for. | 
|  | *  desc - Pointer to MallocDesc instance that will receive allocation | 
|  | *      information. | 
|  | *  routine - Code of the allocation routine, in context of which query is made: | 
|  | *      1 - free | 
|  | *      2 - realloc | 
|  | * Return: | 
|  | *  Zero on success, or -1 on failure. | 
|  | */ | 
|  | static inline int query_qemu_malloc_info(const void* ptr, MallocDesc* desc, uint32_t routine) { | 
|  | volatile MallocDescQuery query; | 
|  |  | 
|  | query.ptr = ptr; | 
|  | query.libc_pid = malloc_pid; | 
|  | query.query_pid = getpid(); | 
|  | query.routine = routine; | 
|  | query.desc = desc; | 
|  | notify_qemu(TRACE_DEV_REG_QUERY_MALLOC, reinterpret_cast<uintptr_t>(&query)); | 
|  |  | 
|  | /* Emulator reports failure by zeroing libc_pid field of the | 
|  | * descriptor. */ | 
|  | return query.libc_pid != 0 ? 0 : -1; | 
|  | } | 
|  |  | 
|  | /* Logs a message to emulator's stdout. | 
|  | * Param: | 
|  | *  prio - Message priority (debug, info, or error) | 
|  | *  fmt + rest - Message format and parameters. | 
|  | */ | 
|  | static void qemu_log(int prio, const char* fmt, ...) { | 
|  | va_list ap; | 
|  | char buf[4096]; | 
|  | const char* prefix; | 
|  |  | 
|  | /* Choose message prefix depending on the priority value. */ | 
|  | switch (prio) { | 
|  | case ANDROID_LOG_ERROR: | 
|  | if (!tracing_enabled(error)) { | 
|  | return; | 
|  | } | 
|  | prefix = "E"; | 
|  | break; | 
|  | case ANDROID_LOG_INFO: | 
|  | if (!tracing_enabled(info)) { | 
|  | return; | 
|  | } | 
|  | prefix = "I"; | 
|  | break; | 
|  | case ANDROID_LOG_DEBUG: | 
|  | default: | 
|  | if (!tracing_enabled(debug)) { | 
|  | return; | 
|  | } | 
|  | prefix = "D"; | 
|  | break; | 
|  | } | 
|  |  | 
|  | va_start(ap, fmt); | 
|  | vsnprintf(buf, sizeof(buf), fmt, ap); | 
|  | va_end(ap); | 
|  | buf[sizeof(buf) - 1] = '\0'; | 
|  |  | 
|  | TR("%s/memcheck: %s\n", prefix, buf); | 
|  | } | 
|  |  | 
|  | /* Dumps content of memory allocation descriptor to a string. | 
|  | * Param: | 
|  | *  str - String to dump descriptor to. | 
|  | *  str_buf_size - Size of string's buffer. | 
|  | *  desc - Descriptor to dump. | 
|  | */ | 
|  | static void dump_malloc_descriptor(char* str, size_t str_buf_size, const MallocDesc* desc) { | 
|  | if (str_buf_size) { | 
|  | snprintf(str, str_buf_size, | 
|  | "MDesc: %p: %p <-> %p [%u + %u + %u] by pid=%03u in libc_pid=%03u", | 
|  | mallocdesc_user_ptr(desc), desc->ptr, | 
|  | mallocdesc_alloc_end(desc), desc->prefix_size, | 
|  | desc->requested_bytes, desc->suffix_size, desc->allocator_pid, | 
|  | desc->libc_pid); | 
|  | str[str_buf_size - 1] = '\0'; | 
|  | } | 
|  | } | 
|  |  | 
|  | #if TEST_ACCESS_VIOLATIONS | 
|  | /* Causes an access violation on allocation descriptor, and verifies that | 
|  | * violation has been detected by memory checker in the emulator. | 
|  | */ | 
|  | static void test_access_violation(const MallocDesc* desc) { | 
|  | MallocDesc desc_chk; | 
|  | char ch; | 
|  | volatile char* prefix = (volatile char*)desc->ptr; | 
|  | volatile char* suffix = (volatile char*)mallocdesc_user_ptr(desc) + | 
|  | desc->requested_bytes; | 
|  | /* We're causing AV by reading from the prefix and suffix areas of the | 
|  | * allocated block. This should produce two access violations, so when we | 
|  | * get allocation descriptor from QEMU, av_counter should be bigger than | 
|  | * av_counter of the original descriptor by 2. */ | 
|  | ch = *prefix; | 
|  | ch = *suffix; | 
|  | if (!query_qemu_malloc_info(mallocdesc_user_ptr(desc), &desc_chk, 2) && | 
|  | desc_chk.av_count != (desc->av_count + 2)) { | 
|  | log_mdesc(error, &desc_chk, | 
|  | "<libc_pid=%03u, pid=%03u>: malloc: Access violation test failed:\n" | 
|  | "Expected violations count %u is not equal to the actually reported %u", | 
|  | malloc_pid, getpid(), desc->av_count + 2, | 
|  | desc_chk.av_count); | 
|  | } | 
|  | } | 
|  | #endif  // TEST_ACCESS_VIOLATIONS | 
|  |  | 
|  | // ============================================================================= | 
|  | // API routines | 
|  | // ============================================================================= | 
|  |  | 
|  | extern "C" void* qemu_instrumented_calloc(size_t, size_t); | 
|  | extern "C" void  qemu_instrumented_free(void*); | 
|  | extern "C" struct mallinfo qemu_instrumented_mallinfo(); | 
|  | extern "C" void* qemu_instrumented_malloc(size_t); | 
|  | extern "C" size_t qemu_instrumented_malloc_usable_size(const void*); | 
|  | extern "C" void* qemu_instrumented_memalign(size_t, size_t); | 
|  | extern "C" int qemu_instrumented_posix_memalign(void**, size_t, size_t); | 
|  | extern "C" void* qemu_instrumented_pvalloc(size_t); | 
|  | extern "C" void* qemu_instrumented_realloc(void*, size_t); | 
|  | extern "C" void* qemu_instrumented_valloc(size_t); | 
|  |  | 
|  | /* Initializes malloc debugging instrumentation for the emulator. | 
|  | * This routine is called from malloc_init_impl routine implemented in | 
|  | * bionic/libc/bionic/malloc_debug_common.c when malloc debugging gets | 
|  | * initialized for a process. The way malloc debugging implementation is | 
|  | * done, it is guaranteed that this routine will be called just once per | 
|  | * process. | 
|  | * Return: | 
|  | *  0 on success, or -1 on failure. | 
|  | */ | 
|  | extern "C" bool malloc_debug_initialize(HashTable*, const MallocDebug* malloc_dispatch) { | 
|  | g_malloc_dispatch = malloc_dispatch; | 
|  |  | 
|  | /* We will be using emulator's magic page to report memory allocation | 
|  | * activities. In essence, what magic page does, it translates writes to | 
|  | * the memory mapped spaces into writes to an I/O port that emulator | 
|  | * "listens to" on the other end. Note that until we open and map that | 
|  | * device, logging to emulator's stdout will not be available. */ | 
|  | int fd = open("/dev/qemu_trace", O_CLOEXEC | O_RDWR); | 
|  | if (fd < 0) { | 
|  | error_log("Unable to open /dev/qemu_trace"); | 
|  | return false; | 
|  | } else { | 
|  | qtrace = mmap(NULL, PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | 
|  | close(fd); | 
|  |  | 
|  | if (qtrace == MAP_FAILED) { | 
|  | qtrace = NULL; | 
|  | error_log("Unable to mmap /dev/qemu_trace"); | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Cache pid of the process this library has been initialized for. */ | 
|  | malloc_pid = getpid(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* Completes malloc debugging instrumentation for the emulator. | 
|  | * Note that this routine is called after successful return from | 
|  | * malloc_debug_initialize, which means that connection to the emulator via | 
|  | * "magic page" has been established. | 
|  | * Param: | 
|  | *  alignment - Alignment requirement set for memiry allocations. | 
|  | *  memcheck_param - Emulator's -memcheck option parameters. This string | 
|  | *      contains abbreviation for guest events that are enabled for tracing. | 
|  | * Return: | 
|  | *  0 on success, or -1 on failure. | 
|  | */ | 
|  | extern "C" int memcheck_initialize(int alignment, const char* memcheck_param) { | 
|  | malloc_alignment = alignment; | 
|  |  | 
|  | /* Parse -memcheck parameter for the guest tracing flags. */ | 
|  | while (*memcheck_param != '\0') { | 
|  | switch (*memcheck_param) { | 
|  | case 'a': | 
|  | // Enable all messages from the guest. | 
|  | tracing_flags |= ALL_TRACING_ENABLED; | 
|  | break; | 
|  | case 'd': | 
|  | // Enable debug messages from the guest. | 
|  | tracing_flags |= DEBUG_TRACING_ENABLED; | 
|  | break; | 
|  | case 'e': | 
|  | // Enable error messages from the guest. | 
|  | tracing_flags |= ERROR_TRACING_ENABLED; | 
|  | break; | 
|  | case 'i': | 
|  | // Enable info messages from the guest. | 
|  | tracing_flags |= INFO_TRACING_ENABLED; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | if (tracing_flags == ALL_TRACING_ENABLED) { | 
|  | break; | 
|  | } | 
|  | memcheck_param++; | 
|  | } | 
|  |  | 
|  | notify_qemu_libc_initialized(malloc_pid); | 
|  |  | 
|  | qemu_debug_log("Instrumented for pid=%03u: malloc=%p, free=%p, calloc=%p, realloc=%p, memalign=%p", | 
|  | malloc_pid, qemu_instrumented_malloc, qemu_instrumented_free, | 
|  | qemu_instrumented_calloc, qemu_instrumented_realloc, | 
|  | qemu_instrumented_memalign); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* This routine serves as entry point for 'malloc'. | 
|  | * Primary responsibility of this routine is to allocate requested number of | 
|  | * bytes (plus prefix, and suffix guards), and report allocation to the | 
|  | * emulator. | 
|  | */ | 
|  | extern "C" void* qemu_instrumented_malloc(size_t bytes) { | 
|  | MallocDesc desc; | 
|  |  | 
|  | /* Initialize block descriptor and allocate memory. Note that malloc | 
|  | * returns a valid pointer on zero allocation. Lets mimic this behavior. */ | 
|  | desc.prefix_size = DEFAULT_PREFIX_SIZE; | 
|  | desc.requested_bytes = bytes; | 
|  | desc.suffix_size = DEFAULT_SUFFIX_SIZE; | 
|  | size_t size = mallocdesc_alloc_size(&desc); | 
|  | if (size < bytes) { // Overflow | 
|  | qemu_error_log("<libc_pid=%03u, pid=%03u> malloc: malloc(%zu) overflow caused failure.", | 
|  | malloc_pid, getpid(), bytes); | 
|  | errno = ENOMEM; | 
|  | return NULL; | 
|  | } | 
|  | desc.ptr = g_malloc_dispatch->malloc(size); | 
|  | if (desc.ptr == NULL) { | 
|  | qemu_error_log("<libc_pid=%03u, pid=%03u> malloc(%zu): malloc(%zu) failed.", | 
|  | malloc_pid, getpid(), bytes, size); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | // Fire up event in the emulator. | 
|  | if (notify_qemu_malloc(&desc)) { | 
|  | log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: malloc: notify_malloc failed for ", | 
|  | malloc_pid, getpid()); | 
|  | g_malloc_dispatch->free(desc.ptr); | 
|  | errno = ENOMEM; | 
|  | return NULL; | 
|  | } else { | 
|  | #if TEST_ACCESS_VIOLATIONS | 
|  | test_access_violation(&desc); | 
|  | #endif  // TEST_ACCESS_VIOLATIONS | 
|  | log_mdesc(info, &desc, "+++ <libc_pid=%03u, pid=%03u> malloc(%zu) -> ", | 
|  | malloc_pid, getpid(), bytes); | 
|  | return mallocdesc_user_ptr(&desc); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* This routine serves as entry point for 'malloc'. | 
|  | * Primary responsibility of this routine is to free requested memory, and | 
|  | * report free block to the emulator. | 
|  | */ | 
|  | extern "C" void qemu_instrumented_free(void* mem) { | 
|  | MallocDesc desc; | 
|  |  | 
|  | if (mem == NULL) { | 
|  | // Just let go NULL free | 
|  | g_malloc_dispatch->free(mem); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Query emulator for the freeing block information. | 
|  | if (query_qemu_malloc_info(mem, &desc, 1)) { | 
|  | error_log("<libc_pid=%03u, pid=%03u>: free(%p) query_info failed.", | 
|  | malloc_pid, getpid(), mem); | 
|  | return; | 
|  | } | 
|  |  | 
|  | #if TEST_ACCESS_VIOLATIONS | 
|  | test_access_violation(&desc); | 
|  | #endif  // TEST_ACCESS_VIOLATIONS | 
|  |  | 
|  | /* Make sure that pointer that's being freed matches what we expect | 
|  | * for this memory block. Note that this violation should be already | 
|  | * caught in the emulator. */ | 
|  | if (mem != mallocdesc_user_ptr(&desc)) { | 
|  | log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: free(%p) is invalid for ", | 
|  | malloc_pid, getpid(), mem); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Fire up event in the emulator and free block that was actually allocated. | 
|  | if (notify_qemu_free(mem)) { | 
|  | log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: free(%p) notify_free failed for ", | 
|  | malloc_pid, getpid(), mem); | 
|  | } else { | 
|  | log_mdesc(info, &desc, "--- <libc_pid=%03u, pid=%03u> free(%p) -> ", | 
|  | malloc_pid, getpid(), mem); | 
|  | g_malloc_dispatch->free(desc.ptr); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* This routine serves as entry point for 'calloc'. | 
|  | * This routine behaves similarly to qemu_instrumented_malloc. | 
|  | */ | 
|  | extern "C" void* qemu_instrumented_calloc(size_t n_elements, size_t elem_size) { | 
|  | if (n_elements == 0 || elem_size == 0) { | 
|  | // Just let go zero bytes allocation. | 
|  | qemu_info_log("::: <libc_pid=%03u, pid=%03u>: Zero calloc redir to malloc", | 
|  | malloc_pid, getpid()); | 
|  | return qemu_instrumented_malloc(0); | 
|  | } | 
|  |  | 
|  | // Fail on overflow - just to be safe even though this code runs only | 
|  | // within the debugging C library, not the production one. | 
|  | if (n_elements && SIZE_MAX / n_elements < elem_size) { | 
|  | qemu_error_log("<libc_pid=%03u, pid=%03u> calloc: calloc(%zu, %zu) overflow caused failure.", | 
|  | malloc_pid, getpid(), n_elements, elem_size); | 
|  | errno = ENOMEM; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | MallocDesc desc; | 
|  |  | 
|  | /* Calculating prefix size. The trick here is to make sure that | 
|  | * first element (returned to the caller) is properly aligned. */ | 
|  | if (DEFAULT_PREFIX_SIZE >= elem_size) { | 
|  | /* If default alignment is bigger than element size, we will | 
|  | * set our prefix size to the default alignment size. */ | 
|  | desc.prefix_size = DEFAULT_PREFIX_SIZE; | 
|  | /* For the suffix we will use whatever bytes remain from the prefix | 
|  | * allocation size, aligned to the size of an element, plus the usual | 
|  | * default suffix size. */ | 
|  | desc.suffix_size = (DEFAULT_PREFIX_SIZE % elem_size) + | 
|  | DEFAULT_SUFFIX_SIZE; | 
|  | } else { | 
|  | /* Make sure that prefix, and suffix sizes is at least elem_size, | 
|  | * and first element returned to the caller is properly aligned. */ | 
|  | desc.prefix_size = elem_size + DEFAULT_PREFIX_SIZE - 1; | 
|  | desc.prefix_size &= ~(malloc_alignment - 1); | 
|  | desc.suffix_size = DEFAULT_SUFFIX_SIZE; | 
|  | } | 
|  | desc.requested_bytes = n_elements * elem_size; | 
|  | size_t total_size = desc.requested_bytes + desc.prefix_size + desc.suffix_size; | 
|  | if (total_size < desc.requested_bytes) { // Overflow | 
|  | qemu_error_log("<libc_pid=%03u, pid=%03u> calloc: calloc(%zu, %zu) overflow caused failure.", | 
|  | malloc_pid, getpid(), n_elements, elem_size); | 
|  | errno = ENOMEM; | 
|  | return NULL; | 
|  | } | 
|  | size_t total_elements = total_size / elem_size; | 
|  | total_size %= elem_size; | 
|  | if (total_size != 0) { | 
|  | // Add extra to the suffix area. | 
|  | total_elements++; | 
|  | desc.suffix_size += (elem_size - total_size); | 
|  | } | 
|  | desc.ptr = g_malloc_dispatch->calloc(total_elements, elem_size); | 
|  | if (desc.ptr == NULL) { | 
|  | error_log("<libc_pid=%03u, pid=%03u> calloc: calloc(%zu(%zu), %zu) (prx=%u, sfx=%u) failed.", | 
|  | malloc_pid, getpid(), n_elements, total_elements, elem_size, | 
|  | desc.prefix_size, desc.suffix_size); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (notify_qemu_malloc(&desc)) { | 
|  | log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: calloc(%zu(%zu), %zu): notify_malloc failed for ", | 
|  | malloc_pid, getpid(), n_elements, total_elements, elem_size); | 
|  | g_malloc_dispatch->free(desc.ptr); | 
|  | errno = ENOMEM; | 
|  | return NULL; | 
|  | } else { | 
|  | #if TEST_ACCESS_VIOLATIONS | 
|  | test_access_violation(&desc); | 
|  | #endif  // TEST_ACCESS_VIOLATIONS | 
|  | log_mdesc(info, &desc, "### <libc_pid=%03u, pid=%03u> calloc(%zu(%zu), %zu) -> ", | 
|  | malloc_pid, getpid(), n_elements, total_elements, elem_size); | 
|  | return mallocdesc_user_ptr(&desc); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* This routine serves as entry point for 'realloc'. | 
|  | * This routine behaves similarly to qemu_instrumented_free + | 
|  | * qemu_instrumented_malloc. Note that this modifies behavior of "shrinking" an | 
|  | * allocation, but overall it doesn't seem to matter, as caller of realloc | 
|  | * should not expect that pointer returned after shrinking will remain the same. | 
|  | */ | 
|  | extern "C" void* qemu_instrumented_realloc(void* mem, size_t bytes) { | 
|  | if (mem == NULL) { | 
|  | // Nothing to realloc. just do regular malloc. | 
|  | qemu_info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %zu) redir to malloc", | 
|  | malloc_pid, getpid(), mem, bytes); | 
|  | return qemu_instrumented_malloc(bytes); | 
|  | } | 
|  |  | 
|  | if (bytes == 0) { | 
|  | // This is a "free" condition. | 
|  | qemu_info_log("::: <libc_pid=%03u, pid=%03u>: realloc(%p, %zu) redir to free and malloc", | 
|  | malloc_pid, getpid(), mem, bytes); | 
|  | qemu_instrumented_free(mem); | 
|  |  | 
|  | // This is what realloc does for a "free" realloc. | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | // Query emulator for the reallocating block information. | 
|  | MallocDesc cur_desc; | 
|  | if (query_qemu_malloc_info(mem, &cur_desc, 2)) { | 
|  | // Note that this violation should be already caught in the emulator. | 
|  | error_log("<libc_pid=%03u, pid=%03u>: realloc(%p, %zu) query_info failed.", | 
|  | malloc_pid, getpid(), mem, bytes); | 
|  | errno = ENOMEM; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | #if TEST_ACCESS_VIOLATIONS | 
|  | test_access_violation(&cur_desc); | 
|  | #endif  // TEST_ACCESS_VIOLATIONS | 
|  |  | 
|  | /* Make sure that reallocating pointer value is what we would expect | 
|  | * for this memory block. Note that this violation should be already caught | 
|  | * in the emulator.*/ | 
|  | if (mem != mallocdesc_user_ptr(&cur_desc)) { | 
|  | log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zu) is invalid for ", | 
|  | malloc_pid, getpid(), mem, bytes); | 
|  | errno = ENOMEM; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* TODO: We're a bit inefficient here, always allocating new block from | 
|  | * the heap. If this realloc shrinks current buffer, we can just do the | 
|  | * shrinking "in place", adjusting suffix_size in the allocation descriptor | 
|  | * for this block that is stored in the emulator. */ | 
|  |  | 
|  | // Initialize descriptor for the new block. | 
|  | MallocDesc new_desc; | 
|  | new_desc.prefix_size = DEFAULT_PREFIX_SIZE; | 
|  | new_desc.requested_bytes = bytes; | 
|  | new_desc.suffix_size = DEFAULT_SUFFIX_SIZE; | 
|  | size_t new_size = mallocdesc_alloc_size(&new_desc); | 
|  | if (new_size < bytes) { // Overflow | 
|  | qemu_error_log("<libc_pid=%03u, pid=%03u>: realloc(%p, %zu): malloc(%zu) failed due to overflow", | 
|  | malloc_pid, getpid(), mem, bytes, new_size); | 
|  | errno = ENOMEM; | 
|  | return NULL; | 
|  | } | 
|  | new_desc.ptr = g_malloc_dispatch->malloc(new_size); | 
|  | if (new_desc.ptr == NULL) { | 
|  | log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zu): malloc(%zu) failed on ", | 
|  | malloc_pid, getpid(), mem, bytes, new_size); | 
|  | return NULL; | 
|  | } | 
|  | void* new_mem = mallocdesc_user_ptr(&new_desc); | 
|  |  | 
|  | // Copy user data from old block to the new one. | 
|  | size_t to_copy = bytes < cur_desc.requested_bytes ? bytes : cur_desc.requested_bytes; | 
|  | if (to_copy != 0) { | 
|  | memcpy(new_mem, mallocdesc_user_ptr(&cur_desc), to_copy); | 
|  | } | 
|  |  | 
|  | // Register new block with emulator. | 
|  | if (notify_qemu_malloc(&new_desc)) { | 
|  | log_mdesc(error, &new_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zu) notify_malloc failed -> ", | 
|  | malloc_pid, getpid(), mem, bytes); | 
|  | log_mdesc(error, &cur_desc, "                                                                <- "); | 
|  | g_malloc_dispatch->free(new_desc.ptr); | 
|  | errno = ENOMEM; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | #if TEST_ACCESS_VIOLATIONS | 
|  | test_access_violation(&new_desc); | 
|  | #endif  // TEST_ACCESS_VIOLATIONS | 
|  |  | 
|  | // Free old block. | 
|  | if (notify_qemu_free(mem)) { | 
|  | log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zu): notify_free failed for ", | 
|  | malloc_pid, getpid(), mem, bytes); | 
|  | /* Since we registered new decriptor with the emulator, we need | 
|  | * to unregister it before freeing newly allocated block. */ | 
|  | notify_qemu_free(mallocdesc_user_ptr(&new_desc)); | 
|  | g_malloc_dispatch->free(new_desc.ptr); | 
|  | errno = ENOMEM; | 
|  | return NULL; | 
|  | } | 
|  | g_malloc_dispatch->free(cur_desc.ptr); | 
|  |  | 
|  | log_mdesc(info, &new_desc, "=== <libc_pid=%03u, pid=%03u>: realloc(%p, %zu) -> ", | 
|  | malloc_pid, getpid(), mem, bytes); | 
|  | log_mdesc(info, &cur_desc, "                                               <- "); | 
|  |  | 
|  | return new_mem; | 
|  | } | 
|  |  | 
|  | /* This routine serves as entry point for 'memalign'. | 
|  | * This routine behaves similarly to qemu_instrumented_malloc. | 
|  | */ | 
|  | extern "C" void* qemu_instrumented_memalign(size_t alignment, size_t bytes) { | 
|  | MallocDesc desc; | 
|  |  | 
|  | if (bytes == 0) { | 
|  | // Just let go zero bytes allocation. | 
|  | qemu_info_log("::: <libc_pid=%03u, pid=%03u>: memalign(%zx, %zu) redir to malloc", | 
|  | malloc_pid, getpid(), alignment, bytes); | 
|  | return qemu_instrumented_malloc(0); | 
|  | } | 
|  |  | 
|  | // Prefix size for aligned allocation must be equal to the alignment used | 
|  | // for allocation in order to ensure proper alignment of the returned | 
|  | // pointer. in case that alignment requirement is greater than prefix | 
|  | // size. | 
|  | if (alignment < DEFAULT_PREFIX_SIZE) { | 
|  | alignment = DEFAULT_PREFIX_SIZE; | 
|  | } else if (!powerof2(alignment)) { | 
|  | alignment = BIONIC_ROUND_UP_POWER_OF_2(alignment); | 
|  | } | 
|  | desc.prefix_size = alignment; | 
|  | desc.requested_bytes = bytes; | 
|  | desc.suffix_size = DEFAULT_SUFFIX_SIZE; | 
|  | size_t size = mallocdesc_alloc_size(&desc); | 
|  | if (size < bytes) { // Overflow | 
|  | qemu_error_log("<libc_pid=%03u, pid=%03u> memalign(%zx, %zu): malloc(%zu) failed due to overflow.", | 
|  | malloc_pid, getpid(), alignment, bytes, size); | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  | desc.ptr = g_malloc_dispatch->memalign(desc.prefix_size, size); | 
|  | if (desc.ptr == NULL) { | 
|  | error_log("<libc_pid=%03u, pid=%03u> memalign(%zx, %zu): malloc(%zu) failed.", | 
|  | malloc_pid, getpid(), alignment, bytes, size); | 
|  | return NULL; | 
|  | } | 
|  | if (notify_qemu_malloc(&desc)) { | 
|  | log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: memalign(%zx, %zu): notify_malloc failed for ", | 
|  | malloc_pid, getpid(), alignment, bytes); | 
|  | g_malloc_dispatch->free(desc.ptr); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | #if TEST_ACCESS_VIOLATIONS | 
|  | test_access_violation(&desc); | 
|  | #endif  // TEST_ACCESS_VIOLATIONS | 
|  |  | 
|  | log_mdesc(info, &desc, "@@@ <libc_pid=%03u, pid=%03u> memalign(%zx, %zu) -> ", | 
|  | malloc_pid, getpid(), alignment, bytes); | 
|  | return mallocdesc_user_ptr(&desc); | 
|  | } | 
|  |  | 
|  | extern "C" size_t qemu_instrumented_malloc_usable_size(const void* mem) { | 
|  | MallocDesc cur_desc; | 
|  |  | 
|  | // Query emulator for the reallocating block information. | 
|  | if (query_qemu_malloc_info(mem, &cur_desc, 2)) { | 
|  | // Note that this violation should be already caught in the emulator. | 
|  | error_log("<libc_pid=%03u, pid=%03u>: malloc_usable_size(%p) query_info failed.", | 
|  | malloc_pid, getpid(), mem); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Make sure that reallocating pointer value is what we would expect | 
|  | * for this memory block. Note that this violation should be already caught | 
|  | * in the emulator.*/ | 
|  | if (mem != mallocdesc_user_ptr(&cur_desc)) { | 
|  | log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: malloc_usable_size(%p) is invalid for ", | 
|  | malloc_pid, getpid(), mem); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* during instrumentation, we can't really report anything more than requested_bytes */ | 
|  | return cur_desc.requested_bytes; | 
|  | } | 
|  |  | 
|  | extern "C" struct mallinfo qemu_instrumented_mallinfo() { | 
|  | return g_malloc_dispatch->mallinfo(); | 
|  | } | 
|  |  | 
|  | extern "C" int qemu_instrumented_posix_memalign(void** memptr, size_t alignment, size_t size) { | 
|  | if ((alignment & (alignment - 1)) != 0) { | 
|  | qemu_error_log("<libc_pid=%03u, pid=%03u> posix_memalign(%p, %zu, %zu): invalid alignment.", | 
|  | malloc_pid, getpid(), memptr, alignment, size); | 
|  | return EINVAL; | 
|  | } | 
|  | int saved_errno = errno; | 
|  | *memptr = qemu_instrumented_memalign(alignment, size); | 
|  | errno = saved_errno; | 
|  | return (*memptr != NULL) ? 0 : ENOMEM; | 
|  | } | 
|  |  | 
|  | extern "C" void* qemu_instrumented_pvalloc(size_t bytes) { | 
|  | size_t pagesize = getpagesize(); | 
|  | size_t size = BIONIC_ALIGN(bytes, pagesize); | 
|  | if (size < bytes) { // Overflow | 
|  | qemu_error_log("<libc_pid=%03u, pid=%03u> pvalloc(%zu): overflow (%zu).", | 
|  | malloc_pid, getpid(), bytes, size); | 
|  | return NULL; | 
|  | } | 
|  | return qemu_instrumented_memalign(pagesize, size); | 
|  | } | 
|  |  | 
|  | extern "C" void* qemu_instrumented_valloc(size_t size) { | 
|  | return qemu_instrumented_memalign(getpagesize(), size); | 
|  | } |