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