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