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