Home | History | Annotate | Download | only in memcheck
      1 /* Copyright (C) 2007-2010 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 
     13 /*
     14  * Contains declarations of structures, routines, etc. that are commonly used
     15  * in memechecker framework.
     16  */
     17 
     18 #ifndef QEMU_MEMCHECK_MEMCHECK_COMMON_H
     19 #define QEMU_MEMCHECK_MEMCHECK_COMMON_H
     20 
     21 #include "qemu-common.h"
     22 #include "cpu.h"
     23 
     24 #ifdef __cplusplus
     25 extern "C" {
     26 #endif
     27 
     28 // =============================================================================
     29 // Events generated by the guest system.
     30 // =============================================================================
     31 
     32 /* Notifies the emulator that libc has been initialized for a process.
     33  * Event's value parameter is PID for the process in context of which libc has
     34  * been initialized.
     35  */
     36 #define TRACE_DEV_REG_LIBC_INIT             1536
     37 
     38 /* Notifies the emulator about new memory block being allocated.
     39  * Event's value parameter points to MallocDesc instance in the guest's address
     40  * space that contains allocated block information. Note that 'libc_pid' field
     41  * of the descriptor is used by emulator to report failure in handling this
     42  * event. In case of failure emulator will zero that filed before completing
     43  * this event.
     44  */
     45 #define TRACE_DEV_REG_MALLOC                1537
     46 
     47 /* Notifies the emulator about memory block being freed.
     48  * Event's value parameter points to MallocFree descriptor instance in the
     49  * guest's address space that contains information about block that's being
     50  * freed. Note that 'libc_pid' field of the descriptor is used by emulator to
     51  * report failure in handling this event. In case of failure emulator will zero
     52  * that filed before completing this event.
     53  */
     54 #define TRACE_DEV_REG_FREE_PTR              1538
     55 
     56 /* Queries the emulator about memory block information.
     57  * Event's value parameter points to MallocDescQuery descriptor instance in the
     58  * guest's address space that contains query parameters. Note that 'libc_pid'
     59  * field of the descriptor is used by emulator to report failure in handling
     60  * this event. In case of failure emulator will zero that filed before
     61  * completing this event.
     62  */
     63 #define TRACE_DEV_REG_QUERY_MALLOC          1539
     64 
     65 /* Queries the emulator to print a string to its stdout.
     66  * Event's value parameter points to zero-terminated string to be printed. Note
     67  * that this string is located in the guest's address space.
     68  */
     69 #define TRACE_DEV_REG_PRINT_USER_STR        1540
     70 
     71 // =============================================================================
     72 // Communication structures
     73 // =============================================================================
     74 
     75 /* Describes memory block allocated from the heap. This structure is passed
     76  * along with TRACE_DEV_REG_MALLOC event. This descriptor is used to inform
     77  * the emulator about new memory block being allocated from the heap. The entire
     78  * structure is initialized by the guest system before event is fired up. It is
     79  * important to remember that same structure (an exact copy) is also declared
     80  * in the libc's sources. So, every time a change is made to any of these
     81  * two declaration, another one must be also updated accordingly. */
     82 typedef struct MallocDesc {
     83     /* Poniter to the memory block actually allocated from the heap. Note that
     84      * this is not the pointer that is returned to the malloc's caller. Pointer
     85      * returned to the caller is calculated by adding value stored in this field
     86      * to the value stored in prefix_size field of this structure.
     87      */
     88     target_ulong    ptr;
     89 
     90     /* Nuber of bytes requested by the malloc's caller. */
     91     uint32_t        requested_bytes;
     92 
     93     /* Byte size of the prefix data. Actual pointer returned to the malloc's
     94      * caller is calculated by adding value stored in this field to the value
     95      * stored in in the ptr field of this structure.
     96      */
     97     uint32_t        prefix_size;
     98 
     99     /* Byte size of the suffix data. */
    100     uint32_t        suffix_size;
    101 
    102     /* Id of the process that initialized libc instance, in which allocation
    103      * has occurred. This field is used by the emulator to report errors in
    104      * the course of TRACE_DEV_REG_MALLOC event handling. In case of an error,
    105      * emulator sets this field to zero (invalid value for a process ID).
    106      */
    107     uint32_t        libc_pid;
    108 
    109     /* Id of the process in context of which allocation has occurred.
    110      * Value in this field may differ from libc_pid value, if process that
    111      * is doing allocation has been forked from the process that initialized
    112      * libc instance.
    113      */
    114     uint32_t        allocator_pid;
    115 
    116     /* Number of access violations detected on this allocation. */
    117     uint32_t        av_count;
    118 } MallocDesc;
    119 /* Helpers for addressing field in MallocDesc structure, using which emulator
    120  * reports an error back to the guest.
    121  */
    122 #define ALLOC_RES_OFFSET        ((uint32_t)(ptrdiff_t)&(((MallocDesc*)0)->libc_pid))
    123 #define ALLOC_RES_ADDRESS(p)    (p + ALLOC_RES_OFFSET)
    124 
    125 /* Describes memory block info queried from emulator. This structure is passed
    126  * along with TRACE_DEV_REG_QUERY_MALLOC event. When handling free and realloc
    127  * calls, it is required that we have information about memory blocks that were
    128  * actually allocated in previous calls to malloc, memalign, or realloc. Since
    129  * we don't keep this information directlry in the allocated block, but rather
    130  * we keep it in the emulator, we need to query emulator for that information
    131  * with TRACE_DEV_REG_QUERY_MALLOC query. The entire structure is initialized
    132  * by the guest system before event is fired up It is important to remember that
    133  * same structure (an exact copy) is also declared in the libc's sources. So,
    134  * every time a change is made to any of these two declaration, another one
    135  * must be also updated accordingly.
    136  */
    137 typedef struct MallocDescQuery {
    138     /* Pointer for which information is queried. Note that this pointer doesn't
    139      * have to be exact pointer returned to malloc's caller, but can point
    140      * anywhere inside an allocated block, including guarding areas. Emulator
    141      * will respond with information about allocated block that contains this
    142      * pointer.
    143      */
    144     target_ulong    ptr;
    145 
    146     /* Id of the process that initialized libc instance, in which this query
    147      * is called. This field is used by the emulator to report errors in
    148      * the course of TRACE_DEV_REG_QUERY_MALLOC event handling. In case of an
    149      * error, emulator sets this field to zero (invalid value for a process ID).
    150      */
    151     uint32_t        libc_pid;
    152 
    153     /* Process ID in context of which query is made. */
    154     uint32_t        query_pid;
    155 
    156     /* Code of the allocation routine, in context of which query has been made:
    157      *  1 - free
    158      *  2 - realloc
    159      */
    160     uint32_t        routine;
    161 
    162     /* Address in guest's virtual space of memory allocation descriptor for the
    163      * queried pointer. Descriptor, addressed by this field is initialized by
    164      * the emulator in response to the query.
    165      */
    166     target_ulong    desc;
    167 } MallocDescQuery;
    168 /* Helpers for addressing field in MallocDescQuery structure using which
    169  * emulator reports an error back to the guest.
    170  */
    171 #define QUERY_RES_OFFSET        ((uint32_t)(ptrdiff_t)&(((MallocDescQuery*)0)->libc_pid))
    172 #define QUERY_RES_ADDRESS(p)    (p + QUERY_RES_OFFSET)
    173 
    174 /* Describes memory block that is being freed back to the heap. This structure
    175  * is passed along with TRACE_DEV_REG_FREE_PTR event. The entire structure is
    176  * initialized by the guest system before event is fired up. It is important to
    177  * remember that same structure (an exact copy) is also declared in the libc's
    178  * sources. So, every time a change is made to any of these two declaration,
    179  * another one must be also updated accordingly.
    180  */
    181 typedef struct MallocFree {
    182     /* Pointer to be freed. */
    183     uint32_t    ptr;
    184 
    185     /* Id of the process that initialized libc instance, in which this free
    186      * is called. This field is used by the emulator to report errors in
    187      * the course of TRACE_DEV_REG_FREE_PTR event handling. In case of an
    188      * error, emulator sets this field to zero (invalid value for a process ID).
    189      */
    190     uint32_t    libc_pid;
    191 
    192     /* Process ID in context of which memory is being freed. */
    193     uint32_t    free_pid;
    194 } MallocFree;
    195 /* Helpers for addressing field in MallocFree structure, using which emulator
    196  * reports an error back to the guest.
    197  */
    198 #define FREE_RES_OFFSET         ((uint32_t)(ptrdiff_t)&(((MallocFree*)0)->libc_pid))
    199 #define FREE_RES_ADDRESS(p)     (p + FREE_RES_OFFSET)
    200 
    201 /* Extends MallocDesc structure with additional information, used by memchecker.
    202  */
    203 typedef struct MallocDescEx {
    204     /* Allocation descriptor this structure extends. */
    205     MallocDesc      malloc_desc;
    206 
    207     /* Call stack that lead to memory allocation. The array is arranged in
    208      * accending order, where entry at index 0 corresponds to the routine
    209      * that allocated memory. */
    210     target_ulong*   call_stack;
    211 
    212     /* Number of entries in call_stack array. */
    213     uint32_t        call_stack_count;
    214 
    215     /* Set of misc. flags. See MDESC_FLAG_XXX bellow. */
    216     uint32_t        flags;
    217 } MallocDescEx;
    218 
    219 /* Indicates that memory has been allocated before process started execution.
    220  * After a process has been forked, but before it actually starts executing,
    221  * allocations can be made in context of that process PID. This flag marks such
    222  * allocations in the process' allocation descriptors map.
    223  */
    224 #define MDESC_FLAG_TRANSITION_ENTRY         0x00000001
    225 
    226 /* Indicates that memory block has been inherited from the parent process.
    227  * When a process is forked from its parent process, the forked process inherits
    228  * a copy of the parent process' heap. Thus, all allocations that were recorded
    229  * for the parent process must be also recorded for the forked process. This
    230  * flag marks entries in the forked process' allocation descriptors map that
    231  * were copied over from the parent process' allocation descriptors map.
    232  */
    233 #define MDESC_FLAG_INHERITED_ON_FORK        0x00000002
    234 
    235 /* Describes a memory mapping of an execution module in the guest system. */
    236 typedef struct MMRangeDesc {
    237     /* Starting address of mmapping of a module in the guest's address space. */
    238     target_ulong            map_start;
    239 
    240     /* Ending address of mmapping of a module in the guest's address space. */
    241     target_ulong            map_end;
    242 
    243     /* Mmapping's execution offset. */
    244     target_ulong            exec_offset;
    245 
    246     /* Image path of the module that has been mapped with this mmapping. */
    247     char*                   path;
    248 } MMRangeDesc;
    249 
    250 /* Enumerates returned values for insert routines implemeted for red-black
    251  * tree maps.
    252  */
    253 typedef enum {
    254     /* New entry has been inserted into the map. */
    255     RBT_MAP_RESULT_ENTRY_INSERTED = 0,
    256 
    257     /* An entry, matching the new one already exists in the map. */
    258     RBT_MAP_RESULT_ENTRY_ALREADY_EXISTS,
    259 
    260     /* An existing entry, matching the new one has been replaced
    261     * with the new entry.
    262     */
    263     RBT_MAP_RESULT_ENTRY_REPLACED,
    264 
    265     /* An error has occurred when inserting entry into the map. */
    266     RBT_MAP_RESULT_ERROR = -1,
    267 } RBTMapResult;
    268 
    269 /* Encapsulates an array of guest addresses, sorted in accending order. */
    270 typedef struct AddrArray {
    271     /* Array of addresses. */
    272     target_ulong*   addr;
    273 
    274     /* Number of elements in the array. */
    275     int             num;
    276 } AddrArray;
    277 
    278 // =============================================================================
    279 // Inlines
    280 // =============================================================================
    281 
    282 /* Gets pointer returned to malloc caller for the given allocation decriptor.
    283  * Param:
    284  *  desc - Allocation descriptor.
    285  * Return:
    286  *  Pointer to the allocated memory returned to the malloc caller.
    287  */
    288 static inline target_ulong
    289 mallocdesc_get_user_ptr(const MallocDesc* desc)
    290 {
    291     return desc->ptr + desc->prefix_size;
    292 }
    293 
    294 /* Gets total size of the allocated block for the given descriptor.
    295  * Param:
    296  *  desc - Descriptor for the memory block, allocated in malloc handler.
    297  * Return:
    298  *  Total size of memory block allocated in malloc handler.
    299  */
    300 static inline uint32_t
    301 mallocdesc_get_alloc_size(const MallocDesc* desc)
    302 {
    303     return desc->prefix_size + desc->requested_bytes + desc->suffix_size;
    304 }
    305 
    306 /* Gets the end of the allocated block for the given descriptor.
    307  * Param:
    308  *  desc - Descriptor for the memory block, allocated in malloc handler.
    309  * Return:
    310  *  Pointer to the end of the allocated block (next byte past the block).
    311  */
    312 static inline target_ulong
    313 mallocdesc_get_alloc_end(const MallocDesc* desc)
    314 {
    315     return desc->ptr + mallocdesc_get_alloc_size(desc);
    316 }
    317 
    318 /* Gets the end of the allocated block available to the user for the given
    319  * descriptor.
    320  * Param:
    321  *  desc - Descriptor for the memory block, allocated in malloc handler.
    322  * Return:
    323  *  Pointer to the end of the allocated block available to the user (next byte
    324  *  past the block - suffix guarding area).
    325  */
    326 static inline target_ulong
    327 mallocdesc_get_user_alloc_end(const MallocDesc* desc)
    328 {
    329     return mallocdesc_get_user_ptr(desc) + desc->requested_bytes;
    330 }
    331 
    332 /* Checks if allocation has been made before process started execution.
    333  * Param:
    334  *  desc - Allocation descriptor to check.
    335  * Return:
    336  *  boolean: 1 if allocation has been made before process started execution,
    337  *  or 0 if allocation has been made after process started execution.
    338  */
    339 static inline int
    340 mallocdescex_is_transition_entry(const MallocDescEx* desc)
    341 {
    342     return (desc->flags & MDESC_FLAG_TRANSITION_ENTRY) != 0;
    343 }
    344 
    345 /* Checks if allocation block has been inherited on fork.
    346  * Param:
    347  *  desc - Allocation descriptor to check.
    348  * Return:
    349  *  boolean: 1 if allocation has been inherited on fork, or 0 if allocation
    350  *  has been made by this process..
    351  */
    352 static inline int
    353 mallocdescex_is_inherited_on_fork(const MallocDescEx* desc)
    354 {
    355     return (desc->flags & MDESC_FLAG_INHERITED_ON_FORK) != 0;
    356 }
    357 
    358 /* Gets offset for the given address inside a mapped module.
    359  * Param:
    360  *  address - Address to get offset for.
    361  * Return:
    362  *  Offset of the given address inside a mapped module, represented with the
    363  *  given mmaping range descriptor.
    364  */
    365 static inline target_ulong
    366 mmrangedesc_get_module_offset(const MMRangeDesc* rdesc, target_ulong address)
    367 {
    368     return address - rdesc->map_start + rdesc->exec_offset;
    369 }
    370 
    371 /* Checks if given address is contained in the given address array.
    372  * Return:
    373  *  boolean: 1 if address is contained in the array, or zero if it's not.
    374  */
    375 static inline int
    376 addrarray_check(const AddrArray* addr_array, target_ulong addr)
    377 {
    378     if (addr_array->num != 0) {
    379         int m_min = 0;
    380         int m_max = addr_array->num - 1;
    381 
    382         /* May be odd for THUMB mode. */
    383         addr &= ~1;
    384         /* Since array is sorted we can do binary search here. */
    385         while (m_min <= m_max) {
    386             const int m = (m_min + m_max) >> 1;
    387             const target_ulong saved = addr_array->addr[m];
    388             if (addr == saved) {
    389                 return 1;
    390             }
    391             if (addr < saved) {
    392                 m_max = m - 1;
    393             } else {
    394                 m_min = m + 1;
    395             }
    396         }
    397     }
    398     return 0;
    399 }
    400 
    401 /* Adds an address to the address array.
    402  * Return:
    403  *  1  - Address has been added to the array.
    404  *  -1 - Address already exists in the array.
    405  *  0  - Unable to expand the array.
    406  */
    407 static inline int
    408 addrarray_add(AddrArray* addr_array, target_ulong addr)
    409 {
    410     target_ulong* new_arr;
    411     int m_min;
    412     int m_max;
    413 
    414     /* May be odd for THUMB mode. */
    415     addr &= ~1;
    416     if (addr_array->num == 0) {
    417         /* First element. */
    418         addr_array->addr = qemu_malloc(sizeof(target_ulong));
    419         assert(addr_array->addr != NULL);
    420         if (addr_array->addr == NULL) {
    421             return 0;
    422         }
    423         *addr_array->addr = addr;
    424         addr_array->num++;
    425         return 1;
    426     }
    427 
    428     /* Using binary search find the place where to insert new address. */
    429     m_min = 0;
    430     m_max = addr_array->num - 1;
    431     while (m_min <= m_max) {
    432         const int m = (m_min + m_max) >> 1;
    433         const target_ulong saved = addr_array->addr[m];
    434         if (addr == saved) {
    435             return -1;
    436         }
    437         if (addr < saved) {
    438             m_max = m - 1;
    439         } else {
    440             m_min = m + 1;
    441         }
    442     }
    443     if (m_max < 0) {
    444         m_max = 0;
    445     }
    446     /* Expand the array. */
    447     new_arr = qemu_malloc(sizeof(target_ulong) * (addr_array->num + 1));
    448     assert(new_arr != NULL);
    449     if (new_arr == NULL) {
    450         return 0;
    451     }
    452     /* Copy preceding elements to the new array. */
    453     if (m_max != 0) {
    454         memcpy(new_arr, addr_array->addr, m_max * sizeof(target_ulong));
    455     }
    456     if (addr > addr_array->addr[m_max]) {
    457         new_arr[m_max] = addr_array->addr[m_max];
    458         m_max++;
    459     }
    460     /* Insert new address. */
    461     new_arr[m_max] = addr;
    462     /* Copy remaining elements to the new array. */
    463     if (m_max < addr_array->num) {
    464         memcpy(new_arr + m_max + 1, addr_array->addr + m_max,
    465                (addr_array->num - m_max) * sizeof(target_ulong));
    466     }
    467     /* Swap arrays. */
    468     qemu_free(addr_array->addr);
    469     addr_array->addr = new_arr;
    470     addr_array->num++;
    471     return 1;
    472 }
    473 
    474 #ifdef __cplusplus
    475 };  /* end of extern "C" */
    476 #endif
    477 
    478 #endif  // QEMU_MEMCHECK_MEMCHECK_COMMON_H
    479