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