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