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