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