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 implementation of memory checking framework in the emulator.
     15  */
     16 
     17 /* This file should compile iff qemu is built with memory checking
     18  * configuration turned on. */
     19 #ifndef CONFIG_MEMCHECK
     20 #error CONFIG_MEMCHECK is not defined.
     21 #endif  // CONFIG_MEMCHECK
     22 
     23 #include "sys-queue.h"
     24 #include "qemu_file.h"
     25 #include "elff_api.h"
     26 #include "memcheck.h"
     27 #include "memcheck_proc_management.h"
     28 #include "memcheck_util.h"
     29 #include "memcheck_logging.h"
     30 
     31 // =============================================================================
     32 // Global data
     33 // =============================================================================
     34 
     35 /* Controls what messages from the guest should be printed to emulator's
     36  * stdout. This variable holds a combinations of TRACE_LIBC_XXX flags. */
     37 uint32_t trace_flags = 0;
     38 
     39 /* Global flag, indicating whether or not memchecking has been enabled
     40  * for the current emulator session. 1 means that memchecking has been enabled,
     41  * 0 means that memchecking has not been enabled. */
     42 int memcheck_enabled = 0;
     43 
     44 /* Global flag, indicating whether or not __ld/__stx_mmu should be instrumented
     45  * for checking for access violations. If read / write access violation check
     46  * has been disabled by -memcheck flags, there is no need to instrument mmu
     47  * routines and waste performance.
     48  * 1 means that instrumenting is required, 0 means that instrumenting is not
     49  * required. */
     50 int memcheck_instrument_mmu = 0;
     51 
     52 /* Global flag, indicating whether or not memchecker is collecting call stack.
     53  * 1 - call stack is being collected, 0 means that stack is not being
     54  * collected. */
     55 int memcheck_watch_call_stack = 1;
     56 
     57 // =============================================================================
     58 // Static routines.
     59 // =============================================================================
     60 
     61 /* Prints invalid pointer access violation information.
     62  * Param:
     63  *  proc - Process that caused access violation.
     64  *  ptr - Pointer that caused access violation.
     65  *  routine - If 1, access violation has occurred in 'free' routine.
     66  *      If 2, access violation has occurred in 'realloc' routine.
     67  */
     68 static void
     69 av_invalid_pointer(ProcDesc* proc, target_ulong ptr, int routine)
     70 {
     71     if (trace_flags & TRACE_CHECK_INVALID_PTR_ENABLED) {
     72         printf("memcheck: Access violation is detected in process %s[pid=%u]:\n"
     73           "  INVALID POINTER 0x%08X is used in '%s' operation.\n"
     74           "  Allocation descriptor for this pointer has not been found in the\n"
     75           "  allocation map for the process. Most likely, this is an attempt\n"
     76           "  to %s a pointer that has been freed.\n",
     77           proc->image_path, proc->pid, ptr, routine == 1 ? "free" : "realloc",
     78           routine == 1 ? "free" : "reallocate");
     79     }
     80 }
     81 
     82 /* Prints read / write access violation information.
     83  * Param:
     84  *  proc - Process that caused access violation.
     85  *  desc - Allocation descriptor for the violation.
     86  *  addr - Address at which vilation has occurred.
     87  *  data_size - Size of data accessed at the 'addr'.
     88  *  val - If access violation has occurred at write operation, this parameter
     89  *      contains value that's being written to 'addr'. For read violation this
     90  *      parameter is not used.
     91  *  retaddr - Code address (in TB) where access violation has occurred.
     92  *  is_read - If 1, access violation has occurred when memory at 'addr' has been
     93  *      read. If 0, access violation has occurred when memory was written.
     94  */
     95 static void
     96 av_access_violation(ProcDesc* proc,
     97                     MallocDescEx* desc,
     98                     target_ulong addr,
     99                     uint32_t data_size,
    100                     uint64_t val,
    101                     target_ulong retaddr,
    102                     int is_read)
    103 {
    104     target_ulong vaddr;
    105     Elf_AddressInfo elff_info;
    106     ELFF_HANDLE elff_handle = NULL;
    107 
    108     desc->malloc_desc.av_count++;
    109     if ((is_read && !(trace_flags & TRACE_CHECK_READ_VIOLATION_ENABLED)) ||
    110         (!is_read && !(trace_flags & TRACE_CHECK_WRITE_VIOLATION_ENABLED))) {
    111         return;
    112     }
    113 
    114     /* Convert host address to guest address. */
    115     vaddr = memcheck_tpc_to_gpc(retaddr);
    116     printf("memcheck: Access violation is detected in process %s[pid=%u]:\n",
    117            proc->image_path, proc->pid);
    118 
    119     /* Obtain routine, filename / line info for the address. */
    120     const MMRangeDesc* rdesc = procdesc_get_range_desc(proc, vaddr);
    121     if (rdesc != NULL) {
    122         int elff_res;
    123         printf("  In module %s at address 0x%08X\n", rdesc->path, vaddr);
    124         elff_res =
    125           memcheck_get_address_info(vaddr, rdesc, &elff_info, &elff_handle);
    126         if (elff_res == 0) {
    127             printf("  In routine %s in %s/%s:%u\n",
    128                    elff_info.routine_name, elff_info.dir_name,
    129                    elff_info.file_name, elff_info.line_number);
    130             if (elff_info.inline_stack != NULL) {
    131                 const Elf_InlineInfo* inl = elff_info.inline_stack;
    132                 int index = 0;
    133                 for (; inl[index].routine_name != NULL; index++) {
    134                     char align[64];
    135                     size_t set_align = 4 + index * 2;
    136                     if (set_align >= sizeof(align)) {
    137                         set_align = sizeof(align) -1;
    138                     }
    139                     memset(align, ' ', set_align);
    140                     align[set_align] = '\0';
    141                     printf(align);
    142                     if (inl[index].inlined_in_file == NULL) {
    143                         printf("inlined to %s in unknown location\n",
    144                                inl[index].routine_name);
    145                     } else {
    146                         printf("inlined to %s in %s/%s:%u\n",
    147                                inl[index].routine_name,
    148                                inl[index].inlined_in_file_dir,
    149                                inl[index].inlined_in_file,
    150                                inl[index].inlined_at_line);
    151                     }
    152                 }
    153             }
    154             elff_free_pc_address_info(elff_handle, &elff_info);
    155             elff_close(elff_handle);
    156         } else if (elff_res == 1) {
    157             printf("  Unable to obtain routine information. Symbols file is not found.\n");
    158         } else {
    159             printf("  Unable to obtain routine information.\n"
    160                    "  Symbols file doesn't contain debugging information for address 0x%08X.\n",
    161                     mmrangedesc_get_module_offset(rdesc, vaddr));
    162         }
    163     } else {
    164         printf("  In unknown module at address 0x%08X\n", vaddr);
    165     }
    166 
    167     printf("  Process attempts to %s %u bytes %s address 0x%08X\n",
    168            is_read ? "read" : "write", data_size,
    169            is_read ? "from" : "to", addr);
    170     printf("  Accessed range belongs to the %s guarding area of allocated block.\n",
    171            addr < (target_ulong)mallocdesc_get_user_ptr(&desc->malloc_desc) ?
    172                 "prefix" : "suffix");
    173     printf("  Allocation descriptor for this violation:\n");
    174     memcheck_dump_malloc_desc(desc, 1, 0);
    175 }
    176 
    177 /* Validates access to a guest address.
    178  * Param:
    179  *  addr - Virtual address in the guest space where memory is accessed.
    180  *  data_size - Size of the accessed data.
    181  *  proc_ptr - Upon exit from this routine contains pointer to the process
    182  *      descriptor for the current process, or NULL, if no such descriptor has
    183  *      been found.
    184  *  desc_ptr - Upon exit from this routine contains pointer to the allocation
    185  *      descriptor matching given address range, or NULL, if allocation
    186  *      descriptor for the validated memory range has not been found.
    187  * Return:
    188  *  0 if access to the given guest address range doesn't violate anything, or
    189  *  1 if given guest address range doesn't match any entry in the current
    190  *      process allocation descriptors map, or
    191  *  -1 if a violation has been detected.
    192  */
    193 static int
    194 memcheck_common_access_validation(target_ulong addr,
    195                                   uint32_t data_size,
    196                                   ProcDesc** proc_ptr,
    197                                   MallocDescEx** desc_ptr)
    198 {
    199     MallocDescEx* desc;
    200     target_ulong validating_range_end;
    201     target_ulong user_range_end;
    202 
    203     ProcDesc* proc = get_current_process();
    204     *proc_ptr = proc;
    205     if (proc == NULL) {
    206         *desc_ptr = NULL;
    207         return 1;
    208     }
    209 
    210     desc = procdesc_find_malloc_for_range(proc, addr, data_size);
    211     *desc_ptr = desc;
    212     if (desc == NULL) {
    213         return 1;
    214     }
    215 
    216     /* Verify that validating address range doesn't start before the address
    217      * available to the user. */
    218     if (addr < mallocdesc_get_user_ptr(&desc->malloc_desc)) {
    219         // Stepped on the prefix guarding area.
    220         return -1;
    221     }
    222 
    223     validating_range_end = addr + data_size;
    224     user_range_end = mallocdesc_get_user_alloc_end(&desc->malloc_desc);
    225 
    226     /* Verify that validating address range ends inside the user block.
    227      * We may step on the suffix guarding area because of alignment issue.
    228      * For example, the application code reads last byte in the allocated block
    229      * with something like this:
    230      *
    231      *      char last_byte_value = *(char*)last_byte_address;
    232      *
    233      * and this code got compiled into something like this:
    234      *
    235      *      mov eax, [last_byte_address];
    236      *      mov [last_byte_value], al;
    237      *
    238      * In this case we will catch a read from the suffix area, even though
    239      * there were no errors in the code. So, in order to prevent such "false
    240      * negative" alarms, lets "forgive" this violation.
    241      * There is one bad thing about this "forgivness" though, as it may very
    242      * well be, that in real life some of these "out of bound" bytes will cross
    243      * page boundaries, marching into a page that has not been mapped to the
    244      * process.
    245      */
    246     if (validating_range_end <= user_range_end) {
    247         // Validating address range is fully contained inside the user block.
    248         return 0;
    249     }
    250 
    251     /* Lets see if this AV is caused by an alignment issue.*/
    252     if ((validating_range_end - user_range_end) < data_size) {
    253         /* Could be an alignment. */
    254         return 0;
    255     }
    256 
    257     return -1;
    258 }
    259 
    260 /* Checks if process has allocation descriptors for pages defined by a buffer.
    261  * Param:
    262  *  addr - Starting address of a buffer.
    263  *  buf_size - Buffer size.
    264  * Return:
    265  *  1 if process has allocations descriptors for pages defined by a buffer, or
    266  *  0 if pages containing given buffer don't have any memory allocations in
    267  *  them.
    268  */
    269 static inline int
    270 procdesc_contains_allocs(ProcDesc* proc, target_ulong addr, uint32_t buf_size) {
    271     if (proc != NULL) {
    272         // Beginning of the page containing last byte in range.
    273         const target_ulong end_page = (addr + buf_size - 1) & TARGET_PAGE_MASK;
    274         // Adjust beginning of the range to the beginning of the page.
    275         addr &= TARGET_PAGE_MASK;
    276         // Total size of range to check for descriptors.
    277         buf_size = end_page - addr + TARGET_PAGE_SIZE + 1;
    278         return procdesc_find_malloc_for_range(proc, addr, buf_size) ? 1 : 0;
    279     } else {
    280         return 0;
    281     }
    282 }
    283 
    284 // =============================================================================
    285 // Memchecker API.
    286 // =============================================================================
    287 
    288 void
    289 memcheck_init(const char* tracing_flags)
    290 {
    291     if (*tracing_flags == '0') {
    292         // Memchecker is disabled.
    293         return;
    294     } else if (*tracing_flags == '1') {
    295         // Set default tracing.
    296         trace_flags = TRACE_CHECK_LEAK_ENABLED             |
    297                       TRACE_CHECK_READ_VIOLATION_ENABLED   |
    298                       TRACE_CHECK_INVALID_PTR_ENABLED      |
    299                       TRACE_CHECK_WRITE_VIOLATION_ENABLED;
    300     }
    301 
    302     // Parse -memcheck option params, converting them into tracing flags.
    303     while (*tracing_flags) {
    304         switch (*tracing_flags) {
    305             case 'A':
    306                 // Enable all emulator's tracing messages.
    307                 trace_flags |= TRACE_ALL_ENABLED;
    308                 break;
    309             case 'F':
    310                 // Enable fork() tracing.
    311                 trace_flags |= TRACE_PROC_FORK_ENABLED;
    312                 break;
    313             case 'S':
    314                 // Enable guest process staring tracing.
    315                 trace_flags |= TRACE_PROC_START_ENABLED;
    316                 break;
    317             case 'E':
    318                 // Enable guest process exiting tracing.
    319                 trace_flags |= TRACE_PROC_EXIT_ENABLED;
    320                 break;
    321             case 'C':
    322                 // Enable clone() tracing.
    323                 trace_flags |= TRACE_PROC_CLONE_ENABLED;
    324                 break;
    325             case 'N':
    326                 // Enable new PID allocation tracing.
    327                 trace_flags |= TRACE_PROC_NEW_PID_ENABLED;
    328                 break;
    329             case 'B':
    330                 // Enable libc.so initialization tracing.
    331                 trace_flags |= TRACE_PROC_LIBC_INIT_ENABLED;
    332                 break;
    333             case 'L':
    334                 // Enable memory leaks tracing.
    335                 trace_flags |= TRACE_CHECK_LEAK_ENABLED;
    336                 break;
    337             case 'I':
    338                 // Enable invalid free / realloc pointer tracing.
    339                 trace_flags |= TRACE_CHECK_INVALID_PTR_ENABLED;
    340                 break;
    341             case 'R':
    342                 // Enable reading violations tracing.
    343                 trace_flags |= TRACE_CHECK_READ_VIOLATION_ENABLED;
    344                 break;
    345             case 'W':
    346                 // Enable writing violations tracing.
    347                 trace_flags |= TRACE_CHECK_WRITE_VIOLATION_ENABLED;
    348                 break;
    349             case 'M':
    350                 // Enable module mapping tracing.
    351                 trace_flags |= TRACE_PROC_MMAP_ENABLED;
    352                 break;
    353             default:
    354                 break;
    355         }
    356         if (trace_flags == TRACE_ALL_ENABLED) {
    357             break;
    358         }
    359         tracing_flags++;
    360     }
    361 
    362     /* Lets see if we need to instrument MMU, injecting memory access checking.
    363      * We instrument MMU only if we monitor read, or write memory access. */
    364     if (trace_flags & (TRACE_CHECK_READ_VIOLATION_ENABLED |
    365                        TRACE_CHECK_WRITE_VIOLATION_ENABLED)) {
    366         memcheck_instrument_mmu = 1;
    367     } else {
    368         memcheck_instrument_mmu = 0;
    369     }
    370 
    371     memcheck_init_proc_management();
    372 
    373     /* Lets check env. variables needed for memory checking. */
    374     if (getenv("ANDROID_PROJECT_OUT") == NULL) {
    375         printf("memcheck: Missing ANDROID_PROJECT_OUT environment variable, that is used\n"
    376                "to calculate path to symbol files.\n");
    377     }
    378 
    379     // Always set this flag at the very end of the initialization!
    380     memcheck_enabled = 1;
    381 }
    382 
    383 void
    384 memcheck_guest_libc_initialized(uint32_t pid)
    385 {
    386     ProcDesc* proc = get_process_from_pid(pid);
    387     if (proc == NULL) {
    388         ME("memcheck: Unable to obtain process for libc_init pid=%u", pid);
    389         return;
    390     }
    391     proc->flags |= PROC_FLAG_LIBC_INITIALIZED;
    392 
    393     /* When process initializes its own libc.so instance, it means that now
    394      * it has fresh heap. So, at this point we must get rid of all entries
    395      * (inherited and transition) that were collected in this process'
    396      * allocation descriptors map. */
    397     procdesc_empty_alloc_map(proc);
    398     T(PROC_LIBC_INIT, "memcheck: libc.so has been initialized for %s[pid=%u]\n",
    399       proc->image_path, proc->pid);
    400 }
    401 
    402 void
    403 memcheck_guest_alloc(target_ulong guest_address)
    404 {
    405     MallocDescEx desc;
    406     MallocDescEx replaced;
    407     RBTMapResult insert_res;
    408     ProcDesc* proc;
    409     ThreadDesc* thread;
    410     uint32_t indx;
    411 
    412     // Copy allocation descriptor from guest to emulator.
    413     memcheck_get_malloc_descriptor(&desc.malloc_desc, guest_address);
    414     desc.flags = 0;
    415     desc.call_stack = NULL;
    416     desc.call_stack_count = 0;
    417 
    418     proc = get_process_from_pid(desc.malloc_desc.allocator_pid);
    419     if (proc == NULL) {
    420         ME("memcheck: Unable to obtain process for allocation pid=%u",
    421            desc.malloc_desc.allocator_pid);
    422         memcheck_fail_alloc(guest_address);
    423         return;
    424     }
    425 
    426     if (!procdesc_is_executing(proc)) {
    427         desc.flags |= MDESC_FLAG_TRANSITION_ENTRY;
    428     }
    429 
    430     /* Copy thread's calling stack to the allocation descriptor. */
    431     thread = get_current_thread();
    432     desc.call_stack_count = thread->call_stack_count;
    433     if (desc.call_stack_count) {
    434         desc.call_stack = qemu_malloc(desc.call_stack_count * sizeof(target_ulong));
    435         if (desc.call_stack == NULL) {
    436             ME("memcheck: Unable to allocate %u bytes for the calling stack",
    437                desc.call_stack_count * sizeof(target_ulong));
    438             return;
    439         }
    440     }
    441 
    442     /* Thread's calling stack is in descending order (i.e. first entry in the
    443      * thread's stack is the most distant routine from the current one). On the
    444      * other hand, we keep calling stack entries in allocation descriptor in
    445      * assending order. */
    446     for (indx = 0; indx < thread->call_stack_count; indx++) {
    447         desc.call_stack[indx] =
    448            thread->call_stack[thread->call_stack_count - 1 - indx].call_address;
    449     }
    450 
    451     // Save malloc descriptor in the map.
    452     insert_res = procdesc_add_malloc(proc, &desc, &replaced);
    453     if (insert_res == RBT_MAP_RESULT_ENTRY_INSERTED) {
    454         // Invalidate TLB cache for the allocated block.
    455         if (memcheck_instrument_mmu) {
    456             invalidate_tlb_cache(desc.malloc_desc.ptr,
    457                                 mallocdesc_get_alloc_end(&desc.malloc_desc));
    458         }
    459     } else if (insert_res == RBT_MAP_RESULT_ENTRY_REPLACED) {
    460         /* We don't expect to have another entry in the map that matches
    461          * inserting entry. This is an error condition for us, indicating
    462          * that we somehow lost track of memory allocations. */
    463         ME("memcheck: Duplicate allocation blocks:");
    464         if (VERBOSE_CHECK(memcheck)) {
    465             printf("   New block:\n");
    466             memcheck_dump_malloc_desc(&desc, 1, 1);
    467             printf("   Replaced block:\n");
    468             memcheck_dump_malloc_desc(&replaced, 1, 1);
    469         }
    470         if (replaced.call_stack != NULL) {
    471             qemu_free(replaced.call_stack);
    472         }
    473     } else {
    474         ME("memcheck: Unable to insert an entry to the allocation map:");
    475         if (VERBOSE_CHECK(memcheck)) {
    476             memcheck_dump_malloc_desc(&desc, 1, 1);
    477         }
    478         memcheck_fail_alloc(guest_address);
    479         return;
    480     }
    481 }
    482 
    483 void
    484 memcheck_guest_free(target_ulong guest_address)
    485 {
    486     MallocFree desc;
    487     MallocDescEx pulled;
    488     int pull_res;
    489     ProcDesc* proc;
    490 
    491     // Copy free descriptor from guest to emulator.
    492     memcheck_get_free_descriptor(&desc, guest_address);
    493 
    494     proc = get_process_from_pid(desc.free_pid);
    495     if (proc == NULL) {
    496         ME("memcheck: Unable to obtain process for pid=%u on free",
    497            desc.free_pid);
    498         memcheck_fail_free(guest_address);
    499         return;
    500     }
    501 
    502     // Pull matching entry from the map.
    503     pull_res = procdesc_pull_malloc(proc, desc.ptr, &pulled);
    504     if (pull_res) {
    505         av_invalid_pointer(proc, desc.ptr, 1);
    506         memcheck_fail_free(guest_address);
    507         return;
    508     }
    509 
    510     // Make sure that ptr has expected value
    511     if (desc.ptr != mallocdesc_get_user_ptr(&pulled.malloc_desc)) {
    512         if (trace_flags & TRACE_CHECK_INVALID_PTR_ENABLED) {
    513             printf("memcheck: Access violation is detected in process %s[pid=%u]:\n",
    514                    proc->image_path, proc->pid);
    515             printf("  INVALID POINTER 0x%08X is used in 'free' operation.\n"
    516                    "  This pointer is unexpected for 'free' operation, as allocation\n"
    517                    "  descriptor found for this pointer in the process' allocation map\n"
    518                    "  suggests that 0x%08X is the pointer to be used to free this block.\n"
    519                    "  Allocation descriptor matching the pointer:\n",
    520                    desc.ptr,
    521                    (uint32_t)mallocdesc_get_user_ptr(&pulled.malloc_desc));
    522             memcheck_dump_malloc_desc(&pulled, 1, 0);
    523         }
    524     }
    525     if (pulled.call_stack != NULL) {
    526         qemu_free(pulled.call_stack);
    527     }
    528 }
    529 
    530 void
    531 memcheck_guest_query_malloc(target_ulong guest_address)
    532 {
    533     MallocDescQuery qdesc;
    534     MallocDescEx* found;
    535     ProcDesc* proc;
    536 
    537     // Copy free descriptor from guest to emulator.
    538     memcheck_get_query_descriptor(&qdesc, guest_address);
    539 
    540     proc = get_process_from_pid(qdesc.query_pid);
    541     if (proc == NULL) {
    542         ME("memcheck: Unable to obtain process for pid=%u on query_%s",
    543            qdesc.query_pid, qdesc.routine == 1 ? "free" : "realloc");
    544         memcheck_fail_query(guest_address);
    545         return;
    546     }
    547 
    548     // Find allocation entry for the given address.
    549     found = procdesc_find_malloc(proc, qdesc.ptr);
    550     if (found == NULL) {
    551         av_invalid_pointer(proc, qdesc.ptr, qdesc.routine);
    552         memcheck_fail_query(guest_address);
    553         return;
    554     }
    555 
    556     // Copy allocation descriptor back to the guest's space.
    557     memcheck_set_malloc_descriptor(qdesc.desc, &found->malloc_desc);
    558 }
    559 
    560 void
    561 memcheck_guest_print_str(target_ulong str) {
    562     char str_copy[4096];
    563     memcheck_get_guest_string(str_copy, str, sizeof(str_copy));
    564     printf(str_copy);
    565 }
    566 
    567 /* Validates read operations, detected in __ldx_mmu routine.
    568  * This routine is called from __ldx_mmu wrapper implemented in
    569  * softmmu_template.h on condition that loading is occurring from user memory.
    570  * Param:
    571  *  addr - Virtual address in the guest space where memory is read.
    572  *  data_size - Size of the read.
    573  *  retaddr - Code address (in TB) that accesses memory.
    574  * Return:
    575  *  1 if TLB record for the accessed page should be invalidated in order to
    576  *  ensure that subsequent attempts to access data in this page will cause
    577  *  __ld/stx_mmu to be used. If memchecker is no longer interested in monitoring
    578  * access to this page, this routine returns 0.
    579  */
    580 int
    581 memcheck_validate_ld(target_ulong addr,
    582                      uint32_t data_size,
    583                      target_ulong retaddr)
    584 {
    585     ProcDesc* proc;
    586     MallocDescEx* desc;
    587 
    588     int res = memcheck_common_access_validation(addr, data_size, &proc, &desc);
    589     if (res == -1) {
    590         av_access_violation(proc, desc, addr, data_size, 0, retaddr, 1);
    591         return 1;
    592     }
    593 
    594     /* Even though descriptor for the given address range has not been found,
    595      * we need to make sure that pages containing the given address range
    596      * don't contain other descriptors. */
    597     return res ? procdesc_contains_allocs(proc, addr, data_size) : 0;
    598 }
    599 
    600 /* Validates write operations, detected in __stx_mmu routine.
    601  * This routine is called from __stx_mmu wrapper implemented in
    602  * softmmu_template.h on condition that storing is occurring from user memory.
    603  * Param:
    604  *  addr - Virtual address in the guest space where memory is written.
    605  *  data_size - Size of the write.
    606  *  value - Value to be written. Note that we typecast all values to 64 bits,
    607  *      since this will fit all data sizes.
    608  *  retaddr - Code address (in TB) that accesses memory.
    609  * Return:
    610  *  1 if TLB record for the accessed page should be invalidated in order to
    611  *  ensure that subsequent attempts to access data in this page will cause
    612  *  __ld/stx_mmu to be used. If memchecker is no longer interested in monitoring
    613  * access to this page, this routine returns 0.
    614  */
    615 int
    616 memcheck_validate_st(target_ulong addr,
    617                      uint32_t data_size,
    618                      uint64_t value,
    619                      target_ulong retaddr)
    620 {
    621     MallocDescEx* desc;
    622     ProcDesc* proc;
    623 
    624     int res = memcheck_common_access_validation(addr, data_size, &proc, &desc);
    625     if (res == -1) {
    626         av_access_violation(proc, desc, addr, data_size, value, retaddr, 0);
    627         return 1;
    628     }
    629 
    630     /* Even though descriptor for the given address range has not been found,
    631      * we need to make sure that pages containing the given address range
    632      * don't contain other descriptors. */
    633     return res ? procdesc_contains_allocs(proc, addr, data_size) : 0;
    634 }
    635 
    636 /* Checks if given address range in the context of the current process is under
    637  * surveillance.
    638  * Param:
    639  *  addr - Starting address of a range.
    640  *  size - Range size.
    641  * Return:
    642  *  boolean: 1 if address range contains memory that require access violation
    643  *  detection, or 0 if given address range is in no interest to the memchecker.
    644  */
    645 int
    646 memcheck_is_checked(target_ulong addr, uint32_t size) {
    647     return procdesc_contains_allocs(get_current_process(), addr, size) ? 1 : 0;
    648 }
    649