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