xref: /illumos-gate/usr/src/cmd/rcap/rcapd/rcapd_mapping.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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
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
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
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
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
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
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
179 lmapping_free_cb(lmapping_t *lm, void *arg)
180 {
181 	free(lm);
182 	return (0);
183 }
184 
185 void
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
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