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