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 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <sys/types.h>
30 #include <assert.h>
31 #include <stdlib.h>
32 #include "rcapd_mapping.h"
33 #include "utils.h"
34
35 /*
36 * lmapping_t is a list of non-overlapping mappings, ordered by address. These
37 * functions add, remove, and verify the existence of mappings in such a list.
38 * rcapd_scanner.c is a consumer.
39 */
40
41 typedef struct lmapping_find_cb_arg {
42 uintptr_t lmfa_addr;
43 size_t lmfa_size;
44 lmapping_t *lmfa_prior;
45 lmapping_t *lmfa_ret;
46 } lmapping_find_cb_arg_t;
47
48 #ifdef DEBUG
49 /*
50 * Verify a sublist is properly ordered.
51 */
52 static void
lmapping_verify(lmapping_t * lm)53 lmapping_verify(lmapping_t *lm)
54 {
55 while (lm != NULL) {
56 if (lm->lm_next != NULL)
57 ASSERT(lm->lm_next->lm_addr > lm->lm_addr);
58 lm = lm->lm_next;
59 }
60 }
61 #else /* !DEBUG */
62 #define lmapping_verify(x) ((void)0)
63 #endif /* DEBUG */
64
65 /*
66 * Determine the position of a mapping with the given address and size. Upon
67 * return, lmfa_ret will be set to the actual mapping, if it exists, and
68 * lmfa_prior will be set to the mapping which does or would precede one with
69 * the given characteristics.
70 */
71 static int
lmapping_find_cb(lmapping_t * lm,void * arg)72 lmapping_find_cb(lmapping_t *lm, void *arg)
73 {
74 lmapping_find_cb_arg_t *lmfa = arg;
75
76 if (lm->lm_addr >= lmfa->lmfa_addr) {
77 if (lmfa->lmfa_addr == lm->lm_addr && lmfa->lmfa_size ==
78 lm->lm_size)
79 lmfa->lmfa_ret = lm;
80 return (1);
81 } else
82 lmfa->lmfa_prior = lm;
83
84 return (0);
85 }
86
87 static void
lmapping_walk(lmapping_t * lm,int (* lmapping_walk_cb)(lmapping_t *,void *),void * arg)88 lmapping_walk(lmapping_t *lm, int(*lmapping_walk_cb)(lmapping_t *, void *),
89 void *arg)
90 {
91 lmapping_t *next;
92
93 while (lm != NULL) {
94 next = lm->lm_next;
95 lmapping_verify(lm);
96 if (lmapping_walk_cb(lm, arg) != 0) {
97 lmapping_verify(lm);
98 return;
99 }
100 lm = next;
101 }
102 }
103
104 int
lmapping_remove(lmapping_t ** lm,uintptr_t addr,size_t size)105 lmapping_remove(lmapping_t **lm, uintptr_t addr, size_t size)
106 {
107 lmapping_find_cb_arg_t lmfa;
108
109 lmfa.lmfa_addr = addr;
110 lmfa.lmfa_size = size;
111 lmfa.lmfa_prior = lmfa.lmfa_ret = NULL;
112
113 lmapping_verify(*lm);
114 lmapping_walk(*lm, lmapping_find_cb, &lmfa);
115 if (lmfa.lmfa_ret == NULL)
116 return (-1);
117
118 if (lmfa.lmfa_prior != NULL)
119 lmfa.lmfa_prior->lm_next = lmfa.lmfa_ret->lm_next;
120 else if (*lm == lmfa.lmfa_ret)
121 *lm = lmfa.lmfa_ret->lm_next;
122
123 free(lmfa.lmfa_ret);
124
125 lmapping_verify(*lm);
126
127 return (0);
128 }
129
130 int
lmapping_insert(lmapping_t ** lm,uintptr_t addr,size_t size)131 lmapping_insert(lmapping_t **lm, uintptr_t addr, size_t size)
132 {
133 lmapping_find_cb_arg_t lmfa;
134 lmapping_t *cur;
135
136 cur = malloc(sizeof (*cur));
137 if (cur == NULL)
138 return (-1);
139
140 cur->lm_addr = addr;
141 cur->lm_size = size;
142 cur->lm_next = NULL;
143
144 lmfa.lmfa_addr = addr;
145 lmfa.lmfa_size = size;
146 lmfa.lmfa_prior = lmfa.lmfa_ret = NULL;
147
148 lmapping_verify(*lm);
149 lmapping_walk(*lm, lmapping_find_cb, &lmfa);
150 ASSERT(lmfa.lmfa_ret == NULL);
151 if (lmfa.lmfa_prior != NULL) {
152 cur->lm_next = lmfa.lmfa_prior->lm_next;
153 lmfa.lmfa_prior->lm_next = cur;
154 } else {
155 cur->lm_next = *lm;
156 *lm = cur;
157 }
158
159 lmapping_verify(*lm);
160
161 return (0);
162 }
163
164 int
lmapping_contains(lmapping_t * lm,uintptr_t addr,size_t size)165 lmapping_contains(lmapping_t *lm, uintptr_t addr, size_t size)
166 {
167 lmapping_find_cb_arg_t lmfa;
168
169 lmfa.lmfa_addr = addr;
170 lmfa.lmfa_size = size;
171 lmfa.lmfa_ret = NULL;
172
173 lmapping_walk(lm, lmapping_find_cb, &lmfa);
174 return (lmfa.lmfa_ret != NULL);
175 }
176
177 /*ARGSUSED*/
178 static int
lmapping_free_cb(lmapping_t * lm,void * arg)179 lmapping_free_cb(lmapping_t *lm, void *arg)
180 {
181 free(lm);
182 return (0);
183 }
184
185 void
lmapping_free(lmapping_t ** lm)186 lmapping_free(lmapping_t **lm)
187 {
188 lmapping_walk(*lm, lmapping_free_cb, NULL);
189 *lm = NULL;
190 }
191
192 #ifdef DEBUG
193 int
lmapping_dump_diff(lmapping_t * lm1,lmapping_t * lm2)194 lmapping_dump_diff(lmapping_t *lm1, lmapping_t *lm2)
195 {
196 lmapping_t **lmv;
197 int res = 0;
198 int ch = 0;
199 int label_printed = 0;
200
201 #define OUTPUT_LABEL() \
202 if (label_printed == 0) { \
203 debug("changes in mappings:\n"); \
204 label_printed++; \
205 }
206
207 while (lm1 != NULL && lm2 != NULL) {
208 if ((lm1->lm_addr != lm2->lm_addr) || (lm1->lm_size !=
209 lm2->lm_size)) {
210 res = -1;
211
212 if (lm1->lm_addr == lm2->lm_addr && lm1->lm_size <
213 lm2->lm_size || lm1->lm_addr < lm2->lm_addr) {
214 lmv = &lm1;
215 ch = '-';
216 } else {
217 lmv = &lm2;
218 ch = '+';
219 }
220 OUTPUT_LABEL();
221 debug("%c%p+0x%llx\n", ch, (void *)(*lmv)->lm_addr,
222 (long long)(*lmv)->lm_size);
223 *lmv = (*lmv)->lm_next;
224 } else {
225 lm1 = lm1->lm_next;
226 lm2 = lm2->lm_next;
227 }
228 }
229 while (lm1 != NULL) {
230 OUTPUT_LABEL();
231 debug("%c%p+0x%llx\n", '-', (void *)lm1->lm_addr,
232 (unsigned long long)lm1->lm_size);
233 lm1 = lm1->lm_next;
234 res = 1;
235 }
236 while (lm2 != NULL) {
237 OUTPUT_LABEL();
238 debug("%c%p+0x%llx\n", '+', (void *)lm2->lm_addr,
239 (long long)lm2->lm_size);
240 lm2 = lm2->lm_next;
241 res = 1;
242 }
243
244 return (res);
245 #undef OUTPUT_LABEL
246 }
247 #endif /* DEBUG */
248