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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright(c) 1988 AT&T 24 * All Rights Reserved 25 * 26 */ 27 28 /* 29 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 30 * Use is subject to license terms. 31 */ 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 35 #include "mcs.h" 36 #include "extern.h" 37 #include "gelf.h" 38 39 /* 40 * Function prototypes. 41 */ 42 static void docompress(section_info_table *); 43 static char *compress(char *, size_t *); 44 static void doappend(char *, section_info_table *); 45 static void doprint(char *, section_info_table *); 46 static void dozap(section_info_table *); 47 static int dohash(char *); 48 49 50 51 /* 52 * Apply the actions specified by the user. 53 */ 54 int 55 apply_action(section_info_table *info, char *cur_file, Cmd_Info *cmd_info) 56 { 57 int act_index; 58 int ret = 0; 59 GElf_Shdr shdr; 60 61 (void) gelf_getshdr(info->scn, &shdr); 62 for (act_index = 0; act_index < actmax; act_index++) { 63 Action[act_index].a_cnt++; 64 switch (Action[act_index].a_action) { 65 case ACT_ZAP: 66 if (GET_ACTION(info->flags) == ACT_DELETE) 67 break; 68 dozap(info); 69 SET_ACTION(info->flags, ACT_ZAP); 70 SET_MODIFIED(info->flags); 71 break; 72 case ACT_PRINT: 73 if (GET_ACTION(info->flags) == ACT_DELETE) 74 break; 75 if (shdr.sh_type == SHT_NOBITS) { 76 error_message(ACT_PRINT_ERROR, 77 PLAIN_ERROR, (char *)0, 78 prog, cur_file, SECT_NAME); 79 break; 80 } 81 doprint(cur_file, info); 82 break; 83 case ACT_DELETE: 84 /* 85 * If I am strip command, this is the 86 * only action I can take. 87 */ 88 if (GET_ACTION(info->flags) == ACT_DELETE) 89 break; 90 if (GET_LOC(info->flags) == IN) { 91 /* 92 * If I am 'strip', I have to 93 * unset the candidate flag and 94 * unset the error return code. 95 */ 96 if (CHK_OPT(info, I_AM_STRIP)) { 97 ret = 0; 98 UNSET_CANDIDATE(info->flags); 99 } else { 100 ret++; 101 error_message(ACT_DELETE1_ERROR, 102 PLAIN_ERROR, (char *)0, 103 prog, cur_file, info->name); 104 } 105 break; 106 } else if (info->rel_loc == IN) { 107 /* 108 * If I am 'strip', I have to 109 * unset the candidate flag and 110 * unset the error return code. 111 */ 112 if (CHK_OPT(info, I_AM_STRIP)) { 113 ret = 0; 114 UNSET_CANDIDATE(info->flags); 115 } else { 116 ret++; 117 error_message(ACT_DELETE2_ERROR, 118 PLAIN_ERROR, (char *)0, 119 prog, cur_file, SECT_NAME, 120 info->rel_name); 121 } 122 break; 123 } else if (GET_LOC(info->flags) == PRIOR) { 124 /* 125 * I can not delete this 126 * section. I can only NULL 127 * this out. 128 */ 129 info->secno = (GElf_Word)NULLED; 130 (cmd_info->no_of_nulled)++; 131 } else { 132 info->secno = (GElf_Word)DELETED; 133 (cmd_info->no_of_delete)++; 134 } 135 SET_ACTION(info->flags, ACT_DELETE); 136 SET_MODIFIED(info->flags); 137 break; 138 case ACT_APPEND: 139 if (shdr.sh_type == SHT_NOBITS) { 140 ret++; 141 error_message(ACT_APPEND1_ERROR, 142 PLAIN_ERROR, (char *)0, 143 prog, cur_file, SECT_NAME); 144 break; 145 } else if (GET_LOC(info->flags) == IN) { 146 ret++; 147 error_message(ACT_APPEND2_ERROR, 148 PLAIN_ERROR, (char *)0, 149 prog, cur_file, SECT_NAME); 150 break; 151 } 152 doappend(Action[act_index].a_string, info); 153 (cmd_info->no_of_append)++; 154 info->secno = info->osecno; 155 SET_ACTION(info->flags, ACT_APPEND); 156 SET_MODIFIED(info->flags); 157 if (GET_LOC(info->flags) == PRIOR) 158 info->secno = (GElf_Word)EXPANDED; 159 break; 160 case ACT_COMPRESS: 161 /* 162 * If this section is already deleted, 163 * don't do anything. 164 */ 165 if (GET_ACTION(info->flags) == ACT_DELETE) 166 break; 167 if (shdr.sh_type == SHT_NOBITS) { 168 ret++; 169 error_message(ACT_COMPRESS1_ERROR, 170 PLAIN_ERROR, (char *)0, 171 prog, cur_file, SECT_NAME); 172 break; 173 } else if (GET_LOC(info->flags) == IN) { 174 ret++; 175 error_message(ACT_COMPRESS2_ERROR, 176 PLAIN_ERROR, (char *)0, 177 prog, cur_file, SECT_NAME); 178 break; 179 } 180 181 docompress(info); 182 (cmd_info->no_of_compressed)++; 183 SET_ACTION(info->flags, ACT_COMPRESS); 184 SET_MODIFIED(info->flags); 185 if (GET_LOC(info->flags) == PRIOR) 186 info->secno = (GElf_Word)SHRUNK; 187 break; 188 } 189 } 190 return (ret); 191 } 192 193 /* 194 * ACT_ZAP 195 */ 196 static void 197 dozap(section_info_table *info) 198 { 199 Elf_Data *data; 200 201 info->mdata = data = malloc(sizeof (Elf_Data)); 202 if (data == NULL) { 203 error_message(MALLOC_ERROR, 204 PLAIN_ERROR, (char *)0, 205 prog); 206 exit(1); 207 } 208 *data = *info->data; 209 data->d_buf = calloc(1, data->d_size); 210 if (data->d_buf == NULL) { 211 error_message(MALLOC_ERROR, 212 PLAIN_ERROR, (char *)0, 213 prog); 214 exit(1); 215 } 216 } 217 218 /* 219 * ACT_PRINT 220 */ 221 static void 222 doprint(char *cur_file, section_info_table *info) 223 { 224 Elf_Data *data; 225 size_t temp_size; 226 char *temp_string; 227 228 if (GET_MODIFIED(info->flags) == 0) 229 data = info->data; 230 else 231 data = info->mdata; 232 if (data == 0) 233 return; 234 235 temp_size = data->d_size; 236 temp_string = data->d_buf; 237 238 if (temp_size == 0) 239 return; 240 (void) fprintf(stdout, "%s:\n", cur_file); 241 242 while (temp_size--) { 243 char c = *temp_string++; 244 switch (c) { 245 case '\0': 246 (void) putchar('\n'); 247 break; 248 default: 249 (void) putchar(c); 250 break; 251 } 252 } 253 (void) putchar('\n'); 254 } 255 256 /* 257 * ACT_APPEND 258 */ 259 static void 260 doappend(char *a_string, section_info_table *info) 261 { 262 Elf_Data *data; 263 char *p; 264 size_t len; 265 char *tp; 266 267 /* 268 * Get the length of the string to be added. We accept any 269 * string (even null), as this is arbitrary user defined text. 270 * 271 * The caller expects this routine to replace a NULL info->mdata 272 * field with a pointer to a freshly allocated copy. Any attempt 273 * to optimize away a null string append would have to deal with 274 * that, as failing to do so will cause a segfault when the NULL 275 * mdata field is dereferenced. Accepting null strings in 276 * this very unimportant case eliminates the need for that. 277 */ 278 len = strlen(a_string); 279 280 /* 281 * Every modification operation will be done 282 * to a new Elf_Data descriptor. 283 */ 284 if (info->mdata == 0) { 285 /* 286 * mdata is not allocated yet. 287 * Allocate the data and set it. 288 */ 289 info->mdata = data = calloc(1, sizeof (Elf_Data)); 290 if (data == NULL) { 291 error_message(MALLOC_ERROR, 292 PLAIN_ERROR, (char *)0, 293 prog); 294 exit(1); 295 } 296 *data = *info->data; 297 298 /* 299 * Check if the section is deleted or not. 300 * Or if the size is 0 or not. 301 */ 302 if ((GET_ACTION(info->flags) == ACT_DELETE) || 303 data->d_size == 0) { 304 /* 305 * The section was deleated. 306 * But now, the user wants to add data to this 307 * section. 308 */ 309 data->d_buf = calloc(1, len + 2); 310 if (data->d_buf == 0) { 311 error_message(MALLOC_ERROR, 312 PLAIN_ERROR, (char *)0, 313 prog); 314 exit(1); 315 } 316 tp = (char *)data->d_buf; 317 (void) memcpy(& tp[1], a_string, len + 1); 318 data->d_size = len + 2; 319 } else { 320 /* 321 * The user wants to add data to the section. 322 * I am not going to change the original data. 323 * Do the modification on the new one. 324 */ 325 p = malloc(len + 1 + data->d_size); 326 if (p == NULL) { 327 error_message(MALLOC_ERROR, 328 PLAIN_ERROR, (char *)0, 329 prog); 330 exit(1); 331 } 332 (void) memcpy(p, data->d_buf, data->d_size); 333 (void) memcpy(&p[data->d_size], a_string, len + 1); 334 data->d_buf = p; 335 data->d_size = data->d_size + len + 1; 336 } 337 } else { 338 /* 339 * mdata is already allocated. 340 * Modify it. 341 */ 342 data = info->mdata; 343 if ((GET_ACTION(info->flags) == ACT_DELETE) || 344 data->d_size == 0) { 345 /* 346 * The section was deleated. 347 * But now, the user wants to add data to this 348 * section. 349 */ 350 if (data->d_buf) 351 free(data->d_buf); 352 data->d_buf = calloc(1, len + 2); 353 if (data->d_buf == 0) { 354 error_message(MALLOC_ERROR, 355 PLAIN_ERROR, (char *)0, 356 prog); 357 exit(1); 358 } 359 tp = (char *)data->d_buf; 360 (void) memcpy(&tp[1], a_string, len + 1); 361 data->d_size = len + 2; 362 } else { 363 /* 364 * The user wants to add data to the section. 365 * I am not going to change the original data. 366 * Do the modification on the new one. 367 */ 368 p = malloc(len + 1 + data->d_size); 369 if (p == NULL) { 370 error_message(MALLOC_ERROR, 371 PLAIN_ERROR, (char *)0, 372 prog); 373 exit(1); 374 } 375 (void) memcpy(p, data->d_buf, data->d_size); 376 (void) memcpy(&p[data->d_size], a_string, len + 1); 377 free(data->d_buf); 378 data->d_buf = p; 379 data->d_size = data->d_size + len + 1; 380 } 381 } 382 } 383 384 /* 385 * ACT_COMPRESS 386 */ 387 #define HALFLONG 16 388 #define low(x) (x&((1L<<HALFLONG)-1)) 389 #define high(x) (x>>HALFLONG) 390 391 static void 392 docompress(section_info_table *info) 393 { 394 Elf_Data *data; 395 size_t size; 396 char *buf; 397 398 if (info->mdata == 0) { 399 /* 400 * mdata is not allocated yet. 401 * Allocate the data and set it. 402 */ 403 char *p; 404 info->mdata = data = calloc(1, sizeof (Elf_Data)); 405 if (data == NULL) { 406 error_message(MALLOC_ERROR, 407 PLAIN_ERROR, (char *)0, 408 prog); 409 exit(1); 410 } 411 *data = *info->data; 412 p = malloc(data->d_size); 413 (void) memcpy(p, (char *)data->d_buf, data->d_size); 414 data->d_buf = p; 415 } 416 size = info->mdata->d_size; 417 buf = (char *)info->mdata->d_buf; 418 buf = compress(buf, &size); 419 info->mdata->d_buf = buf; 420 info->mdata->d_size = size; 421 } 422 423 static char * 424 compress(char *str, size_t *size) 425 { 426 int hash; 427 int i; 428 size_t temp_string_size = 0; 429 size_t o_size = *size; 430 char *temp_string = str; 431 432 int *hash_key; 433 size_t hash_num; 434 size_t hash_end; 435 size_t *hash_str; 436 char *strings; 437 size_t next_str; 438 size_t str_size; 439 440 hash_key = malloc(sizeof (int) * 200); 441 hash_end = 200; 442 hash_str = malloc(sizeof (size_t) * 200); 443 str_size = o_size+1; 444 strings = malloc(str_size); 445 446 if (hash_key == NULL || hash_str == NULL || strings == NULL) { 447 error_message(MALLOC_ERROR, 448 PLAIN_ERROR, (char *)0, 449 prog); 450 mcs_exit(FAILURE); 451 } 452 453 hash_num = 0; 454 next_str = 0; 455 456 while (temp_string_size < o_size) { 457 size_t pos; 458 char c; 459 /* 460 * Get a string 461 */ 462 pos = next_str; 463 464 while ((c = *(temp_string++)) != '\0' && 465 (temp_string_size + (next_str - pos)) <= o_size) { 466 if (next_str >= str_size) { 467 str_size *= 2; 468 if ((strings = (char *) 469 realloc(strings, str_size)) == NULL) { 470 error_message(MALLOC_ERROR, 471 PLAIN_ERROR, (char *)0, 472 prog); 473 mcs_exit(FAILURE); 474 } 475 } 476 strings[next_str++] = c; 477 } 478 479 if (next_str >= str_size) { 480 str_size *= 2; 481 if ((strings = (char *) 482 realloc(strings, str_size)) == NULL) { 483 error_message(MALLOC_ERROR, 484 PLAIN_ERROR, (char *)0, 485 prog); 486 mcs_exit(FAILURE); 487 } 488 } 489 strings[next_str++] = NULL; 490 /* 491 * End get string 492 */ 493 494 temp_string_size += (next_str - pos); 495 hash = dohash(pos + strings); 496 for (i = 0; i < hash_num; i++) { 497 if (hash != hash_key[i]) 498 continue; 499 if (strcmp(pos + strings, hash_str[i] + strings) == 0) 500 break; 501 } 502 if (i != hash_num) { 503 next_str = pos; 504 continue; 505 } 506 if (hash_num == hash_end) { 507 hash_end *= 2; 508 hash_key = realloc((char *)hash_key, 509 hash_end * sizeof (int)); 510 hash_str = realloc((char *)hash_str, 511 hash_end * sizeof (size_t)); 512 if (hash_key == NULL || hash_str == NULL) { 513 error_message(MALLOC_ERROR, 514 PLAIN_ERROR, (char *)0, 515 prog); 516 mcs_exit(FAILURE); 517 } 518 } 519 hash_key[hash_num] = hash; 520 hash_str[hash_num++] = pos; 521 } 522 523 /* 524 * Clean up 525 */ 526 free(hash_key); 527 free(hash_str); 528 529 /* 530 * Return 531 */ 532 if (next_str != o_size) { 533 /* 534 * string compressed. 535 */ 536 *size = next_str; 537 free(str); 538 str = malloc(next_str); 539 (void) memcpy(str, strings, next_str); 540 } 541 free(strings); 542 return (str); 543 } 544 545 static int 546 dohash(char *str) 547 { 548 long sum; 549 unsigned shift; 550 int t; 551 sum = 1; 552 for (shift = 0; (t = *str++) != NULL; shift += 7) { 553 sum += (long)t << (shift %= HALFLONG); 554 } 555 sum = low(sum) + high(sum); 556 /* LINTED */ 557 return ((short)low(sum) + (short)high(sum)); 558 } 559 560 /* 561 * Append an item to the specified list, and return a pointer to the list 562 * node created. 563 */ 564 Listnode * 565 list_appendc(List *lst, const void *item) 566 { 567 Listnode *_lnp; 568 569 if ((_lnp = malloc(sizeof (Listnode))) == (Listnode *)0) 570 return (0); 571 572 _lnp->data = (void *)item; 573 _lnp->next = NULL; 574 575 if (lst->head == NULL) 576 lst->tail = lst->head = _lnp; 577 else { 578 lst->tail->next = _lnp; 579 lst->tail = lst->tail->next; 580 } 581 return (_lnp); 582 } 583