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