aboutsummaryrefslogtreecommitdiffstats
path: root/memcheck/memcheck_proc_management.h
blob: 7f489cf4089451c1df1ed83ec21656f03bf6c160 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/* Copyright (C) 2007-2010 The Android Open Source Project
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
*/

/*
 * Contains declarations of structures, routines, etc. related to process
 * management in memchecker framework.
 */

#ifndef QEMU_MEMCHECK_MEMCHECK_PROC_MANAGEMENT_H
#define QEMU_MEMCHECK_MEMCHECK_PROC_MANAGEMENT_H

#include "qemu-queue.h"
#include "memcheck_common.h"
#include "memcheck_malloc_map.h"
#include "memcheck_mmrange_map.h"

#ifdef __cplusplus
extern "C" {
#endif

// =============================================================================
// Process management structures
// =============================================================================

/* Describes a process that is monitored by memchecker framework. */
typedef struct ProcDesc {
    /* Map of memory blocks allocated in context of this process. */
    AllocMap                                    alloc_map;

    /* Map of memory mapped modules loaded in context of this process. */
    MMRangeMap                                  mmrange_map;

    /* Descriptor's entry in the global process list. */
    QLIST_ENTRY(ProcDesc)                        global_entry;

    /* List of threads running in context of this process. */
    QLIST_HEAD(threads, ThreadDesc)              threads;

    /* Path to the process' image file. */
    char*                                       image_path;

    /* Process id. */
    uint32_t                                    pid;

    /* Parent process id. */
    uint32_t                                    parent_pid;

    /* Misc. process flags. See PROC_FLAG_XXX */
    uint32_t                                    flags;
} ProcDesc;

/* Process is executing. */
#define PROC_FLAG_EXECUTING             0x00000001
/* Process is exiting. */
#define PROC_FLAG_EXITING               0x00000002
/* ProcDesc->image_path has been replaced during process execution. */
#define PROC_FLAG_IMAGE_PATH_REPLACED   0x00000004
/* libc.so instance has been initialized for this process. */
#define PROC_FLAG_LIBC_INITIALIZED      0x00000008

/* Entry in the thread's calling stack array. */
typedef struct ThreadCallStackEntry {
    /* Guest PC where call has been made. */
    target_ulong    call_address;
    /* Guest PC where call has been made, relative to the beginning of the
     * mapped module that contains call_address. */
    target_ulong    call_address_rel;
    /* Guest PC where call will return. */
    target_ulong    ret_address;
    /* Guest PC where call will return, relative to the beginning of the
     * mapped module that contains ret_address. */
    target_ulong    ret_address_rel;
    /* Path to the image file of the module containing call_address. */
    char*           module_path;
} ThreadCallStackEntry;

/* Describes a thread that is monitored by memchecker framework. */
typedef struct ThreadDesc {
    /* Descriptor's entry in the global thread list. */
    QLIST_ENTRY(ThreadDesc)  global_entry;

    /* Descriptor's entry in the process' thread list. */
    QLIST_ENTRY(ThreadDesc)  proc_entry;

    /* Descriptor of the process this thread belongs to. */
    ProcDesc*               process;

    /* Calling stack for this thread. */
    ThreadCallStackEntry*   call_stack;

    /* Number of entries in the call_stack array. */
    uint32_t                call_stack_count;

    /* Maximum number of entries that can fit into call_stack buffer. */
    uint32_t                call_stack_max;

    /* Thread id. */
    uint32_t                tid;
} ThreadDesc;

// =============================================================================
// Inlines
// =============================================================================

/* Checks if process has been forked, rather than created from a "fresh" PID.
 * Param:
 *  proc - Descriptor for the process to check.
 * Return:
 *  boolean: 1 if process has been forked, or 0 if it was
 *  created from a "fresh" PID.
 */
static inline int
procdesc_is_forked(const ProcDesc* proc)
{
    return proc->parent_pid != 0;
}

/* Checks if process is executing.
 * Param:
 *  proc - Descriptor for the process to check.
 * Return:
 *  boolean: 1 if process is executing, or 0 if it is not executing.
 */
static inline int
procdesc_is_executing(const ProcDesc* proc)
{
    return (proc->flags & PROC_FLAG_EXECUTING) != 0;
}

/* Checks if process is exiting.
 * Param:
 *  proc - Descriptor for the process to check.
 * Return:
 *  boolean: 1 if process is exiting, or 0 if it is still alive.
 */
static inline int
procdesc_is_exiting(const ProcDesc* proc)
{
    return (proc->flags & PROC_FLAG_EXITING) != 0;
}

/* Checks if process has initialized its libc.so instance.
 * Param:
 *  proc - Descriptor for the process to check.
 * Return:
 *  boolean: 1 if process has initialized its libc.so instance, or 0 otherwise.
 */
static inline int
procdesc_is_libc_initialized(const ProcDesc* proc)
{
    return (proc->flags & PROC_FLAG_LIBC_INITIALIZED) != 0;
}

/* Checks if process image path has been replaced.
 * Param:
 *  proc - Descriptor for the process to check.
 * Return:
 *  boolean: 1 if process image path has been replaced,
 *  or 0 if it was not replaced.
 */
static inline int
procdesc_is_image_path_replaced(const ProcDesc* proc)
{
    return (proc->flags & PROC_FLAG_IMAGE_PATH_REPLACED) != 0;
}

// =============================================================================
// Process management API
// =============================================================================

/* Gets thread descriptor for the current thread.
 * Return:
 *  Found thread descriptor, or NULL if thread descriptor has not been found.
 */
ThreadDesc* get_current_thread(void);

/* Initializes process management API. */
void memcheck_init_proc_management(void);

/* Gets process descriptor for the current process.
 * Return:
 *  Process descriptor for the current process, or NULL, if process descriptor
 *  has not been found.
 */
ProcDesc* get_current_process(void);

/* Finds process descriptor for a process id.
 * Param:
 *  pid - Process ID to look up process descriptor for.
 * Return:
 *  Process descriptor for the PID, or NULL, if process descriptor
 *  has not been found.
 */
ProcDesc* get_process_from_pid(uint32_t pid);

/* Inserts new (or replaces existing) entry in the allocation descriptors map
 * for the given process.
 * See allocmap_insert for more information on this routine, its parameters
 * and returning value.
 * Param:
 *  proc - Process descriptor where to add new allocation entry info.
 */
static inline RBTMapResult
procdesc_add_malloc(ProcDesc* proc,
                    const MallocDescEx* desc,
                    MallocDescEx* replaced)
{
    return allocmap_insert(&proc->alloc_map, desc, replaced);
}

/* Finds an entry in the allocation descriptors map for the given process,
 * matching given address range.
 * See allocmap_find for more information on this routine, its parameters
 * and returning value.
 * Param:
 *  proc - Process descriptor where to find an allocation entry.
 */
static inline MallocDescEx*
procdesc_find_malloc_for_range(ProcDesc* proc,
                               target_ulong address,
                               uint32_t block_size)
{
    return allocmap_find(&proc->alloc_map, address, block_size);
}

/* Finds an entry in the allocation descriptors map for the given process,
 * matching given address.
 * See allocmap_find for more information on this routine, its parameters
 * and returning value.
 * Param:
 *  proc - Process descriptor where to find an allocation entry.
 */
static inline MallocDescEx*
procdesc_find_malloc(ProcDesc* proc, target_ulong address)
{
    return procdesc_find_malloc_for_range(proc, address, 1);
}

/* Pulls (finds and removes) an entry from the allocation descriptors map for
 * the given process, matching given address.
 * See allocmap_pull for more information on this routine, its parameters
 * and returning value.
 * Param:
 *  proc - Process descriptor where to pull an allocation entry from.
 */
static inline int
procdesc_pull_malloc(ProcDesc* proc, target_ulong address, MallocDescEx* pulled)
{
    return allocmap_pull(&proc->alloc_map, address, pulled);
}

/* Empties allocation descriptors map for the process.
 * Param:
 *  proc - Process to empty allocation map for.
 * Return:
 *  Number of entries deleted from the allocation map.
 */
static inline int
procdesc_empty_alloc_map(ProcDesc* proc)
{
    return allocmap_empty(&proc->alloc_map);
}

/* Finds mmapping entry for the given address in the given process.
 * Param:
 *  proc - Descriptor of the process where to look for an entry.
 *  addr - Address in the guest space for which to find an entry.
 * Return:
 *  Mapped entry, or NULL if no mapping for teh given address exists in the
 *  process address space.
 */
static inline MMRangeDesc*
procdesc_find_mapentry(const ProcDesc* proc, target_ulong addr)
{
    return mmrangemap_find(&proc->mmrange_map, addr, addr + 1);
}

/* Gets module descriptor for the given address.
 * Param:
 *  proc - Descriptor of the process where to look for a module.
 *  addr - Address in the guest space for which to find a module descriptor.
 * Return:
 *  module descriptor for the module containing the given address, or NULL if no
 *  such module has been found in the process' map of mmaped modules.
 */
static inline const MMRangeDesc*
procdesc_get_range_desc(const ProcDesc* proc, target_ulong addr)
{
    return procdesc_find_mapentry(proc, addr);
}

/* Gets name of the module mmaped in context of the given process for the
 * given address.
 * Param:
 *  proc - Descriptor of the process where to look for a module.
 *  addr - Address in the guest space for which to find a module.
 * Return:
 *  Image path to the module containing the given address, or NULL if no such
 *  module has been found in the process' map of mmaped modules.
 */
static inline const char*
procdesc_get_module_path(const ProcDesc* proc, target_ulong addr)
{
    MMRangeDesc* rdesc = procdesc_find_mapentry(proc, addr);
    return rdesc != NULL ? rdesc->path : NULL;
}

#ifdef __cplusplus
};  /* end of extern "C" */
#endif

#endif  // QEMU_MEMCHECK_MEMCHECK_PROC_MANAGEMENT_H