• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
get_sym_path(const char * module_path,char * sym_path,size_t max_char)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
memcheck_get_guest_buffer(void * qemu_address,target_ulong guest_address,size_t buffer_size)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
memcheck_set_guest_buffer(target_ulong guest_address,const void * qemu_address,size_t buffer_size)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
memcheck_get_guest_string(char * qemu_str,target_ulong guest_str,size_t qemu_buffer_size)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
memcheck_get_guest_kernel_string(char * qemu_str,target_ulong guest_str,size_t qemu_buffer_size)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
memcheck_fail_alloc(target_ulong guest_address)161 memcheck_fail_alloc(target_ulong guest_address)
162 {
163     stl_user(ALLOC_RES_ADDRESS(guest_address), 0);
164 }
165 
166 void
memcheck_fail_free(target_ulong guest_address)167 memcheck_fail_free(target_ulong guest_address)
168 {
169     stl_user(FREE_RES_ADDRESS(guest_address), 0);
170 }
171 
172 void
memcheck_fail_query(target_ulong guest_address)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
invalidate_tlb_cache(target_ulong start,target_ulong end)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
memcheck_dump_malloc_desc(const MallocDescEx * desc_ex,int print_flags,int print_proc_info)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
memcheck_get_address_info(target_ulong abs_pc,const MMRangeDesc * rdesc,Elf_AddressInfo * info,ELFF_HANDLE * elff_handle)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