Home | History | Annotate | Download | only in dis
      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
     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 *
     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
    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
    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 *
    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
    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 *
    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
    297 dis_namelist_empty(dis_namelist_t *list)
    298 {
    299 	return (uu_list_numnodes(list) == 0);
    300 }
    301 
    302 static void
    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
    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
    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
    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
    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
    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