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 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 * 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 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 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 * 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 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 * 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 295 dis_namelist_empty(dis_namelist_t *list) 296 { 297 return (uu_list_numnodes(list) == 0); 298 } 299 300 static void 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 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 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 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 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 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