• 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 declarations of structures, routines, etc. that are commonly used
15  * in memechecker framework.
16  */
17 
18 #ifndef QEMU_MEMCHECK_MEMCHECK_COMMON_H
19 #define QEMU_MEMCHECK_MEMCHECK_COMMON_H
20 
21 /* This file should compile iff qemu is built with memory checking
22  * configuration turned on. */
23 #ifndef CONFIG_MEMCHECK
24 #error CONFIG_MEMCHECK is not defined.
25 #endif  // CONFIG_MEMCHECK
26 
27 #include "qemu-common.h"
28 #include "cpu.h"
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
34 // =============================================================================
35 // Events generated by the guest system.
36 // =============================================================================
37 
38 /* Notifies the emulator that libc has been initialized for a process.
39  * Event's value parameter is PID for the process in context of which libc has
40  * been initialized.
41  */
42 #define TRACE_DEV_REG_LIBC_INIT             1536
43 
44 /* Notifies the emulator about new memory block being allocated.
45  * Event's value parameter points to MallocDesc instance in the guest's address
46  * space that contains allocated block information. Note that 'libc_pid' field
47  * of the descriptor is used by emulator to report failure in handling this
48  * event. In case of failure emulator will zero that filed before completing
49  * this event.
50  */
51 #define TRACE_DEV_REG_MALLOC                1537
52 
53 /* Notifies the emulator about memory block being freed.
54  * Event's value parameter points to MallocFree descriptor instance in the
55  * guest's address space that contains information about block that's being
56  * freed. Note that 'libc_pid' field of the descriptor is used by emulator to
57  * report failure in handling this event. In case of failure emulator will zero
58  * that filed before completing this event.
59  */
60 #define TRACE_DEV_REG_FREE_PTR              1538
61 
62 /* Queries the emulator about memory block information.
63  * Event's value parameter points to MallocDescQuery descriptor instance in the
64  * guest's address space that contains query parameters. Note that 'libc_pid'
65  * field of the descriptor is used by emulator to report failure in handling
66  * this event. In case of failure emulator will zero that filed before
67  * completing this event.
68  */
69 #define TRACE_DEV_REG_QUERY_MALLOC          1539
70 
71 /* Queries the emulator to print a string to its stdout.
72  * Event's value parameter points to zero-terminated string to be printed. Note
73  * that this string is located in the guest's address space.
74  */
75 #define TRACE_DEV_REG_PRINT_USER_STR        1540
76 
77 // =============================================================================
78 // Communication structures
79 // =============================================================================
80 
81 /* Describes memory block allocated from the heap. This structure is passed
82  * along with TRACE_DEV_REG_MALLOC event. This descriptor is used to inform
83  * the emulator about new memory block being allocated from the heap. The entire
84  * structure is initialized by the guest system before event is fired up. It is
85  * important to remember that same structure (an exact copy) is also declared
86  * in the libc's sources. So, every time a change is made to any of these
87  * two declaration, another one must be also updated accordingly. */
88 typedef struct MallocDesc {
89     /* Poniter to the memory block actually allocated from the heap. Note that
90      * this is not the pointer that is returned to the malloc's caller. Pointer
91      * returned to the caller is calculated by adding value stored in this field
92      * to the value stored in prefix_size field of this structure.
93      */
94     target_ulong    ptr;
95 
96     /* Nuber of bytes requested by the malloc's caller. */
97     uint32_t        requested_bytes;
98 
99     /* Byte size of the prefix data. Actual pointer returned to the malloc's
100      * caller is calculated by adding value stored in this field to the value
101      * stored in in the ptr field of this structure.
102      */
103     uint32_t        prefix_size;
104 
105     /* Byte size of the suffix data. */
106     uint32_t        suffix_size;
107 
108     /* Id of the process that initialized libc instance, in which allocation
109      * has occurred. This field is used by the emulator to report errors in
110      * the course of TRACE_DEV_REG_MALLOC event handling. In case of an error,
111      * emulator sets this field to zero (invalid value for a process ID).
112      */
113     uint32_t        libc_pid;
114 
115     /* Id of the process in context of which allocation has occurred.
116      * Value in this field may differ from libc_pid value, if process that
117      * is doing allocation has been forked from the process that initialized
118      * libc instance.
119      */
120     uint32_t        allocator_pid;
121 
122     /* Number of access violations detected on this allocation. */
123     uint32_t        av_count;
124 } MallocDesc;
125 /* Helpers for addressing field in MallocDesc structure, using which emulator
126  * reports an error back to the guest.
127  */
128 #define ALLOC_RES_OFFSET        ((uint32_t)&(((MallocDesc*)0)->libc_pid))
129 #define ALLOC_RES_ADDRESS(p)    (p + ALLOC_RES_OFFSET)
130 
131 /* Describes memory block info queried from emulator. This structure is passed
132  * along with TRACE_DEV_REG_QUERY_MALLOC event. When handling free and realloc
133  * calls, it is required that we have information about memory blocks that were
134  * actually allocated in previous calls to malloc, memalign, or realloc. Since
135  * we don't keep this information directlry in the allocated block, but rather
136  * we keep it in the emulator, we need to query emulator for that information
137  * with TRACE_DEV_REG_QUERY_MALLOC query. The entire structure is initialized
138  * by the guest system before event is fired up It is important to remember that
139  * same structure (an exact copy) is also declared in the libc's sources. So,
140  * every time a change is made to any of these two declaration, another one
141  * must be also updated accordingly.
142  */
143 typedef struct MallocDescQuery {
144     /* Pointer for which information is queried. Note that this pointer doesn't
145      * have to be exact pointer returned to malloc's caller, but can point
146      * anywhere inside an allocated block, including guarding areas. Emulator
147      * will respond with information about allocated block that contains this
148      * pointer.
149      */
150     target_ulong    ptr;
151 
152     /* Id of the process that initialized libc instance, in which this query
153      * is called. This field is used by the emulator to report errors in
154      * the course of TRACE_DEV_REG_QUERY_MALLOC event handling. In case of an
155      * error, emulator sets this field to zero (invalid value for a process ID).
156      */
157     uint32_t        libc_pid;
158 
159     /* Process ID in context of which query is made. */
160     uint32_t        query_pid;
161 
162     /* Code of the allocation routine, in context of which query has been made:
163      *  1 - free
164      *  2 - realloc
165      */
166     uint32_t        routine;
167 
168     /* Address in guest's virtual space of memory allocation descriptor for the
169      * queried pointer. Descriptor, addressed by this field is initialized by
170      * the emulator in response to the query.
171      */
172     target_ulong    desc;
173 } MallocDescQuery;
174 /* Helpers for addressing field in MallocDescQuery structure using which
175  * emulator reports an error back to the guest.
176  */
177 #define QUERY_RES_OFFSET        ((uint32_t)&(((MallocDescQuery*)0)->libc_pid))
178 #define QUERY_RES_ADDRESS(p)    (p + QUERY_RES_OFFSET)
179 
180 /* Describes memory block that is being freed back to the heap. This structure
181  * is passed along with TRACE_DEV_REG_FREE_PTR event. The entire structure is
182  * initialized by the guest system before event is fired up. It is important to
183  * remember that same structure (an exact copy) is also declared in the libc's
184  * sources. So, every time a change is made to any of these two declaration,
185  * another one must be also updated accordingly.
186  */
187 typedef struct MallocFree {
188     /* Pointer to be freed. */
189     uint32_t    ptr;
190 
191     /* Id of the process that initialized libc instance, in which this free
192      * is called. This field is used by the emulator to report errors in
193      * the course of TRACE_DEV_REG_FREE_PTR event handling. In case of an
194      * error, emulator sets this field to zero (invalid value for a process ID).
195      */
196     uint32_t    libc_pid;
197 
198     /* Process ID in context of which memory is being freed. */
199     uint32_t    free_pid;
200 } MallocFree;
201 /* Helpers for addressing field in MallocFree structure, using which emulator
202  * reports an error back to the guest.
203  */
204 #define FREE_RES_OFFSET         ((uint32_t)&(((MallocFree*)0)->libc_pid))
205 #define FREE_RES_ADDRESS(p)     (p + FREE_RES_OFFSET)
206 
207 /* Extends MallocDesc structure with additional information, used by memchecker.
208  */
209 typedef struct MallocDescEx {
210     /* Allocation descriptor this structure extends. */
211     MallocDesc      malloc_desc;
212 
213     /* Call stack that lead to memory allocation. The array is arranged in
214      * accending order, where entry at index 0 corresponds to the routine
215      * that allocated memory. */
216     target_ulong*   call_stack;
217 
218     /* Number of entries in call_stack array. */
219     uint32_t        call_stack_count;
220 
221     /* Set of misc. flags. See MDESC_FLAG_XXX bellow. */
222     uint32_t        flags;
223 } MallocDescEx;
224 
225 /* Indicates that memory has been allocated before process started execution.
226  * After a process has been forked, but before it actually starts executing,
227  * allocations can be made in context of that process PID. This flag marks such
228  * allocations in the process' allocation descriptors map.
229  */
230 #define MDESC_FLAG_TRANSITION_ENTRY         0x00000001
231 
232 /* Indicates that memory block has been inherited from the parent process.
233  * When a process is forked from its parent process, the forked process inherits
234  * a copy of the parent process' heap. Thus, all allocations that were recorded
235  * for the parent process must be also recorded for the forked process. This
236  * flag marks entries in the forked process' allocation descriptors map that
237  * were copied over from the parent process' allocation descriptors map.
238  */
239 #define MDESC_FLAG_INHERITED_ON_FORK        0x00000002
240 
241 /* Describes a memory mapping of an execution module in the guest system. */
242 typedef struct MMRangeDesc {
243     /* Starting address of mmapping of a module in the guest's address space. */
244     target_ulong            map_start;
245 
246     /* Ending address of mmapping of a module in the guest's address space. */
247     target_ulong            map_end;
248 
249     /* Mmapping's execution offset. */
250     target_ulong            exec_offset;
251 
252     /* Image path of the module that has been mapped with this mmapping. */
253     char*                   path;
254 } MMRangeDesc;
255 
256 /* Enumerates returned values for insert routines implemeted for red-black
257  * tree maps.
258  */
259 typedef enum {
260     /* New entry has been inserted into the map. */
261     RBT_MAP_RESULT_ENTRY_INSERTED = 0,
262 
263     /* An entry, matching the new one already exists in the map. */
264     RBT_MAP_RESULT_ENTRY_ALREADY_EXISTS,
265 
266     /* An existing entry, matching the new one has been replaced
267     * with the new entry.
268     */
269     RBT_MAP_RESULT_ENTRY_REPLACED,
270 
271     /* An error has occurred when inserting entry into the map. */
272     RBT_MAP_RESULT_ERROR = -1,
273 } RBTMapResult;
274 
275 /* Encapsulates an array of guest addresses, sorted in accending order. */
276 typedef struct AddrArray {
277     /* Array of addresses. */
278     target_ulong*   addr;
279 
280     /* Number of elements in the array. */
281     int             num;
282 } AddrArray;
283 
284 // =============================================================================
285 // Inlines
286 // =============================================================================
287 
288 /* Gets pointer returned to malloc caller for the given allocation decriptor.
289  * Param:
290  *  desc - Allocation descriptor.
291  * Return:
292  *  Pointer to the allocated memory returned to the malloc caller.
293  */
294 static inline target_ulong
mallocdesc_get_user_ptr(const MallocDesc * desc)295 mallocdesc_get_user_ptr(const MallocDesc* desc)
296 {
297     return desc->ptr + desc->prefix_size;
298 }
299 
300 /* Gets total size of the allocated block for the given descriptor.
301  * Param:
302  *  desc - Descriptor for the memory block, allocated in malloc handler.
303  * Return:
304  *  Total size of memory block allocated in malloc handler.
305  */
306 static inline uint32_t
mallocdesc_get_alloc_size(const MallocDesc * desc)307 mallocdesc_get_alloc_size(const MallocDesc* desc)
308 {
309     return desc->prefix_size + desc->requested_bytes + desc->suffix_size;
310 }
311 
312 /* Gets the end of the allocated block for the given descriptor.
313  * Param:
314  *  desc - Descriptor for the memory block, allocated in malloc handler.
315  * Return:
316  *  Pointer to the end of the allocated block (next byte past the block).
317  */
318 static inline target_ulong
mallocdesc_get_alloc_end(const MallocDesc * desc)319 mallocdesc_get_alloc_end(const MallocDesc* desc)
320 {
321     return desc->ptr + mallocdesc_get_alloc_size(desc);
322 }
323 
324 /* Gets the end of the allocated block available to the user for the given
325  * descriptor.
326  * Param:
327  *  desc - Descriptor for the memory block, allocated in malloc handler.
328  * Return:
329  *  Pointer to the end of the allocated block available to the user (next byte
330  *  past the block - suffix guarding area).
331  */
332 static inline target_ulong
mallocdesc_get_user_alloc_end(const MallocDesc * desc)333 mallocdesc_get_user_alloc_end(const MallocDesc* desc)
334 {
335     return mallocdesc_get_user_ptr(desc) + desc->requested_bytes;
336 }
337 
338 /* Checks if allocation has been made before process started execution.
339  * Param:
340  *  desc - Allocation descriptor to check.
341  * Return:
342  *  boolean: 1 if allocation has been made before process started execution,
343  *  or 0 if allocation has been made after process started execution.
344  */
345 static inline int
mallocdescex_is_transition_entry(const MallocDescEx * desc)346 mallocdescex_is_transition_entry(const MallocDescEx* desc)
347 {
348     return (desc->flags & MDESC_FLAG_TRANSITION_ENTRY) != 0;
349 }
350 
351 /* Checks if allocation block has been inherited on fork.
352  * Param:
353  *  desc - Allocation descriptor to check.
354  * Return:
355  *  boolean: 1 if allocation has been inherited on fork, or 0 if allocation
356  *  has been made by this process..
357  */
358 static inline int
mallocdescex_is_inherited_on_fork(const MallocDescEx * desc)359 mallocdescex_is_inherited_on_fork(const MallocDescEx* desc)
360 {
361     return (desc->flags & MDESC_FLAG_INHERITED_ON_FORK) != 0;
362 }
363 
364 /* Gets offset for the given address inside a mapped module.
365  * Param:
366  *  address - Address to get offset for.
367  * Return:
368  *  Offset of the given address inside a mapped module, represented with the
369  *  given mmaping range descriptor.
370  */
371 static inline target_ulong
mmrangedesc_get_module_offset(const MMRangeDesc * rdesc,target_ulong address)372 mmrangedesc_get_module_offset(const MMRangeDesc* rdesc, target_ulong address)
373 {
374     return address - rdesc->map_start + rdesc->exec_offset;
375 }
376 
377 /* Checks if given address is contained in the given address array.
378  * Return:
379  *  boolean: 1 if address is contained in the array, or zero if it's not.
380  */
381 static inline int
addrarray_check(const AddrArray * addr_array,target_ulong addr)382 addrarray_check(const AddrArray* addr_array, target_ulong addr)
383 {
384     if (addr_array->num != 0) {
385         int m_min = 0;
386         int m_max = addr_array->num - 1;
387 
388         /* May be odd for THUMB mode. */
389         addr &= ~1;
390         /* Since array is sorted we can do binary search here. */
391         while (m_min <= m_max) {
392             const int m = (m_min + m_max) >> 1;
393             const target_ulong saved = addr_array->addr[m];
394             if (addr == saved) {
395                 return 1;
396             }
397             if (addr < saved) {
398                 m_max = m - 1;
399             } else {
400                 m_min = m + 1;
401             }
402         }
403     }
404     return 0;
405 }
406 
407 /* Adds an address to the address array.
408  * Return:
409  *  1  - Address has been added to the array.
410  *  -1 - Address already exists in the array.
411  *  0  - Unable to expand the array.
412  */
413 static inline int
addrarray_add(AddrArray * addr_array,target_ulong addr)414 addrarray_add(AddrArray* addr_array, target_ulong addr)
415 {
416     target_ulong* new_arr;
417     int m_min;
418     int m_max;
419 
420     /* May be odd for THUMB mode. */
421     addr &= ~1;
422     if (addr_array->num == 0) {
423         /* First element. */
424         addr_array->addr = qemu_malloc(sizeof(target_ulong));
425         assert(addr_array->addr != NULL);
426         if (addr_array->addr == NULL) {
427             return 0;
428         }
429         *addr_array->addr = addr;
430         addr_array->num++;
431         return 1;
432     }
433 
434     /* Using binary search find the place where to insert new address. */
435     m_min = 0;
436     m_max = addr_array->num - 1;
437     while (m_min <= m_max) {
438         const int m = (m_min + m_max) >> 1;
439         const target_ulong saved = addr_array->addr[m];
440         if (addr == saved) {
441             return -1;
442         }
443         if (addr < saved) {
444             m_max = m - 1;
445         } else {
446             m_min = m + 1;
447         }
448     }
449     if (m_max < 0) {
450         m_max = 0;
451     }
452     /* Expand the array. */
453     new_arr = qemu_malloc(sizeof(target_ulong) * (addr_array->num + 1));
454     assert(new_arr != NULL);
455     if (new_arr == NULL) {
456         return 0;
457     }
458     /* Copy preceding elements to the new array. */
459     if (m_max != 0) {
460         memcpy(new_arr, addr_array->addr, m_max * sizeof(target_ulong));
461     }
462     if (addr > addr_array->addr[m_max]) {
463         new_arr[m_max] = addr_array->addr[m_max];
464         m_max++;
465     }
466     /* Insert new address. */
467     new_arr[m_max] = addr;
468     /* Copy remaining elements to the new array. */
469     if (m_max < addr_array->num) {
470         memcpy(new_arr + m_max + 1, addr_array->addr + m_max,
471                (addr_array->num - m_max) * sizeof(target_ulong));
472     }
473     /* Swap arrays. */
474     qemu_free(addr_array->addr);
475     addr_array->addr = new_arr;
476     addr_array->num++;
477     return 1;
478 }
479 
480 #ifdef __cplusplus
481 };  /* end of extern "C" */
482 #endif
483 
484 #endif  // QEMU_MEMCHECK_MEMCHECK_COMMON_H
485