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