blob: 8a599143e1811140bf4ae167bfea995178d095d3 [file] [log] [blame]
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08001/* 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
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -080017#include "stdio.h"
18#include "qemu-common.h"
19#include "android/utils/path.h"
20#include "cpu.h"
21#include "softmmu_outside_jit.h"
22#include "memcheck_proc_management.h"
23#include "memcheck_logging.h"
24#include "memcheck_util.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 */
37static int
38get_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
87void
88memcheck_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);
David 'Digit' Turner4e024bb2010-09-22 14:19:28 +020099 qemu_address = (uint8_t*)qemu_address + 1;
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800100 guest_address++;
101 buffer_size--;
102 }
103}
104
105void
106memcheck_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++;
David 'Digit' Turner4e024bb2010-09-22 14:19:28 +0200113 qemu_address = (uint8_t*)qemu_address + 1;
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -0800114 buffer_size--;
115 }
116}
117
118size_t
119memcheck_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
137size_t
138memcheck_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
160void
161memcheck_fail_alloc(target_ulong guest_address)
162{
163 stl_user(ALLOC_RES_ADDRESS(guest_address), 0);
164}
165
166void
167memcheck_fail_free(target_ulong guest_address)
168{
169 stl_user(FREE_RES_ADDRESS(guest_address), 0);
170}
171
172void
173memcheck_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
182void
183invalidate_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
201void
202memcheck_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
229int
230memcheck_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}