xref: /illumos-gate/usr/src/cmd/dis/dis_list.c (revision 7a6d80f1660abd4755c68cbd094d4a914681d26e)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stddef.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "dis_target.h"
32 #include "dis_list.h"
33 #include "dis_util.h"
34 
35 /*
36  * List support functions.
37  *
38  * Support routines for managing lists of sections and functions.  We first
39  * process the command line arguments into lists of strings.  For each target,
40  * we resolve these strings against the set of available sections and/or
41  * functions to arrive at the set of objects to disassemble.
42  *
43  * We export two types of lists, namelists and resolvelists.  The first is used
44  * to record names given as command line options.  The latter is used to
45  * maintain the data objects specific to a given target.
46  */
47 
48 typedef struct unresolved_name {
49 	const char	*un_name;	/* name of function or object */
50 	int		un_value;	/* user-supplied data */
51 	int		un_mark;	/* internal counter */
52 	uu_list_node_t	un_node;	/* uulist node */
53 } unresolved_name_t;
54 
55 typedef struct resolved_name {
56 	void		*rn_data;	/* section or function data */
57 	int		rn_value;	/* user-supplied data */
58 	uu_list_node_t	rn_node;	/* uulist node */
59 } resolved_name_t;
60 
61 static uu_list_pool_t *unresolved_pool;
62 static uu_list_pool_t *resolved_pool;
63 static int current_mark = 0;
64 
65 static void
66 initialize_pools(void)
67 {
68 	unresolved_pool = uu_list_pool_create(
69 	    "unresolved_pool", sizeof (unresolved_name_t),
70 	    offsetof(unresolved_name_t, un_node), NULL, 0);
71 	resolved_pool = uu_list_pool_create(
72 	    "resolved_pool", sizeof (resolved_name_t),
73 	    offsetof(resolved_name_t, rn_node), NULL, 0);
74 
75 	if (unresolved_pool == NULL ||
76 	    resolved_pool == NULL)
77 		die("out of memory");
78 }
79 
80 /*
81  * Returns an empty list of unresolved names.
82  */
83 dis_namelist_t *
84 dis_namelist_create(void)
85 {
86 	uu_list_t *listp;
87 
88 	/*
89 	 * If this is the first request to create a list, initialize the list
90 	 * pools.
91 	 */
92 	if (unresolved_pool == NULL)
93 		initialize_pools();
94 
95 	if ((listp = uu_list_create(unresolved_pool, NULL, 0)) == NULL)
96 		die("out of memory");
97 
98 	return (listp);
99 }
100 
101 /*
102  * Adds the given name to the unresolved list.  'value' is an arbitrary value
103  * which is preserved for this entry, even when resolved against a target.  This
104  * allows the caller to associate similar behavior (such as the difference
105  * between -d, -D, and -s) without having to create multiple lists.
106  */
107 void
108 dis_namelist_add(dis_namelist_t *list, const char *name, int value)
109 {
110 	unresolved_name_t *node;
111 
112 	node = safe_malloc(sizeof (unresolved_name_t));
113 
114 	node->un_name = name;
115 	node->un_value = value;
116 	node->un_mark = 0;
117 
118 	(void) uu_list_insert_before(list, NULL, node);
119 }
120 
121 /*
122  * Internal callback structure used
123  */
124 typedef struct cb_data {
125 	int		cb_mark;
126 	uu_list_t	*cb_source;
127 	uu_list_t	*cb_resolved;
128 } cb_data_t;
129 
130 /*
131  * For each section, walk the list of unresolved names and resolve those that
132  * correspond to real functions.  We mark functions as we see them, and re-walk
133  * the list a second time to warn about functions we didn't find.
134  *
135  * This is an O(n * m) algorithm, but we typically search for only a single
136  * function.
137  */
138 /* ARGSUSED */
139 static void
140 walk_sections(dis_tgt_t *tgt, dis_scn_t *scn, void *data)
141 {
142 	cb_data_t *cb = data;
143 	unresolved_name_t *unp;
144 	uu_list_walk_t *walk;
145 
146 	if ((walk = uu_list_walk_start(cb->cb_source, UU_DEFAULT)) == NULL)
147 		die("out of memory");
148 
149 	while ((unp = uu_list_walk_next(walk)) != NULL) {
150 		if (strcmp(unp->un_name, dis_section_name(scn)) == 0) {
151 			resolved_name_t *resolved;
152 
153 			/*
154 			 * Mark the current node as seen
155 			 */
156 			unp->un_mark = cb->cb_mark;
157 
158 			/*
159 			 * Add the data to the resolved list
160 			 */
161 			resolved = safe_malloc(sizeof (resolved_name_t));
162 
163 			resolved->rn_data = dis_section_copy(scn);
164 			resolved->rn_value = unp->un_value;
165 
166 			(void) uu_list_insert_before(cb->cb_resolved, NULL,
167 			    resolved);
168 		}
169 	}
170 
171 	uu_list_walk_end(walk);
172 }
173 
174 /*
175  * Take a list of unresolved names and create a resolved list of sections.  We
176  * rely on walk_sections() to do the dirty work.  After resolving the sections,
177  * we check for any unmarked names and warn the user about missing sections.
178  */
179 dis_scnlist_t *
180 dis_namelist_resolve_sections(dis_namelist_t *namelist, dis_tgt_t *tgt)
181 {
182 	uu_list_t *listp;
183 	cb_data_t cb;
184 	unresolved_name_t *unp;
185 	uu_list_walk_t *walk;
186 
187 	/*
188 	 * Walk all sections in the target, calling walk_sections() for each
189 	 * one.
190 	 */
191 	if ((listp = uu_list_create(resolved_pool, NULL, UU_DEFAULT)) == NULL)
192 		die("out of memory");
193 
194 	cb.cb_mark = ++current_mark;
195 	cb.cb_source = namelist;
196 	cb.cb_resolved = listp;
197 
198 	dis_tgt_section_iter(tgt, walk_sections, &cb);
199 
200 	/*
201 	 * Walk all elements of the unresolved list, and report any that we
202 	 * didn't mark in the process.
203 	 */
204 	if ((walk = uu_list_walk_start(namelist, UU_DEFAULT)) == NULL)
205 		die("out of memory");
206 
207 	while ((unp = uu_list_walk_next(walk)) != NULL) {
208 		if (unp->un_mark != current_mark)
209 			warn("failed to find section '%s' in '%s'",
210 			    unp->un_name, dis_tgt_name(tgt));
211 	}
212 
213 	uu_list_walk_end(walk);
214 
215 	return (listp);
216 }
217 
218 /*
219  * Similar to walk_sections(), but for functions.
220  */
221 /* ARGSUSED */
222 static void
223 walk_functions(dis_tgt_t *tgt, dis_func_t *func, void *data)
224 {
225 	cb_data_t *cb = data;
226 	unresolved_name_t *unp;
227 	uu_list_walk_t *walk;
228 
229 	if ((walk = uu_list_walk_start(cb->cb_source, UU_DEFAULT)) == NULL)
230 		die("out of memory");
231 
232 	while ((unp = uu_list_walk_next(walk)) != NULL) {
233 		if (strcmp(unp->un_name, dis_function_name(func)) == 0) {
234 			resolved_name_t *resolved;
235 
236 			unp->un_mark = cb->cb_mark;
237 
238 			resolved = safe_malloc(sizeof (resolved_name_t));
239 
240 			resolved->rn_data = dis_function_copy(func);
241 			resolved->rn_value = unp->un_value;
242 
243 			(void) uu_list_insert_before(cb->cb_resolved, NULL,
244 			    resolved);
245 		}
246 	}
247 
248 	uu_list_walk_end(walk);
249 }
250 
251 /*
252  * Take a list of unresolved names and create a resolved list of functions.  We
253  * rely on walk_functions() to do the dirty work.  After resolving the
254  * functions, * we check for any unmarked names and warn the user about missing
255  * functions.
256  */
257 dis_funclist_t *
258 dis_namelist_resolve_functions(dis_namelist_t *namelist, dis_tgt_t *tgt)
259 {
260 	uu_list_t *listp;
261 	uu_list_walk_t *walk;
262 	unresolved_name_t *unp;
263 	cb_data_t cb;
264 
265 	if ((listp = uu_list_create(resolved_pool, NULL, UU_DEFAULT)) == NULL)
266 		die("out of memory");
267 
268 	cb.cb_mark = ++current_mark;
269 	cb.cb_source = namelist;
270 	cb.cb_resolved = listp;
271 
272 	dis_tgt_function_iter(tgt, walk_functions, &cb);
273 
274 	/*
275 	 * Walk unresolved list and report any missing functions.
276 	 */
277 	if ((walk = uu_list_walk_start(namelist, UU_DEFAULT)) == NULL)
278 		die("out of memory");
279 
280 	while ((unp = uu_list_walk_next(walk)) != NULL) {
281 		if (unp->un_mark != current_mark)
282 			warn("failed to find function '%s' in '%s'",
283 			    unp->un_name, dis_tgt_name(tgt));
284 	}
285 
286 	uu_list_walk_end(walk);
287 
288 	return (listp);
289 }
290 
291 /*
292  * Returns true if the given list is empty.
293  */
294 int
295 dis_namelist_empty(dis_namelist_t *list)
296 {
297 	return (uu_list_numnodes(list) == 0);
298 }
299 
300 static void
301 free_list(uu_list_t *list)
302 {
303 	uu_list_walk_t *walk;
304 	void *data;
305 
306 	if ((walk = uu_list_walk_start(list, UU_WALK_ROBUST)) == NULL)
307 		die("out of memory");
308 
309 	while ((data = uu_list_walk_next(walk)) != NULL) {
310 		uu_list_remove(list, data);
311 		free(data);
312 	}
313 
314 	uu_list_walk_end(walk);
315 
316 	uu_list_destroy(list);
317 }
318 
319 /*
320  * Destroy a list of sections.  First, walk the list and free the associated
321  * section data.  Pass the list onto to free_list() to clean up the rest of the
322  * list.
323  */
324 void
325 dis_scnlist_destroy(dis_scnlist_t *list)
326 {
327 	uu_list_walk_t *walk;
328 	resolved_name_t *data;
329 
330 	if ((walk = uu_list_walk_start(list, UU_DEFAULT)) == NULL)
331 		die("out of memory");
332 
333 	while ((data = uu_list_walk_next(walk)) != NULL)
334 		dis_section_free(data->rn_data);
335 
336 	uu_list_walk_end(walk);
337 
338 	free_list(list);
339 }
340 
341 /*
342  * Destroy a list of functions.  First, walk the list and free the associated
343  * function data.  Pass the list onto to free_list() to clean up the rest of the
344  * list.
345  */
346 void
347 dis_funclist_destroy(dis_funclist_t *list)
348 {
349 	uu_list_walk_t *walk;
350 	resolved_name_t *data;
351 
352 	if ((walk = uu_list_walk_start(list, UU_DEFAULT)) == NULL)
353 		die("out of memory");
354 
355 	while ((data = uu_list_walk_next(walk)) != NULL)
356 		dis_function_free(data->rn_data);
357 
358 	uu_list_walk_end(walk);
359 
360 	free_list(list);
361 }
362 
363 /*
364  * Destroy a lis tof unresolved names.
365  */
366 void
367 dis_namelist_destroy(dis_namelist_t *list)
368 {
369 	free_list(list);
370 }
371 
372 /*
373  * Iterate over a resolved list of sections.
374  */
375 void
376 dis_scnlist_iter(uu_list_t *list, void (*func)(dis_scn_t *, int, void *),
377     void *arg)
378 {
379 	uu_list_walk_t *walk;
380 	resolved_name_t *data;
381 
382 	if ((walk = uu_list_walk_start(list, UU_DEFAULT)) == NULL)
383 		die("out of memory");
384 
385 	while ((data = uu_list_walk_next(walk)) != NULL)
386 		func(data->rn_data, data->rn_value, arg);
387 
388 	uu_list_walk_end(walk);
389 }
390 
391 /*
392  * Iterate over a resolved list of functions.
393  */
394 void
395 dis_funclist_iter(uu_list_t *list, void (*func)(dis_func_t *, int, void *),
396     void *arg)
397 {
398 	uu_list_walk_t *walk;
399 	resolved_name_t *data;
400 
401 	if ((walk = uu_list_walk_start(list, UU_DEFAULT)) == NULL)
402 		die("out of memory");
403 
404 	while ((data = uu_list_walk_next(walk)) != NULL)
405 		func(data->rn_data, data->rn_value, arg);
406 
407 	uu_list_walk_end(walk);
408 }
409