blob: d9a1211cdd50b5e1a01cb68a3acc0260e52ccd12 [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 routines that implement a red-black tree of
15 * memory mappings in the guest system.
16 */
17
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -080018#include "memcheck_mmrange_map.h"
19#include "memcheck_logging.h"
20
21/* Memory range descriptor stored in the map. */
22typedef struct MMRangeMapEntry {
23 /* R-B tree entry. */
24 RB_ENTRY(MMRangeMapEntry) rb_entry;
25
26 /* Memory range descriptor for this entry. */
27 MMRangeDesc desc;
28} MMRangeMapEntry;
29
30// =============================================================================
31// R-B Tree implementation
32// =============================================================================
33
34/* Compare routine for the map.
35 * Param:
36 * d1 - First map entry to compare.
37 * d2 - Second map entry to compare.
38 * Return:
39 * 0 - Descriptors are equal. Note that descriptors are considered to be
40 * equal iff memory blocks they describe intersect in any part.
41 * 1 - d1 is greater than d2
42 * -1 - d1 is less than d2.
43 */
44static inline int
45cmp_rb(MMRangeMapEntry* d1, MMRangeMapEntry* d2)
46{
47 const target_ulong start1 = d1->desc.map_start;
48 const target_ulong start2 = d2->desc.map_start;
49
50 if (start1 < start2) {
51 return (d1->desc.map_end - 1) < start2 ? -1 : 0;
52 }
53 return (d2->desc.map_end - 1) < start1 ? 1 : 0;
54}
55
56/* Expands RB macros here. */
57RB_GENERATE(MMRangeMap, MMRangeMapEntry, rb_entry, cmp_rb);
58
59// =============================================================================
60// Static routines
61// =============================================================================
62
63/* Inserts new (or replaces existing) entry into the map.
64 * See comments on mmrangemap_insert routine in the header file for details
65 * about this routine.
66 */
67static RBTMapResult
68mmrangemap_insert_desc(MMRangeMap* map,
69 MMRangeMapEntry* rdesc,
70 MMRangeDesc* replaced)
71{
72 MMRangeMapEntry* existing = MMRangeMap_RB_INSERT(map, rdesc);
73 if (existing == NULL) {
74 return RBT_MAP_RESULT_ENTRY_INSERTED;
75 }
76
77 // Matching entry exists. Lets see if we need to replace it.
78 if (replaced == NULL) {
79 return RBT_MAP_RESULT_ENTRY_ALREADY_EXISTS;
80 }
81
82 /* Copy existing entry to the provided buffer and replace it
83 * with the new one. */
84 memcpy(replaced, &existing->desc, sizeof(MMRangeDesc));
85 MMRangeMap_RB_REMOVE(map, existing);
86 qemu_free(existing);
87 MMRangeMap_RB_INSERT(map, rdesc);
88 return RBT_MAP_RESULT_ENTRY_REPLACED;
89}
90
91/* Finds an entry in the map that matches the given address range.
92 * Param:
93 * map - Map where to search for an entry.
94 * start - Starting address of a mapping range.
95 * end - Ending address of a mapping range.
96 * Return:
97 * Address of a map entry that matches the given range, or NULL if no
98 * such entry has been found.
99 */
100static inline MMRangeMapEntry*
101mmrangemap_find_entry(const MMRangeMap* map,
102 target_ulong start,
103 target_ulong end)
104{
105 MMRangeMapEntry rdesc;
106 rdesc.desc.map_start = start;
107 rdesc.desc.map_end = end;
108 return MMRangeMap_RB_FIND((MMRangeMap*)map, &rdesc);
109}
110
111// =============================================================================
112// Map API
113// =============================================================================
114
115void
116mmrangemap_init(MMRangeMap* map)
117{
118 RB_INIT(map);
119}
120
121RBTMapResult
122mmrangemap_insert(MMRangeMap* map,
123 const MMRangeDesc* desc,
124 MMRangeDesc* replaced)
125{
126 RBTMapResult ret;
127
128 // Allocate and initialize new map entry.
129 MMRangeMapEntry* rdesc = qemu_malloc(sizeof(MMRangeMapEntry));
130 if (rdesc == NULL) {
131 ME("memcheck: Unable to allocate new MMRangeMapEntry on insert.");
132 return RBT_MAP_RESULT_ERROR;
133 }
134 memcpy(&rdesc->desc, desc, sizeof(MMRangeDesc));
135
136 // Insert new entry into the map.
137 ret = mmrangemap_insert_desc(map, rdesc, replaced);
138 if (ret == RBT_MAP_RESULT_ENTRY_ALREADY_EXISTS ||
139 ret == RBT_MAP_RESULT_ERROR) {
140 /* Another descriptor already exists for this block, or an error
141 * occurred. We have to free new descriptor, as it wasn't inserted. */
142 qemu_free(rdesc);
143 }
144 return ret;
145}
146
147MMRangeDesc*
148mmrangemap_find(const MMRangeMap* map, target_ulong start, target_ulong end)
149{
150 MMRangeMapEntry* rdesc = mmrangemap_find_entry(map, start, end);
151 return rdesc != NULL ? &rdesc->desc : NULL;
152}
153
154int
155mmrangemap_pull(MMRangeMap* map,
156 target_ulong start,
157 target_ulong end,
158 MMRangeDesc* pulled)
159{
160 MMRangeMapEntry* rdesc = mmrangemap_find_entry(map, start, end);
161 if (rdesc != NULL) {
162 memcpy(pulled, &rdesc->desc, sizeof(MMRangeDesc));
163 MMRangeMap_RB_REMOVE(map, rdesc);
164 qemu_free(rdesc);
165 return 0;
166 } else {
167 return -1;
168 }
169}
170
171int
172mmrangemap_pull_first(MMRangeMap* map, MMRangeDesc* pulled)
173{
174 MMRangeMapEntry* first = RB_MIN(MMRangeMap, map);
175 if (first != NULL) {
176 memcpy(pulled, &first->desc, sizeof(MMRangeDesc));
177 MMRangeMap_RB_REMOVE(map, first);
178 qemu_free(first);
179 return 0;
180 } else {
181 return -1;
182 }
183}
184
185int
186mmrangemap_copy(MMRangeMap* to, const MMRangeMap* from)
187{
188 MMRangeMapEntry* entry;
189 RB_FOREACH(entry, MMRangeMap, (MMRangeMap*)from) {
190 RBTMapResult ins_res;
191 MMRangeMapEntry* new_entry =
192 (MMRangeMapEntry*)qemu_malloc(sizeof(MMRangeMapEntry));
193 if (new_entry == NULL) {
194 ME("memcheck: Unable to allocate new MMRangeMapEntry on copy.");
195 return -1;
196 }
197 memcpy(new_entry, entry, sizeof(MMRangeMapEntry));
198 new_entry->desc.path = qemu_malloc(strlen(entry->desc.path) + 1);
199 if (new_entry->desc.path == NULL) {
200 ME("memcheck: Unable to allocate new path for MMRangeMapEntry on copy.");
201 qemu_free(new_entry);
202 return -1;
203 }
204 strcpy(new_entry->desc.path, entry->desc.path);
205 ins_res = mmrangemap_insert_desc(to, new_entry, NULL);
206 if (ins_res != RBT_MAP_RESULT_ENTRY_INSERTED) {
207 ME("memcheck: Unable to insert new range map entry on copy. Insert returned %u",
208 ins_res);
209 qemu_free(new_entry->desc.path);
210 qemu_free(new_entry);
211 return -1;
212 }
213 }
214
215 return 0;
216}
217
218int
219mmrangemap_empty(MMRangeMap* map)
220{
221 MMRangeDesc pulled;
222 int removed = 0;
223
224 while (!mmrangemap_pull_first(map, &pulled)) {
225 qemu_free(pulled.path);
226 removed++;
227 }
228
229 return removed;
230}