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 utility routines for memchecker framework.
     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 "stdio.h"
     24 #include "qemu-common.h"
     25 #include "android/utils/path.h"
     26 #include "cpu.h"
     27 #include "softmmu_outside_jit.h"
     28 #include "memcheck_proc_management.h"
     29 #include "memcheck_logging.h"
     30 #include "memcheck_util.h"
     31 
     32 /* Gets symblos file path for the given module.
     33  * Param:
     34  *  module_path - Path to the module to get sympath for.
     35  *  sym_path - Buffer, where to save path to the symbols file path for the givem
     36  *      module. NOTE: This buffer must be big enough to contain the largest
     37  *      path possible.
     38  *  max_char - Character size of the buffer addressed by sym_path parameter.
     39  * Return:
     40  *  0 on success, or -1 if symbols file has not been found, or sym_path buffer
     41  *  was too small to contain entire path.
     42  */
     43 static int
     44 get_sym_path(const char* module_path, char* sym_path, size_t max_char)
     45 {
     46     const char* sym_path_root = getenv("ANDROID_PROJECT_OUT");
     47     if (sym_path_root == NULL || strlen(sym_path_root) >= max_char) {
     48         return -1;
     49     }
     50 
     51     strcpy(sym_path, sym_path_root);
     52     max_char -= strlen(sym_path_root);
     53     if (sym_path[strlen(sym_path)-1] != PATH_SEP_C) {
     54         strcat(sym_path, PATH_SEP);
     55         max_char--;
     56     }
     57     if (strlen("symbols") >= max_char) {
     58         return -1;
     59     }
     60     strcat(sym_path, "symbols");
     61     max_char -= strlen("symbols");
     62     if (strlen(module_path) >= max_char) {
     63         return -1;
     64     }
     65     strcat(sym_path, module_path);
     66 
     67     /* Sometimes symbol file for a module is placed into a parent symbols
     68      * directory. Lets iterate through all parent sym dirs, until we find
     69      * sym file, or reached symbols root. */
     70     while (!path_exists(sym_path)) {
     71         /* Select module name. */
     72         char* name = strrchr(sym_path, PATH_SEP_C);
     73         assert(name != NULL);
     74         *name = '\0';
     75         /* Parent directory. */
     76         char* parent = strrchr(sym_path, PATH_SEP_C);
     77         assert(parent != NULL);
     78         *parent = '\0';
     79         if (strcmp(sym_path, sym_path_root) == 0) {
     80             return -1;
     81         }
     82         *parent = PATH_SEP_C;
     83         memmove(parent+1, name + 1, strlen(name + 1) + 1);
     84     }
     85 
     86     return 0;
     87 }
     88 
     89 // =============================================================================
     90 // Transfering data between guest and emulator address spaces.
     91 // =============================================================================
     92 
     93 void
     94 memcheck_get_guest_buffer(void* qemu_address,
     95                           target_ulong guest_address,
     96                           size_t buffer_size)
     97 {
     98     /* Byte-by-byte copying back and forth between guest's and emulator's memory
     99      * appears to be efficient enough (at least on small blocks used in
    100      * memchecker), so there is no real need to optimize it by aligning guest
    101      * buffer to 32 bits and use ld/stl_user instead of ld/stub_user to
    102      * read / write guest's memory. */
    103     while (buffer_size) {
    104         *(uint8_t*)qemu_address = ldub_user(guest_address);
    105         (uint32_t)qemu_address++;
    106         guest_address++;
    107         buffer_size--;
    108     }
    109 }
    110 
    111 void
    112 memcheck_set_guest_buffer(target_ulong guest_address,
    113                           const void* qemu_address,
    114                           size_t buffer_size)
    115 {
    116     while (buffer_size) {
    117         stb_user(guest_address, *(uint8_t*)qemu_address);
    118         guest_address++;
    119         (uint32_t)qemu_address++;
    120         buffer_size--;
    121     }
    122 }
    123 
    124 size_t
    125 memcheck_get_guest_string(char* qemu_str,
    126                           target_ulong guest_str,
    127                           size_t qemu_buffer_size)
    128 {
    129     size_t copied = 0;
    130 
    131     if (qemu_buffer_size > 1) {
    132         for (copied = 0; copied < qemu_buffer_size - 1; copied++) {
    133             qemu_str[copied] = ldub_user(guest_str + copied);
    134             if (qemu_str[copied] == '\0') {
    135                 return copied;
    136             }
    137         }
    138     }
    139     qemu_str[copied] = '\0';
    140     return copied;
    141 }
    142 
    143 size_t
    144 memcheck_get_guest_kernel_string(char* qemu_str,
    145                                  target_ulong guest_str,
    146                                  size_t qemu_buffer_size)
    147 {
    148     size_t copied = 0;
    149 
    150     if (qemu_buffer_size > 1) {
    151         for (copied = 0; copied < qemu_buffer_size - 1; copied++) {
    152             qemu_str[copied] = ldub_kernel(guest_str + copied);
    153             if (qemu_str[copied] == '\0') {
    154                 return copied;
    155             }
    156         }
    157     }
    158     qemu_str[copied] = '\0';
    159     return copied;
    160 }
    161 
    162 // =============================================================================
    163 // Helpers for transfering memory allocation information.
    164 // =============================================================================
    165 
    166 void
    167 memcheck_fail_alloc(target_ulong guest_address)
    168 {
    169     stl_user(ALLOC_RES_ADDRESS(guest_address), 0);
    170 }
    171 
    172 void
    173 memcheck_fail_free(target_ulong guest_address)
    174 {
    175     stl_user(FREE_RES_ADDRESS(guest_address), 0);
    176 }
    177 
    178 void
    179 memcheck_fail_query(target_ulong guest_address)
    180 {
    181     stl_user(QUERY_RES_ADDRESS(guest_address), 0);
    182 }
    183 
    184 // =============================================================================
    185 // Misc. utility routines.
    186 // =============================================================================
    187 
    188 void
    189 invalidate_tlb_cache(target_ulong start, target_ulong end)
    190 {
    191     target_ulong index = (start >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
    192     const target_ulong to = ((end - 1) >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE-1);
    193     for (; index <= to; index++, start += TARGET_PAGE_SIZE) {
    194         target_ulong tlb_addr = cpu_single_env->tlb_table[1][index].addr_write;
    195         if ((start & TARGET_PAGE_MASK) ==
    196             (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
    197             cpu_single_env->tlb_table[1][index].addr_write ^= TARGET_PAGE_MASK;
    198         }
    199         tlb_addr = cpu_single_env->tlb_table[1][index].addr_read;
    200         if ((start & TARGET_PAGE_MASK) ==
    201             (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
    202             cpu_single_env->tlb_table[1][index].addr_read ^= TARGET_PAGE_MASK;
    203         }
    204     }
    205 }
    206 
    207 void
    208 memcheck_dump_malloc_desc(const MallocDescEx* desc_ex,
    209                           int print_flags,
    210                           int print_proc_info)
    211 {
    212     const MallocDesc* desc = &desc_ex->malloc_desc;
    213     printf("            User range:             0x%08X - 0x%08X, %u bytes\n",
    214            (uint32_t)mallocdesc_get_user_ptr(desc),
    215             (uint32_t)mallocdesc_get_user_ptr(desc) + desc->requested_bytes,
    216            desc->requested_bytes);
    217     printf("            Prefix guarding area:   0x%08X - 0x%08X, %u bytes\n",
    218            desc->ptr, desc->ptr + desc->prefix_size, desc->prefix_size);
    219     printf("            Suffix guarding area:   0x%08X - 0x%08X, %u bytes\n",
    220            mallocdesc_get_user_alloc_end(desc),
    221            mallocdesc_get_user_alloc_end(desc) + desc->suffix_size,
    222            desc->suffix_size);
    223     if (print_proc_info) {
    224         ProcDesc* proc = get_process_from_pid(desc->allocator_pid);
    225         if (proc != NULL) {
    226             printf("            Allocated by:           %s[pid=%u]\n",
    227                    proc->image_path, proc->pid);
    228         }
    229     }
    230     if (print_flags) {
    231         printf("            Flags:                  0x%08X\n", desc_ex->flags);
    232     }
    233 }
    234 
    235 int
    236 memcheck_get_address_info(target_ulong abs_pc,
    237                           const MMRangeDesc* rdesc,
    238                           Elf_AddressInfo* info,
    239                           ELFF_HANDLE* elff_handle)
    240 {
    241     char sym_path[MAX_PATH];
    242     ELFF_HANDLE handle;
    243 
    244     if (get_sym_path(rdesc->path, sym_path, MAX_PATH)) {
    245         return 1;
    246     }
    247 
    248     handle = elff_init(sym_path);
    249     if (handle == NULL) {
    250         return -1;
    251     }
    252 
    253     if (!elff_is_exec(handle)) {
    254         /* Debug info for shared library is created for the relative address. */
    255         target_ulong rel_pc = mmrangedesc_get_module_offset(rdesc, abs_pc);
    256         if (elff_get_pc_address_info(handle, rel_pc, info)) {
    257             elff_close(handle);
    258             return -1;
    259         }
    260     } else {
    261         /* Debug info for executables is created for the absoulte address. */
    262         if (elff_get_pc_address_info(handle, abs_pc, info)) {
    263             elff_close(handle);
    264             return -1;
    265         }
    266     }
    267 
    268     *elff_handle = handle;
    269     return 0;
    270 }
    271