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