1*d29b2c44Sab /* 2*d29b2c44Sab * CDDL HEADER START 3*d29b2c44Sab * 4*d29b2c44Sab * The contents of this file are subject to the terms of the 5*d29b2c44Sab * Common Development and Distribution License (the "License"). 6*d29b2c44Sab * You may not use this file except in compliance with the License. 7*d29b2c44Sab * 8*d29b2c44Sab * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*d29b2c44Sab * or http://www.opensolaris.org/os/licensing. 10*d29b2c44Sab * See the License for the specific language governing permissions 11*d29b2c44Sab * and limitations under the License. 12*d29b2c44Sab * 13*d29b2c44Sab * When distributing Covered Code, include this CDDL HEADER in each 14*d29b2c44Sab * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*d29b2c44Sab * If applicable, add the following below this CDDL HEADER, with the 16*d29b2c44Sab * fields enclosed by brackets "[]" replaced with your own identifying 17*d29b2c44Sab * information: Portions Copyright [yyyy] [name of copyright owner] 18*d29b2c44Sab * 19*d29b2c44Sab * CDDL HEADER END 20*d29b2c44Sab */ 21*d29b2c44Sab 22*d29b2c44Sab /* 23*d29b2c44Sab * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*d29b2c44Sab * Use is subject to license terms. 25*d29b2c44Sab */ 26*d29b2c44Sab #pragma ident "%Z%%M% %I% %E% SMI" 27*d29b2c44Sab 28*d29b2c44Sab #include <stdlib.h> 29*d29b2c44Sab #include <stdio.h> 30*d29b2c44Sab #include <unistd.h> 31*d29b2c44Sab #include <libintl.h> 32*d29b2c44Sab #include <libelf.h> 33*d29b2c44Sab #include <sys/machelf.h> 34*d29b2c44Sab #include <link.h> 35*d29b2c44Sab #include <strings.h> 36*d29b2c44Sab #include <ctype.h> 37*d29b2c44Sab #include <elfedit.h> 38*d29b2c44Sab #include <_elfedit.h> 39*d29b2c44Sab #include <sys/elf_SPARC.h> 40*d29b2c44Sab #include <sys/elf_amd64.h> 41*d29b2c44Sab #include <msg.h> 42*d29b2c44Sab 43*d29b2c44Sab 44*d29b2c44Sab 45*d29b2c44Sab /* 46*d29b2c44Sab * This file contains utility functions that are of general use 47*d29b2c44Sab * to different elfedit modules for solving common problems. 48*d29b2c44Sab * The functions in this file are not ELFCLASS specific. Those 49*d29b2c44Sab * functions are found in util_machelf.c 50*d29b2c44Sab * 51*d29b2c44Sab * NOTE: This module contains functions with names 52*d29b2c44Sab * elfedit_atoi, and elfedit_atoui, that are otherwise identical. 53*d29b2c44Sab * These functions are for signed, and unsigned integers, respectively. 54*d29b2c44Sab * In general, I supply one comment header for each such pair, 55*d29b2c44Sab * and put their implementations together. 56*d29b2c44Sab * 57*d29b2c44Sab * There are also functions with names elfedit_atoconst. These are 58*d29b2c44Sab * convenience wrappers that use the corresponding elfedit_atoui() 59*d29b2c44Sab * function to process an array of symbolic names provided by a call 60*d29b2c44Sab * elfedit_const_to_atoui(). 61*d29b2c44Sab */ 62*d29b2c44Sab 63*d29b2c44Sab 64*d29b2c44Sab 65*d29b2c44Sab 66*d29b2c44Sab /* 67*d29b2c44Sab * Given a value and an array of elfedit_ato[u]i items, return a pointer 68*d29b2c44Sab * to the symbolic name for the value. 69*d29b2c44Sab * 70*d29b2c44Sab * entry: 71*d29b2c44Sab * sym - NULL terminated array of name->value mappings. 72*d29b2c44Sab * value - Value to be found 73*d29b2c44Sab * required - If True, and value is not found, an error is issued. 74*d29b2c44Sab * Callers should only set required to True when they know 75*d29b2c44Sab * a priori that the value will be found --- the error 76*d29b2c44Sab * is reported as an internal programming error. 77*d29b2c44Sab * 78*d29b2c44Sab * exit: 79*d29b2c44Sab * If the array contains an entry with the given value, the 80*d29b2c44Sab * name for the first such entry will be returned. 81*d29b2c44Sab * 82*d29b2c44Sab * If no entry is found: If required is True (1), an error is 83*d29b2c44Sab * issued and this routine does not return to the caller. If required 84*d29b2c44Sab * is False (0), then NULL is returned. 85*d29b2c44Sab */ 86*d29b2c44Sab const char * 87*d29b2c44Sab elfedit_atoi_value_to_str(const elfedit_atoi_sym_t *sym, elfedit_atoi_t value, 88*d29b2c44Sab int required) 89*d29b2c44Sab { 90*d29b2c44Sab for (; sym->sym_name != NULL; sym++) 91*d29b2c44Sab if (value == sym->sym_value) 92*d29b2c44Sab return (sym->sym_name); 93*d29b2c44Sab 94*d29b2c44Sab /* Value did not match any of the entries */ 95*d29b2c44Sab if (required) 96*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADGETVAL)); 97*d29b2c44Sab return (NULL); 98*d29b2c44Sab } 99*d29b2c44Sab const char * 100*d29b2c44Sab elfedit_atoui_value_to_str(const elfedit_atoui_sym_t *sym, 101*d29b2c44Sab elfedit_atoui_t value, int required) 102*d29b2c44Sab { 103*d29b2c44Sab for (; sym->sym_name != NULL; sym++) 104*d29b2c44Sab if (value == sym->sym_value) 105*d29b2c44Sab return (sym->sym_name); 106*d29b2c44Sab 107*d29b2c44Sab /* Value did not match any of the entries */ 108*d29b2c44Sab if (required) 109*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADGETVAL)); 110*d29b2c44Sab return (NULL); 111*d29b2c44Sab } 112*d29b2c44Sab const char * 113*d29b2c44Sab elfedit_atoconst_value_to_str(elfedit_const_t const_type, elfedit_atoui_t value, 114*d29b2c44Sab int required) 115*d29b2c44Sab { 116*d29b2c44Sab return (elfedit_atoui_value_to_str(elfedit_const_to_atoui(const_type), 117*d29b2c44Sab value, required)); 118*d29b2c44Sab } 119*d29b2c44Sab 120*d29b2c44Sab 121*d29b2c44Sab /* 122*d29b2c44Sab * Process the symbolic name to value mappings passed to the 123*d29b2c44Sab * atoi and atoui functions. 124*d29b2c44Sab * 125*d29b2c44Sab * entry: 126*d29b2c44Sab * sym - NULL terminated array of name->value mappings. 127*d29b2c44Sab * value - Address of variable to recieve corresponding value. 128*d29b2c44Sab * 129*d29b2c44Sab * exit: 130*d29b2c44Sab * If a mapping is found, *value is set to it, and True is returned. 131*d29b2c44Sab * Otherwise False is returned. 132*d29b2c44Sab */ 133*d29b2c44Sab static int 134*d29b2c44Sab atoi_sym_process(const char *str, const elfedit_atoi_sym_t *sym, 135*d29b2c44Sab elfedit_atoi_t *value) 136*d29b2c44Sab { 137*d29b2c44Sab size_t cmp_len; 138*d29b2c44Sab const char *tail; 139*d29b2c44Sab 140*d29b2c44Sab while (isspace(*str)) 141*d29b2c44Sab str++; 142*d29b2c44Sab 143*d29b2c44Sab tail = str + strlen(str); 144*d29b2c44Sab while ((tail > str) && isspace(*(tail - 1))) 145*d29b2c44Sab tail--; 146*d29b2c44Sab 147*d29b2c44Sab cmp_len = tail - str; 148*d29b2c44Sab 149*d29b2c44Sab for (; sym->sym_name != NULL; sym++) { 150*d29b2c44Sab if ((strlen(sym->sym_name) == cmp_len) && 151*d29b2c44Sab (strncasecmp(sym->sym_name, str, cmp_len) == 0)) { 152*d29b2c44Sab *value = sym->sym_value; 153*d29b2c44Sab return (1); 154*d29b2c44Sab } 155*d29b2c44Sab } 156*d29b2c44Sab 157*d29b2c44Sab /* No symbolic mapping was found */ 158*d29b2c44Sab return (0); 159*d29b2c44Sab } 160*d29b2c44Sab static int 161*d29b2c44Sab atoui_sym_process(const char *str, const elfedit_atoui_sym_t *sym, 162*d29b2c44Sab elfedit_atoui_t *value) 163*d29b2c44Sab { 164*d29b2c44Sab size_t cmp_len; 165*d29b2c44Sab const char *tail; 166*d29b2c44Sab 167*d29b2c44Sab while (isspace(*str)) 168*d29b2c44Sab str++; 169*d29b2c44Sab 170*d29b2c44Sab tail = str + strlen(str); 171*d29b2c44Sab while ((tail > str) && isspace(*(tail - 1))) 172*d29b2c44Sab tail--; 173*d29b2c44Sab 174*d29b2c44Sab cmp_len = tail - str; 175*d29b2c44Sab 176*d29b2c44Sab for (; sym->sym_name != NULL; sym++) { 177*d29b2c44Sab if ((strlen(sym->sym_name) == cmp_len) && 178*d29b2c44Sab (strncasecmp(sym->sym_name, str, cmp_len) == 0)) { 179*d29b2c44Sab *value = sym->sym_value; 180*d29b2c44Sab return (1); 181*d29b2c44Sab } 182*d29b2c44Sab } 183*d29b2c44Sab 184*d29b2c44Sab /* No symbolic mapping was found */ 185*d29b2c44Sab return (0); 186*d29b2c44Sab } 187*d29b2c44Sab 188*d29b2c44Sab 189*d29b2c44Sab 190*d29b2c44Sab /* 191*d29b2c44Sab * A command completion function for atoi and atoui mappings. 192*d29b2c44Sab */ 193*d29b2c44Sab void 194*d29b2c44Sab elfedit_cpl_atoi(void *cpldata, const elfedit_atoi_sym_t *sym) 195*d29b2c44Sab { 196*d29b2c44Sab for (; sym->sym_name != NULL; sym++) 197*d29b2c44Sab elfedit_cpl_match(cpldata, sym->sym_name, 1); 198*d29b2c44Sab } 199*d29b2c44Sab void 200*d29b2c44Sab elfedit_cpl_atoui(void *cpldata, const elfedit_atoui_sym_t *sym) 201*d29b2c44Sab { 202*d29b2c44Sab for (; sym->sym_name != NULL; sym++) 203*d29b2c44Sab elfedit_cpl_match(cpldata, sym->sym_name, 1); 204*d29b2c44Sab } 205*d29b2c44Sab void 206*d29b2c44Sab elfedit_cpl_atoconst(void *cpldata, elfedit_const_t const_type) 207*d29b2c44Sab { 208*d29b2c44Sab elfedit_cpl_atoui(cpldata, elfedit_const_to_atoui(const_type)); 209*d29b2c44Sab } 210*d29b2c44Sab 211*d29b2c44Sab 212*d29b2c44Sab 213*d29b2c44Sab 214*d29b2c44Sab 215*d29b2c44Sab /* 216*d29b2c44Sab * Convert a string to a numeric value. Strings starting with '0' 217*d29b2c44Sab * are taken to be octal, those staring with '0x' are hex, and all 218*d29b2c44Sab * others are decimal. 219*d29b2c44Sab * 220*d29b2c44Sab * entry: 221*d29b2c44Sab * str - String to be converted 222*d29b2c44Sab * sym - NULL, or NULL terminated array of name/value pairs. 223*d29b2c44Sab * 224*d29b2c44Sab * [elfedit_atoi2() and elfedit_atoui2() only] 225*d29b2c44Sab * v - Address of variable to receive resulting value. 226*d29b2c44Sab * 227*d29b2c44Sab * exit: 228*d29b2c44Sab * elfedit_atoi2() and elfedit_atoui2(): 229*d29b2c44Sab * On success, returns True (1) and *v is set to the value. 230*d29b2c44Sab * On failure, returns False (0) and *v is undefined. 231*d29b2c44Sab * 232*d29b2c44Sab * elfedit_atoi() and elfedit_atoui(): 233*d29b2c44Sab * If the string is convertable, the value is returned. 234*d29b2c44Sab * Otherwise an error is issued and this routine does 235*d29b2c44Sab * not return to the caller. 236*d29b2c44Sab */ 237*d29b2c44Sab int 238*d29b2c44Sab elfedit_atoi2(const char *str, const elfedit_atoi_sym_t *sym, elfedit_atoi_t *v) 239*d29b2c44Sab { 240*d29b2c44Sab char *endptr; 241*d29b2c44Sab 242*d29b2c44Sab if (sym && atoi_sym_process(str, sym, v)) 243*d29b2c44Sab return (1); 244*d29b2c44Sab 245*d29b2c44Sab *v = strtoll(str, &endptr, 0); 246*d29b2c44Sab 247*d29b2c44Sab /* If the left over part contains anything but whitespace, fail */ 248*d29b2c44Sab for (; *endptr; endptr++) 249*d29b2c44Sab if (!isspace(*endptr)) 250*d29b2c44Sab return (0); 251*d29b2c44Sab return (1); 252*d29b2c44Sab } 253*d29b2c44Sab elfedit_atoi_t 254*d29b2c44Sab elfedit_atoi(const char *str, const elfedit_atoi_sym_t *sym) 255*d29b2c44Sab { 256*d29b2c44Sab elfedit_atoi_t v; 257*d29b2c44Sab if (elfedit_atoi2(str, sym, &v) == 0) 258*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_ERR, 259*d29b2c44Sab MSG_INTL(MSG_ERR_BADATOISTR), str); 260*d29b2c44Sab return (v); 261*d29b2c44Sab } 262*d29b2c44Sab int 263*d29b2c44Sab elfedit_atoui2(const char *str, const elfedit_atoui_sym_t *sym, 264*d29b2c44Sab elfedit_atoui_t *v) 265*d29b2c44Sab { 266*d29b2c44Sab char *endptr; 267*d29b2c44Sab 268*d29b2c44Sab if (sym && atoui_sym_process(str, sym, v)) 269*d29b2c44Sab return (1); 270*d29b2c44Sab 271*d29b2c44Sab *v = strtoull(str, &endptr, 0); 272*d29b2c44Sab 273*d29b2c44Sab /* If the left over part contains anything but whitespace, fail */ 274*d29b2c44Sab for (; *endptr; endptr++) 275*d29b2c44Sab if (!isspace(*endptr)) 276*d29b2c44Sab return (0); 277*d29b2c44Sab return (1); 278*d29b2c44Sab } 279*d29b2c44Sab elfedit_atoui_t 280*d29b2c44Sab elfedit_atoui(const char *str, const elfedit_atoui_sym_t *sym) 281*d29b2c44Sab { 282*d29b2c44Sab elfedit_atoui_t v; 283*d29b2c44Sab if (elfedit_atoui2(str, sym, &v) == 0) 284*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_ERR, 285*d29b2c44Sab MSG_INTL(MSG_ERR_BADATOISTR), str); 286*d29b2c44Sab return (v); 287*d29b2c44Sab } 288*d29b2c44Sab int 289*d29b2c44Sab elfedit_atoconst2(const char *str, elfedit_const_t const_type, 290*d29b2c44Sab elfedit_atoui_t *v) 291*d29b2c44Sab { 292*d29b2c44Sab return (elfedit_atoui2(str, elfedit_const_to_atoui(const_type), v)); 293*d29b2c44Sab } 294*d29b2c44Sab elfedit_atoui_t 295*d29b2c44Sab elfedit_atoconst(const char *str, elfedit_const_t const_type) 296*d29b2c44Sab { 297*d29b2c44Sab return (elfedit_atoui(str, elfedit_const_to_atoui(const_type))); 298*d29b2c44Sab } 299*d29b2c44Sab 300*d29b2c44Sab /* 301*d29b2c44Sab * Convert a string to a numeric value using elfedit_ato[u]i and 302*d29b2c44Sab * ensure that the resulting value lies within a given range. 303*d29b2c44Sab * elfedit_ato[u]i_range() requires values to be in the range 304*d29b2c44Sab * (min <= value <= max). 305*d29b2c44Sab * 306*d29b2c44Sab * entry: 307*d29b2c44Sab * str - String to be converted 308*d29b2c44Sab * min, max - If check_range is true, the allowed range that the 309*d29b2c44Sab * resulting value must lie in. 310*d29b2c44Sab * sym - NULL, or NULL terminated array of name/value pairs. 311*d29b2c44Sab * 312*d29b2c44Sab * entry [elfedit_atoi_range() and elfedit_atoui_range() only]: 313*d29b2c44Sab * item_name - String describing item for which value is being read. 314*d29b2c44Sab * 315*d29b2c44Sab * entry [elfedit_atoi_range2() and elfedit_atoui_range2() only]: 316*d29b2c44Sab * v - Address of variable to receive resulting value. 317*d29b2c44Sab * 318*d29b2c44Sab * exit: 319*d29b2c44Sab * elfedit_atoi_range2() and elfedit_atoui_range2(): 320*d29b2c44Sab * On success, returns True (1) and *v is set to the value. 321*d29b2c44Sab * On failure, returns False (0) and *v is undefined. 322*d29b2c44Sab * 323*d29b2c44Sab * elfedit_atoi_range() and elfedit_atoui_range(): 324*d29b2c44Sab * If the string is convertable, the value is returned. 325*d29b2c44Sab * Otherwise an error is issued and this routine does 326*d29b2c44Sab * not return to the caller. 327*d29b2c44Sab */ 328*d29b2c44Sab int 329*d29b2c44Sab elfedit_atoi_range2(const char *str, elfedit_atoi_t min, elfedit_atoi_t max, 330*d29b2c44Sab const elfedit_atoi_sym_t *sym, elfedit_atoi_t *v) 331*d29b2c44Sab { 332*d29b2c44Sab return ((elfedit_atoi2(str, sym, v) != 0) && 333*d29b2c44Sab (*v >= min) && (*v <= max)); 334*d29b2c44Sab } 335*d29b2c44Sab elfedit_atoi_t 336*d29b2c44Sab elfedit_atoi_range(const char *str, const char *item_name, 337*d29b2c44Sab elfedit_atoi_t min, elfedit_atoi_t max, const elfedit_atoi_sym_t *sym) 338*d29b2c44Sab { 339*d29b2c44Sab elfedit_atoi_t v = elfedit_atoi(str, sym); 340*d29b2c44Sab 341*d29b2c44Sab if ((v < min) || (v > max)) 342*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ATOIRANGE), 343*d29b2c44Sab item_name, EC_XWORD(min), EC_XWORD(max), EC_XWORD(v)); 344*d29b2c44Sab 345*d29b2c44Sab return (v); 346*d29b2c44Sab } 347*d29b2c44Sab int 348*d29b2c44Sab elfedit_atoui_range2(const char *str, elfedit_atoui_t min, elfedit_atoui_t max, 349*d29b2c44Sab const elfedit_atoui_sym_t *sym, elfedit_atoui_t *v) 350*d29b2c44Sab { 351*d29b2c44Sab return ((elfedit_atoui2(str, sym, v) != 0) && 352*d29b2c44Sab (*v >= min) && (*v <= max)); 353*d29b2c44Sab } 354*d29b2c44Sab elfedit_atoui_t 355*d29b2c44Sab elfedit_atoui_range(const char *str, const char *item_name, 356*d29b2c44Sab elfedit_atoui_t min, elfedit_atoui_t max, const elfedit_atoui_sym_t *sym) 357*d29b2c44Sab { 358*d29b2c44Sab elfedit_atoui_t v = elfedit_atoui(str, sym); 359*d29b2c44Sab 360*d29b2c44Sab if ((v < min) || (v > max)) 361*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ATOUIRANGE), 362*d29b2c44Sab item_name, EC_XWORD(min), EC_XWORD(max), EC_XWORD(v)); 363*d29b2c44Sab 364*d29b2c44Sab return (v); 365*d29b2c44Sab } 366*d29b2c44Sab int 367*d29b2c44Sab elfedit_atoconst_range2(const char *str, elfedit_atoui_t min, 368*d29b2c44Sab elfedit_atoui_t max, elfedit_const_t const_type, elfedit_atoui_t *v) 369*d29b2c44Sab { 370*d29b2c44Sab return (elfedit_atoui_range2(str, min, max, 371*d29b2c44Sab elfedit_const_to_atoui(const_type), v)); 372*d29b2c44Sab } 373*d29b2c44Sab elfedit_atoui_t 374*d29b2c44Sab elfedit_atoconst_range(const char *str, const char *item_name, 375*d29b2c44Sab elfedit_atoui_t min, elfedit_atoui_t max, elfedit_const_t const_type) 376*d29b2c44Sab { 377*d29b2c44Sab return (elfedit_atoui_range(str, item_name, min, max, 378*d29b2c44Sab elfedit_const_to_atoui(const_type))); 379*d29b2c44Sab } 380*d29b2c44Sab 381*d29b2c44Sab 382*d29b2c44Sab /* 383*d29b2c44Sab * Convenience wrapper on elfedit_atoui_range() that expects to see 384*d29b2c44Sab * boolean values. Returns 1 for true, and 0 for false. 385*d29b2c44Sab */ 386*d29b2c44Sab int 387*d29b2c44Sab elfedit_atobool(const char *str, const char *item_name) 388*d29b2c44Sab { 389*d29b2c44Sab 390*d29b2c44Sab return (elfedit_atoconst_range(str, item_name, 0, 1, 391*d29b2c44Sab ELFEDIT_CONST_BOOL) != 0); 392*d29b2c44Sab } 393*d29b2c44Sab 394*d29b2c44Sab 395*d29b2c44Sab 396*d29b2c44Sab /* 397*d29b2c44Sab * Convenience wrapper on elfedit_atoui() to read a section index 398*d29b2c44Sab * that understands the special SHN_ names. 399*d29b2c44Sab * 400*d29b2c44Sab * entry: 401*d29b2c44Sab * str - String to process 402*d29b2c44Sab * shnum - Number of sections in the ELF file 403*d29b2c44Sab * 404*d29b2c44Sab * exit: 405*d29b2c44Sab * If it is possible to convert str to a number, that value 406*d29b2c44Sab * is returned. If the value is out of range for the file, 407*d29b2c44Sab * a warning message to that effect is issued. On failure, 408*d29b2c44Sab * an error is issued and this routine does not return to 409*d29b2c44Sab * the caller. 410*d29b2c44Sab */ 411*d29b2c44Sab elfedit_atoui_t 412*d29b2c44Sab elfedit_atoshndx(const char *str, size_t shnum) 413*d29b2c44Sab { 414*d29b2c44Sab elfedit_atoui_t ndx; 415*d29b2c44Sab 416*d29b2c44Sab ndx = elfedit_atoconst(str, ELFEDIT_CONST_SHN); 417*d29b2c44Sab if ((ndx >= shnum) && ((ndx < SHN_LORESERVE) || (ndx > SHN_HIRESERVE))) 418*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_SHNDX_RANGE), 419*d29b2c44Sab EC_WORD(ndx), EC_WORD(shnum-1)); 420*d29b2c44Sab 421*d29b2c44Sab return (ndx); 422*d29b2c44Sab } 423*d29b2c44Sab 424*d29b2c44Sab 425*d29b2c44Sab 426*d29b2c44Sab /* 427*d29b2c44Sab * Convert an output style string into it's integer constant. This 428*d29b2c44Sab * routine reports success/failure via the return value rather than 429*d29b2c44Sab * by throwing errors so that it can be used to process command 430*d29b2c44Sab * line options at program startup, before 431*d29b2c44Sab * the elfedit framework is initialized. 432*d29b2c44Sab */ 433*d29b2c44Sab int 434*d29b2c44Sab elfedit_atooutstyle(const char *str, elfedit_outstyle_t *outstyle) 435*d29b2c44Sab { 436*d29b2c44Sab int ret; 437*d29b2c44Sab elfedit_atoui_t value; 438*d29b2c44Sab 439*d29b2c44Sab ret = atoui_sym_process(str, 440*d29b2c44Sab elfedit_const_to_atoui(ELFEDIT_CONST_OUTSTYLE), &value); 441*d29b2c44Sab if (ret != 0) 442*d29b2c44Sab *outstyle = value; 443*d29b2c44Sab return (ret); 444*d29b2c44Sab } 445*d29b2c44Sab 446*d29b2c44Sab 447*d29b2c44Sab 448*d29b2c44Sab 449*d29b2c44Sab /* 450*d29b2c44Sab * Initialize a state block for processing by elfedit_getopt(). 451*d29b2c44Sab * 452*d29b2c44Sab * entry: 453*d29b2c44Sab * state - State block to initialize 454*d29b2c44Sab * cmd_name - NULL, or name of command for which we are processing 455*d29b2c44Sab * options. 456*d29b2c44Sab * argc, argv - Address of variables giving number of options and 457*d29b2c44Sab * access to the option strings. 458*d29b2c44Sab * 459*d29b2c44Sab * note: 460*d29b2c44Sab * cmd_name can only be set to NULL when this routine is called 461*d29b2c44Sab * by, or below, a currently active command. Otherwise, results 462*d29b2c44Sab * are undefined (crashing or corruption) if there isn't one. 463*d29b2c44Sab */ 464*d29b2c44Sab void 465*d29b2c44Sab elfedit_getopt_init(elfedit_getopt_state_t *state, 466*d29b2c44Sab int *argc, const char **argv[]) 467*d29b2c44Sab { 468*d29b2c44Sab elfeditGC_cmd_t *cmd = elfedit_curcmd(); 469*d29b2c44Sab 470*d29b2c44Sab state->go_argc = argc; 471*d29b2c44Sab state->go_argv = argv; 472*d29b2c44Sab state->go_optarg = cmd->cmd_opt; 473*d29b2c44Sab state->go_idmask = 0; 474*d29b2c44Sab state->go_done = 0; 475*d29b2c44Sab state->go_sglgrp = NULL; 476*d29b2c44Sab } 477*d29b2c44Sab 478*d29b2c44Sab 479*d29b2c44Sab 480*d29b2c44Sab /* 481*d29b2c44Sab * elfedit-centric version of getopt() 482*d29b2c44Sab * 483*d29b2c44Sab * entry: 484*d29b2c44Sab * state - Getopt state, which must have been previously initialized 485*d29b2c44Sab * via a call to elfedit_getopt_init. 486*d29b2c44Sab * 487*d29b2c44Sab * exit: 488*d29b2c44Sab * If an option is matched, this routine returns a pointer to an 489*d29b2c44Sab * elfedit_getopt_ret_t buffer (which comes from the storage used 490*d29b2c44Sab * for state). If there are no more options to process, NULL is returned. 491*d29b2c44Sab * 492*d29b2c44Sab * Syntax errors are reported via elfedit_command_usage(), and this 493*d29b2c44Sab * routine does not return to the caller. 494*d29b2c44Sab * 495*d29b2c44Sab * note: 496*d29b2c44Sab * - The caller should not access the contents of state directly. 497*d29b2c44Sab * Those contents are private, and subject to change. 498*d29b2c44Sab * - Once a call to this routine returns NULL, the argc/argv have 499*d29b2c44Sab * have been ajusted so that they reference the plain arguments. 500*d29b2c44Sab */ 501*d29b2c44Sab elfedit_getopt_ret_t * 502*d29b2c44Sab elfedit_getopt(elfedit_getopt_state_t *state) 503*d29b2c44Sab { 504*d29b2c44Sab elfedit_cmd_optarg_t *optarg; 505*d29b2c44Sab const char *argstr; 506*d29b2c44Sab int argc = *(state->go_argc); 507*d29b2c44Sab const char **argv = *(state->go_argv); 508*d29b2c44Sab elfedit_optarg_item_t item; 509*d29b2c44Sab struct { 510*d29b2c44Sab int valid; 511*d29b2c44Sab int is_outstyle; 512*d29b2c44Sab elfedit_getopt_ret_t ret; 513*d29b2c44Sab elfedit_cmd_oa_mask_t excmask; 514*d29b2c44Sab } sgl_with_value; 515*d29b2c44Sab 516*d29b2c44Sab if (state->go_sglgrp == NULL) { 517*d29b2c44Sab /* 518*d29b2c44Sab * Reasons to bail out immediately: 519*d29b2c44Sab * - The command does not accept options 520*d29b2c44Sab * - We've already reported the final option. 521*d29b2c44Sab * - There are no more arguments. 522*d29b2c44Sab * - The next argument does not start with '-' 523*d29b2c44Sab */ 524*d29b2c44Sab if ((state->go_optarg == NULL) || state->go_done || 525*d29b2c44Sab (argc <= 0) || (*(argv[0]) != '-')) { 526*d29b2c44Sab state->go_done = 1; 527*d29b2c44Sab return (NULL); 528*d29b2c44Sab } 529*d29b2c44Sab 530*d29b2c44Sab argstr = argv[0]; 531*d29b2c44Sab 532*d29b2c44Sab /* A '-' by itself is a syntax error */ 533*d29b2c44Sab if (argstr[1] == '\0') 534*d29b2c44Sab elfedit_command_usage(); 535*d29b2c44Sab 536*d29b2c44Sab /* A '--' option means we should stop at this point */ 537*d29b2c44Sab if ((argstr[1] == '-') && (argstr[2] == '\0')) { 538*d29b2c44Sab (*state->go_argc)--; 539*d29b2c44Sab (*state->go_argv)++; 540*d29b2c44Sab return (NULL); 541*d29b2c44Sab } 542*d29b2c44Sab 543*d29b2c44Sab /* 544*d29b2c44Sab * We have a string that starts with a '-'. 545*d29b2c44Sab * Does it match an option? 546*d29b2c44Sab */ 547*d29b2c44Sab sgl_with_value.valid = 0; 548*d29b2c44Sab for (optarg = state->go_optarg; optarg->oa_name != NULL; ) { 549*d29b2c44Sab int is_outstyle = 550*d29b2c44Sab (optarg->oa_flags & ELFEDIT_CMDOA_F_INHERIT) && 551*d29b2c44Sab (optarg->oa_name == ELFEDIT_STDOA_OPT_O); 552*d29b2c44Sab int need_value; 553*d29b2c44Sab 554*d29b2c44Sab elfedit_next_optarg(&optarg, &item); 555*d29b2c44Sab need_value = item.oai_flags & ELFEDIT_CMDOA_F_VALUE; 556*d29b2c44Sab 557*d29b2c44Sab /* 558*d29b2c44Sab * If the option is a single letter that accepts 559*d29b2c44Sab * a value, then we allow the combined syntax 560*d29b2c44Sab * -ovalue, where no space is reqired between the 561*d29b2c44Sab * option flag and the value string. 562*d29b2c44Sab */ 563*d29b2c44Sab if ((item.oai_name[2] == '\0') && need_value && 564*d29b2c44Sab (argstr[1] == item.oai_name[1]) && 565*d29b2c44Sab (argstr[2] != '\0')) { 566*d29b2c44Sab /* 567*d29b2c44Sab * We have a match. However, there may also 568*d29b2c44Sab * be a straightforward match that we have 569*d29b2c44Sab * not yet found. If so, we want to prefer that 570*d29b2c44Sab * case over this one. So rather than return 571*d29b2c44Sab * it immediately, we capture the information 572*d29b2c44Sab * and keep looking. If nothing else surfaces, 573*d29b2c44Sab * we'll use this later. 574*d29b2c44Sab */ 575*d29b2c44Sab sgl_with_value.valid = 1; 576*d29b2c44Sab sgl_with_value.ret.gor_idmask = item.oai_idmask; 577*d29b2c44Sab sgl_with_value.excmask = item.oai_excmask; 578*d29b2c44Sab sgl_with_value.ret.gor_value = argstr + 2; 579*d29b2c44Sab sgl_with_value.is_outstyle = is_outstyle; 580*d29b2c44Sab continue; 581*d29b2c44Sab } 582*d29b2c44Sab 583*d29b2c44Sab /* Try for a straightforward match */ 584*d29b2c44Sab if (strcmp(argstr, item.oai_name) == 0) { 585*d29b2c44Sab (*state->go_argc) = --argc; 586*d29b2c44Sab (*state->go_argv) = ++argv; 587*d29b2c44Sab 588*d29b2c44Sab /* Mutually exclusive option already seen? */ 589*d29b2c44Sab if (item.oai_excmask & state->go_idmask) 590*d29b2c44Sab elfedit_command_usage(); 591*d29b2c44Sab 592*d29b2c44Sab /* Return the match */ 593*d29b2c44Sab state->go_idmask |= item.oai_idmask; 594*d29b2c44Sab state->go_ret.gor_idmask = item.oai_idmask; 595*d29b2c44Sab if (need_value) { 596*d29b2c44Sab /* If out of args, syntax error */ 597*d29b2c44Sab if (argc <= 0) 598*d29b2c44Sab elfedit_command_usage(); 599*d29b2c44Sab state->go_ret.gor_value = argv[0]; 600*d29b2c44Sab (*state->go_argc)--; 601*d29b2c44Sab (*state->go_argv)++; 602*d29b2c44Sab } else { 603*d29b2c44Sab state->go_ret.gor_value = NULL; 604*d29b2c44Sab } 605*d29b2c44Sab if (is_outstyle) 606*d29b2c44Sab elfedit_set_cmd_outstyle( 607*d29b2c44Sab state->go_ret.gor_value); 608*d29b2c44Sab return (&state->go_ret); 609*d29b2c44Sab } 610*d29b2c44Sab } 611*d29b2c44Sab 612*d29b2c44Sab /* 613*d29b2c44Sab * No straightforward matches: Did we get a match with 614*d29b2c44Sab * the special single letter and combined value? If so 615*d29b2c44Sab * return that now. 616*d29b2c44Sab */ 617*d29b2c44Sab if (sgl_with_value.valid) { 618*d29b2c44Sab (*state->go_argc)--; 619*d29b2c44Sab (*state->go_argv)++; 620*d29b2c44Sab 621*d29b2c44Sab /* Mutually exclusive option already seen? */ 622*d29b2c44Sab if (sgl_with_value.excmask & state->go_idmask) 623*d29b2c44Sab elfedit_command_usage(); 624*d29b2c44Sab 625*d29b2c44Sab state->go_idmask |= sgl_with_value.ret.gor_idmask; 626*d29b2c44Sab state->go_ret = sgl_with_value.ret; 627*d29b2c44Sab if (sgl_with_value.is_outstyle) 628*d29b2c44Sab elfedit_set_cmd_outstyle( 629*d29b2c44Sab state->go_ret.gor_value); 630*d29b2c44Sab 631*d29b2c44Sab return (&state->go_ret); 632*d29b2c44Sab } 633*d29b2c44Sab 634*d29b2c44Sab /* 635*d29b2c44Sab * If nothing above matched, make this option the single 636*d29b2c44Sab * group string and see if the characters in it all match 637*d29b2c44Sab * as single letter options without values. 638*d29b2c44Sab */ 639*d29b2c44Sab state->go_sglgrp = argstr + 1; /* Skip '-' */ 640*d29b2c44Sab } 641*d29b2c44Sab 642*d29b2c44Sab /* 643*d29b2c44Sab * If there is a single group string, take the first character 644*d29b2c44Sab * and try to match it to an 1-letter option that does not 645*d29b2c44Sab * require a value. 646*d29b2c44Sab */ 647*d29b2c44Sab if (state->go_sglgrp != NULL) { 648*d29b2c44Sab int ch = *state->go_sglgrp++; 649*d29b2c44Sab 650*d29b2c44Sab /* If that is the last character, clear single group mode */ 651*d29b2c44Sab if (*state->go_sglgrp == '\0') { 652*d29b2c44Sab (*state->go_argc)--; 653*d29b2c44Sab (*state->go_argv)++; 654*d29b2c44Sab state->go_sglgrp = NULL; 655*d29b2c44Sab } 656*d29b2c44Sab 657*d29b2c44Sab for (optarg = state->go_optarg; optarg->oa_name != NULL; ) { 658*d29b2c44Sab elfedit_next_optarg(&optarg, &item); 659*d29b2c44Sab 660*d29b2c44Sab if ((item.oai_name[2] == '\0') && 661*d29b2c44Sab (ch == item.oai_name[1])) { 662*d29b2c44Sab /* 663*d29b2c44Sab * It matches. If the option requires a value 664*d29b2c44Sab * then it cannot be in a group. 665*d29b2c44Sab */ 666*d29b2c44Sab if (item.oai_flags & ELFEDIT_CMDOA_F_VALUE) 667*d29b2c44Sab elfedit_command_usage(); 668*d29b2c44Sab 669*d29b2c44Sab /* Mutually exclusive option already seen? */ 670*d29b2c44Sab if (item.oai_excmask & state->go_idmask) 671*d29b2c44Sab elfedit_command_usage(); 672*d29b2c44Sab 673*d29b2c44Sab /* Return the match */ 674*d29b2c44Sab state->go_idmask |= item.oai_idmask; 675*d29b2c44Sab state->go_ret.gor_idmask = item.oai_idmask; 676*d29b2c44Sab state->go_ret.gor_value = NULL; 677*d29b2c44Sab return (&state->go_ret); 678*d29b2c44Sab } 679*d29b2c44Sab } 680*d29b2c44Sab } 681*d29b2c44Sab 682*d29b2c44Sab /* Nothing matched. We have a syntax error */ 683*d29b2c44Sab elfedit_command_usage(); 684*d29b2c44Sab /*NOTREACHED*/ 685*d29b2c44Sab return (NULL); 686*d29b2c44Sab } 687*d29b2c44Sab 688*d29b2c44Sab 689*d29b2c44Sab /* 690*d29b2c44Sab * Return the count of non-zero bits in the value v. 691*d29b2c44Sab * 692*d29b2c44Sab * entry: 693*d29b2c44Sab * v - Value to test 694*d29b2c44Sab * sizeof_orig_v - The result of using the sizeof operator 695*d29b2c44Sab * on the original value of v. The value received 696*d29b2c44Sab * by this routine has been cast to an unsigned 64-bit 697*d29b2c44Sab * integer, so having the caller use sizeof allows us to 698*d29b2c44Sab * avoid testing bits that were not in the original. 699*d29b2c44Sab */ 700*d29b2c44Sab int 701*d29b2c44Sab elfedit_bits_set(u_longlong_t v, int sizeof_orig_v) 702*d29b2c44Sab { 703*d29b2c44Sab int nbits = sizeof_orig_v * 8; 704*d29b2c44Sab int mask; 705*d29b2c44Sab int cnt = 0; 706*d29b2c44Sab 707*d29b2c44Sab for (mask = 1; (nbits-- > 0) && (cnt < 2); mask *= 2) 708*d29b2c44Sab if (v & mask) 709*d29b2c44Sab cnt++; 710*d29b2c44Sab 711*d29b2c44Sab return (cnt); 712*d29b2c44Sab } 713*d29b2c44Sab 714*d29b2c44Sab 715*d29b2c44Sab /* 716*d29b2c44Sab * "delete" items in an array by copying the following items up 717*d29b2c44Sab * over the "deleted" items and then zero filling the vacated 718*d29b2c44Sab * slots at the bottom. 719*d29b2c44Sab * 720*d29b2c44Sab * entry: 721*d29b2c44Sab * name_str - Array identification prefix to use for debug message 722*d29b2c44Sab * data_start - Address of 1st byte in array 723*d29b2c44Sab * entsize - sizeof a single element of the array 724*d29b2c44Sab * num_ent - # of elements in array 725*d29b2c44Sab * start_ndx - Index of first item to be deleted 726*d29b2c44Sab * cnt - # of items to delete 727*d29b2c44Sab * 728*d29b2c44Sab * exit: 729*d29b2c44Sab * Any errors are issued and control does not return to the 730*d29b2c44Sab * caller. On success, the items have been removed, zero filling 731*d29b2c44Sab * has been done, and debug messages issued. 732*d29b2c44Sab */ 733*d29b2c44Sab void 734*d29b2c44Sab elfedit_array_elts_delete(const char *name_str, void *data_start, 735*d29b2c44Sab size_t entsize, size_t num_ent, size_t start_ndx, size_t cnt) 736*d29b2c44Sab { 737*d29b2c44Sab char *data = data_start; 738*d29b2c44Sab 739*d29b2c44Sab /* The specified index and range must be in bounds */ 740*d29b2c44Sab if ((start_ndx + cnt) > num_ent) 741*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ARRBNDS), 742*d29b2c44Sab name_str, EC_WORD(num_ent), EC_WORD(num_ent - 1)); 743*d29b2c44Sab 744*d29b2c44Sab /* 745*d29b2c44Sab * Everything below the deleted items moves up. 746*d29b2c44Sab * Note that bcopy() is documented to handle overlapping 747*d29b2c44Sab * src/dst correctly, so we make no effort to handle this 748*d29b2c44Sab * element by element, but issue a single operation. 749*d29b2c44Sab * 750*d29b2c44Sab * If we're doing the last element, there is nothing to 751*d29b2c44Sab * move up, and we skip this step, moving on to the zeroing below. 752*d29b2c44Sab */ 753*d29b2c44Sab if (start_ndx < (num_ent - 1)) { 754*d29b2c44Sab size_t ncpy = num_ent - (start_ndx + cnt); 755*d29b2c44Sab 756*d29b2c44Sab bcopy(data + ((start_ndx + cnt) * entsize), 757*d29b2c44Sab data + (start_ndx * entsize), ncpy * entsize); 758*d29b2c44Sab if (ncpy == 1) { 759*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG, 760*d29b2c44Sab MSG_INTL(MSG_DEBUG_ARRCPY_1), name_str, 761*d29b2c44Sab EC_WORD(start_ndx + cnt), EC_WORD(start_ndx)); 762*d29b2c44Sab } else { 763*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG, 764*d29b2c44Sab MSG_INTL(MSG_DEBUG_ARRCPY_N), name_str, 765*d29b2c44Sab EC_WORD(start_ndx + cnt), 766*d29b2c44Sab EC_WORD(start_ndx + cnt + ncpy - 1), 767*d29b2c44Sab EC_WORD(start_ndx), 768*d29b2c44Sab EC_WORD(start_ndx + ncpy - 1)); 769*d29b2c44Sab } 770*d29b2c44Sab } 771*d29b2c44Sab 772*d29b2c44Sab /* Zero out the vacated elements at the end */ 773*d29b2c44Sab bzero(data + ((num_ent - cnt) * entsize), entsize * cnt); 774*d29b2c44Sab 775*d29b2c44Sab if (cnt == 1) { 776*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRZERO_1), 777*d29b2c44Sab name_str, EC_WORD(num_ent - 1)); 778*d29b2c44Sab } else { 779*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRZERO_N), 780*d29b2c44Sab name_str, EC_WORD(num_ent - cnt), 781*d29b2c44Sab EC_WORD(num_ent - 1), EC_WORD(cnt)); 782*d29b2c44Sab } 783*d29b2c44Sab } 784*d29b2c44Sab 785*d29b2c44Sab 786*d29b2c44Sab /* 787*d29b2c44Sab * move the location of items in an array by shifting the surround 788*d29b2c44Sab * items into the vacated hole and them putting the values into 789*d29b2c44Sab * the new location. 790*d29b2c44Sab * 791*d29b2c44Sab * entry: 792*d29b2c44Sab * name_str - Array identification prefix to use for debug message 793*d29b2c44Sab * data_start - Address of 1st byte in array 794*d29b2c44Sab * entsize - sizeof a single element of the array 795*d29b2c44Sab * num_ent - # of elements in array 796*d29b2c44Sab * start_ndx - Index of first item to be moved 797*d29b2c44Sab * dst_ndx - Index to receive the moved block 798*d29b2c44Sab * cnt - # of items to move 799*d29b2c44Sab * scr_item - Space allocated by the caller sufficient to hold 800*d29b2c44Sab * one item from the array. Used to swap elements. 801*d29b2c44Sab * 802*d29b2c44Sab * exit: 803*d29b2c44Sab * Any errors are issued and control does not return to the 804*d29b2c44Sab * caller. On success, the items have been moved, and debug 805*d29b2c44Sab * messages issued. 806*d29b2c44Sab */ 807*d29b2c44Sab void 808*d29b2c44Sab elfedit_array_elts_move(const char *name_str, void *data_start, 809*d29b2c44Sab size_t entsize, size_t num_ent, size_t srcndx, 810*d29b2c44Sab size_t dstndx, size_t cnt, void *scr_item) 811*d29b2c44Sab { 812*d29b2c44Sab char *data = data_start; 813*d29b2c44Sab 814*d29b2c44Sab /* The specified source and destination ranges must be in bounds */ 815*d29b2c44Sab if (((srcndx + cnt) > num_ent) || ((dstndx + cnt) > num_ent)) 816*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ARRBNDS), 817*d29b2c44Sab name_str, EC_WORD(num_ent), EC_WORD(num_ent - 1)); 818*d29b2c44Sab 819*d29b2c44Sab /* If source and destination are same, there's nothing to do */ 820*d29b2c44Sab if (srcndx == dstndx) 821*d29b2c44Sab return; 822*d29b2c44Sab 823*d29b2c44Sab /* 824*d29b2c44Sab * It is meaningless to do a move where the source and destination 825*d29b2c44Sab * are overlapping, because this "move" amounts to shifting 826*d29b2c44Sab * the existing items around into a new position. If there is 827*d29b2c44Sab * more than one element, then overlap is possible and we need 828*d29b2c44Sab * to test for it. 829*d29b2c44Sab */ 830*d29b2c44Sab if (cnt > 1) { 831*d29b2c44Sab size_t low, hi; 832*d29b2c44Sab 833*d29b2c44Sab if (srcndx > dstndx) { 834*d29b2c44Sab low = dstndx; 835*d29b2c44Sab hi = srcndx; 836*d29b2c44Sab } else { 837*d29b2c44Sab low = srcndx; 838*d29b2c44Sab hi = dstndx; 839*d29b2c44Sab } 840*d29b2c44Sab /* Ensure that the src and dst don't overlap */ 841*d29b2c44Sab if ((low + cnt) > hi) 842*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_ERR, 843*d29b2c44Sab MSG_INTL(MSG_ERR_ARRMVOVERLAP), name_str, 844*d29b2c44Sab EC_WORD(srcndx), EC_WORD(srcndx + cnt - 1), 845*d29b2c44Sab EC_WORD(dstndx), EC_WORD(dstndx + cnt - 1)); 846*d29b2c44Sab } 847*d29b2c44Sab 848*d29b2c44Sab if (cnt == 1) 849*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRMOVE_1), 850*d29b2c44Sab name_str, EC_WORD(srcndx), EC_WORD(dstndx)); 851*d29b2c44Sab else 852*d29b2c44Sab elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRMOVE_N), 853*d29b2c44Sab name_str, EC_WORD(cnt), 854*d29b2c44Sab EC_WORD(srcndx), EC_WORD(srcndx + cnt - 1), 855*d29b2c44Sab EC_WORD(dstndx), EC_WORD(dstndx + cnt - 1)); 856*d29b2c44Sab 857*d29b2c44Sab if (srcndx < dstndx) { 858*d29b2c44Sab srcndx += cnt - 1; 859*d29b2c44Sab dstndx += cnt - 1; 860*d29b2c44Sab for (; cnt-- > 0; srcndx--, dstndx--) { 861*d29b2c44Sab /* 862*d29b2c44Sab * Copy item at srcndx to scratch location 863*d29b2c44Sab * 864*d29b2c44Sab * save = dyn[srcndx]; 865*d29b2c44Sab */ 866*d29b2c44Sab bcopy(data + (srcndx * entsize), scr_item, entsize); 867*d29b2c44Sab 868*d29b2c44Sab /* 869*d29b2c44Sab * Shift items after source up through destination 870*d29b2c44Sab * to source. bcopy() handles overlapped copies. 871*d29b2c44Sab * 872*d29b2c44Sab * for (i = srcndx; i < dstndx; i++) 873*d29b2c44Sab * dyn[i] = dyn[i + 1]; 874*d29b2c44Sab */ 875*d29b2c44Sab bcopy(data + ((srcndx + 1) * entsize), 876*d29b2c44Sab data + (srcndx * entsize), 877*d29b2c44Sab (dstndx - srcndx) * entsize); 878*d29b2c44Sab 879*d29b2c44Sab /* 880*d29b2c44Sab * Copy saved item into destination slot 881*d29b2c44Sab * 882*d29b2c44Sab * dyn[dstndx] = save; 883*d29b2c44Sab */ 884*d29b2c44Sab bcopy(scr_item, data + (dstndx * entsize), entsize); 885*d29b2c44Sab } 886*d29b2c44Sab } else { 887*d29b2c44Sab for (; cnt-- > 0; srcndx++, dstndx++) { 888*d29b2c44Sab /* 889*d29b2c44Sab * Copy item at srcndx to scratch location 890*d29b2c44Sab * 891*d29b2c44Sab * save = dyn[srcndx]; 892*d29b2c44Sab */ 893*d29b2c44Sab bcopy(data + (srcndx * entsize), scr_item, entsize); 894*d29b2c44Sab 895*d29b2c44Sab /* 896*d29b2c44Sab * Shift items from destination through item below 897*d29b2c44Sab * source up one. bcopy() handles overlapped copies. 898*d29b2c44Sab * 899*d29b2c44Sab * for (i = srcndx; i > dstndx; i--) 900*d29b2c44Sab * dyn[i] = dyn[i - 1]; 901*d29b2c44Sab */ 902*d29b2c44Sab bcopy(data + (dstndx * entsize), 903*d29b2c44Sab data + ((dstndx + 1) * entsize), 904*d29b2c44Sab (srcndx - dstndx) * entsize); 905*d29b2c44Sab 906*d29b2c44Sab /* 907*d29b2c44Sab * Copy saved item into destination slot 908*d29b2c44Sab * 909*d29b2c44Sab * dyn[dstndx] = save; 910*d29b2c44Sab */ 911*d29b2c44Sab bcopy(scr_item, data + (dstndx * entsize), entsize); 912*d29b2c44Sab } 913*d29b2c44Sab } 914*d29b2c44Sab } 915