1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/types.h>
28 #include <assert.h>
29 #include <stdlib.h>
30 #include "rcapd_mapping.h"
31 #include "utils.h"
32
33 /*
34 * lmapping_t is a list of non-overlapping mappings, ordered by address. These
35 * functions add, remove, and verify the existence of mappings in such a list.
36 * rcapd_scanner.c is a consumer.
37 */
38
39 typedef struct lmapping_find_cb_arg {
40 uintptr_t lmfa_addr;
41 size_t lmfa_size;
42 lmapping_t *lmfa_prior;
43 lmapping_t *lmfa_ret;
44 } lmapping_find_cb_arg_t;
45
46 #ifdef DEBUG
47 /*
48 * Verify a sublist is properly ordered.
49 */
50 static void
lmapping_verify(lmapping_t * lm)51 lmapping_verify(lmapping_t *lm)
52 {
53 while (lm != NULL) {
54 if (lm->lm_next != NULL)
55 ASSERT(lm->lm_next->lm_addr > lm->lm_addr);
56 lm = lm->lm_next;
57 }
58 }
59 #else /* !DEBUG */
60 #define lmapping_verify(x) ((void)0)
61 #endif /* DEBUG */
62
63 /*
64 * Determine the position of a mapping with the given address and size. Upon
65 * return, lmfa_ret will be set to the actual mapping, if it exists, and
66 * lmfa_prior will be set to the mapping which does or would precede one with
67 * the given characteristics.
68 */
69 static int
lmapping_find_cb(lmapping_t * lm,void * arg)70 lmapping_find_cb(lmapping_t *lm, void *arg)
71 {
72 lmapping_find_cb_arg_t *lmfa = arg;
73
74 if (lm->lm_addr >= lmfa->lmfa_addr) {
75 if (lmfa->lmfa_addr == lm->lm_addr && lmfa->lmfa_size ==
76 lm->lm_size)
77 lmfa->lmfa_ret = lm;
78 return (1);
79 } else
80 lmfa->lmfa_prior = lm;
81
82 return (0);
83 }
84
85 static void
lmapping_walk(lmapping_t * lm,int (* lmapping_walk_cb)(lmapping_t *,void *),void * arg)86 lmapping_walk(lmapping_t *lm, int(*lmapping_walk_cb)(lmapping_t *, void *),
87 void *arg)
88 {
89 lmapping_t *next;
90
91 while (lm != NULL) {
92 next = lm->lm_next;
93 lmapping_verify(lm);
94 if (lmapping_walk_cb(lm, arg) != 0) {
95 lmapping_verify(lm);
96 return;
97 }
98 lm = next;
99 }
100 }
101
102 int
lmapping_remove(lmapping_t ** lm,uintptr_t addr,size_t size)103 lmapping_remove(lmapping_t **lm, uintptr_t addr, size_t size)
104 {
105 lmapping_find_cb_arg_t lmfa;
106
107 lmfa.lmfa_addr = addr;
108 lmfa.lmfa_size = size;
109 lmfa.lmfa_prior = lmfa.lmfa_ret = NULL;
110
111 lmapping_verify(*lm);
112 lmapping_walk(*lm, lmapping_find_cb, &lmfa);
113 if (lmfa.lmfa_ret == NULL)
114 return (-1);
115
116 if (lmfa.lmfa_prior != NULL)
117 lmfa.lmfa_prior->lm_next = lmfa.lmfa_ret->lm_next;
118 else if (*lm == lmfa.lmfa_ret)
119 *lm = lmfa.lmfa_ret->lm_next;
120
121 free(lmfa.lmfa_ret);
122
123 lmapping_verify(*lm);
124
125 return (0);
126 }
127
128 int
lmapping_insert(lmapping_t ** lm,uintptr_t addr,size_t size)129 lmapping_insert(lmapping_t **lm, uintptr_t addr, size_t size)
130 {
131 lmapping_find_cb_arg_t lmfa;
132 lmapping_t *cur;
133
134 cur = malloc(sizeof (*cur));
135 if (cur == NULL)
136 return (-1);
137
138 cur->lm_addr = addr;
139 cur->lm_size = size;
140 cur->lm_next = NULL;
141
142 lmfa.lmfa_addr = addr;
143 lmfa.lmfa_size = size;
144 lmfa.lmfa_prior = lmfa.lmfa_ret = NULL;
145
146 lmapping_verify(*lm);
147 lmapping_walk(*lm, lmapping_find_cb, &lmfa);
148 ASSERT(lmfa.lmfa_ret == NULL);
149 if (lmfa.lmfa_prior != NULL) {
150 cur->lm_next = lmfa.lmfa_prior->lm_next;
151 lmfa.lmfa_prior->lm_next = cur;
152 } else {
153 cur->lm_next = *lm;
154 *lm = cur;
155 }
156
157 lmapping_verify(*lm);
158
159 return (0);
160 }
161
162 int
lmapping_contains(lmapping_t * lm,uintptr_t addr,size_t size)163 lmapping_contains(lmapping_t *lm, uintptr_t addr, size_t size)
164 {
165 lmapping_find_cb_arg_t lmfa;
166
167 lmfa.lmfa_addr = addr;
168 lmfa.lmfa_size = size;
169 lmfa.lmfa_ret = NULL;
170
171 lmapping_walk(lm, lmapping_find_cb, &lmfa);
172 return (lmfa.lmfa_ret != NULL);
173 }
174
175 /*ARGSUSED*/
176 static int
lmapping_free_cb(lmapping_t * lm,void * arg)177 lmapping_free_cb(lmapping_t *lm, void *arg)
178 {
179 free(lm);
180 return (0);
181 }
182
183 void
lmapping_free(lmapping_t ** lm)184 lmapping_free(lmapping_t **lm)
185 {
186 lmapping_walk(*lm, lmapping_free_cb, NULL);
187 *lm = NULL;
188 }
189
190 #ifdef DEBUG
191 int
lmapping_dump_diff(lmapping_t * lm1,lmapping_t * lm2)192 lmapping_dump_diff(lmapping_t *lm1, lmapping_t *lm2)
193 {
194 lmapping_t **lmv;
195 int res = 0;
196 int ch = 0;
197 int label_printed = 0;
198
199 #define OUTPUT_LABEL() \
200 if (label_printed == 0) { \
201 debug("changes in mappings:\n"); \
202 label_printed++; \
203 }
204
205 while (lm1 != NULL && lm2 != NULL) {
206 if ((lm1->lm_addr != lm2->lm_addr) || (lm1->lm_size !=
207 lm2->lm_size)) {
208 res = -1;
209
210 if (lm1->lm_addr == lm2->lm_addr && lm1->lm_size <
211 lm2->lm_size || lm1->lm_addr < lm2->lm_addr) {
212 lmv = &lm1;
213 ch = '-';
214 } else {
215 lmv = &lm2;
216 ch = '+';
217 }
218 OUTPUT_LABEL();
219 debug("%c%p+0x%llx\n", ch, (void *)(*lmv)->lm_addr,
220 (long long)(*lmv)->lm_size);
221 *lmv = (*lmv)->lm_next;
222 } else {
223 lm1 = lm1->lm_next;
224 lm2 = lm2->lm_next;
225 }
226 }
227 while (lm1 != NULL) {
228 OUTPUT_LABEL();
229 debug("%c%p+0x%llx\n", '-', (void *)lm1->lm_addr,
230 (unsigned long long)lm1->lm_size);
231 lm1 = lm1->lm_next;
232 res = 1;
233 }
234 while (lm2 != NULL) {
235 OUTPUT_LABEL();
236 debug("%c%p+0x%llx\n", '+', (void *)lm2->lm_addr,
237 (long long)lm2->lm_size);
238 lm2 = lm2->lm_next;
239 res = 1;
240 }
241
242 return (res);
243 #undef OUTPUT_LABEL
244 }
245 #endif /* DEBUG */
246