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