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
initialize_pools(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 *
dis_namelist_create(void)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
dis_namelist_add(dis_namelist_t * list,const char * name,int value)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
walk_sections(dis_tgt_t * tgt,dis_scn_t * scn,void * data)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 *
dis_namelist_resolve_sections(dis_namelist_t * namelist,dis_tgt_t * tgt)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
walk_functions(dis_tgt_t * tgt,dis_func_t * func,void * data)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 *
dis_namelist_resolve_functions(dis_namelist_t * namelist,dis_tgt_t * tgt)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
dis_namelist_empty(dis_namelist_t * list)297 dis_namelist_empty(dis_namelist_t *list)
298 {
299 return (uu_list_numnodes(list) == 0);
300 }
301
302 static void
free_list(uu_list_t * list)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
dis_scnlist_destroy(dis_scnlist_t * list)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
dis_funclist_destroy(dis_funclist_t * list)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
dis_namelist_destroy(dis_namelist_t * list)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
dis_scnlist_iter(uu_list_t * list,void (* func)(dis_scn_t *,int,void *),void * arg)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
dis_funclist_iter(uu_list_t * list,void (* func)(dis_func_t *,int,void *),void * arg)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