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