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