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 2009 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 NULL, 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, NULL, 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, NULL, 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, PLAIN_ERROR, 142 NULL, prog, cur_file, SECT_NAME); 143 break; 144 } else if (GET_LOC(info->flags) == IN) { 145 ret++; 146 error_message(ACT_APPEND2_ERROR, PLAIN_ERROR, 147 NULL, prog, cur_file, SECT_NAME); 148 break; 149 } 150 doappend(Action[act_index].a_string, info); 151 (cmd_info->no_of_append)++; 152 info->secno = info->osecno; 153 SET_ACTION(info->flags, ACT_APPEND); 154 SET_MODIFIED(info->flags); 155 if (GET_LOC(info->flags) == PRIOR) 156 info->secno = (GElf_Word)EXPANDED; 157 break; 158 case ACT_COMPRESS: 159 /* 160 * If this section is already deleted, 161 * don't do anything. 162 */ 163 if (GET_ACTION(info->flags) == ACT_DELETE) 164 break; 165 if (shdr.sh_type == SHT_NOBITS) { 166 ret++; 167 error_message(ACT_COMPRESS1_ERROR, PLAIN_ERROR, 168 NULL, prog, cur_file, SECT_NAME); 169 break; 170 } else if (GET_LOC(info->flags) == IN) { 171 ret++; 172 error_message(ACT_COMPRESS2_ERROR, PLAIN_ERROR, 173 NULL, prog, cur_file, SECT_NAME); 174 break; 175 } 176 177 docompress(info); 178 (cmd_info->no_of_compressed)++; 179 SET_ACTION(info->flags, ACT_COMPRESS); 180 SET_MODIFIED(info->flags); 181 if (GET_LOC(info->flags) == PRIOR) 182 info->secno = (GElf_Word)SHRUNK; 183 break; 184 } 185 } 186 return (ret); 187 } 188 189 /* 190 * ACT_ZAP 191 */ 192 static void 193 dozap(section_info_table *info) 194 { 195 Elf_Data *data; 196 197 info->mdata = data = malloc(sizeof (Elf_Data)); 198 if (data == NULL) { 199 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); 200 mcs_exit(FAILURE); 201 } 202 *data = *info->data; 203 data->d_buf = calloc(1, data->d_size); 204 if (data->d_buf == NULL) { 205 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); 206 mcs_exit(FAILURE); 207 } 208 } 209 210 /* 211 * ACT_PRINT 212 */ 213 static void 214 doprint(char *cur_file, section_info_table *info) 215 { 216 Elf_Data *data; 217 size_t temp_size; 218 char *temp_string; 219 220 if (GET_MODIFIED(info->flags) == 0) 221 data = info->data; 222 else 223 data = info->mdata; 224 if (data == 0) 225 return; 226 227 temp_size = data->d_size; 228 temp_string = data->d_buf; 229 230 if (temp_size == 0) 231 return; 232 (void) fprintf(stdout, "%s:\n", cur_file); 233 234 while (temp_size--) { 235 char c = *temp_string++; 236 switch (c) { 237 case '\0': 238 (void) putchar('\n'); 239 break; 240 default: 241 (void) putchar(c); 242 break; 243 } 244 } 245 (void) putchar('\n'); 246 } 247 248 /* 249 * ACT_APPEND 250 */ 251 static void 252 doappend(char *a_string, section_info_table *info) 253 { 254 Elf_Data *data; 255 char *p; 256 size_t len; 257 char *tp; 258 259 /* 260 * Get the length of the string to be added. We accept any 261 * string (even null), as this is arbitrary user defined text. 262 * 263 * The caller expects this routine to replace a NULL info->mdata 264 * field with a pointer to a freshly allocated copy. Any attempt 265 * to optimize away a null string append would have to deal with 266 * that, as failing to do so will cause a segfault when the NULL 267 * mdata field is dereferenced. Accepting null strings in 268 * this very unimportant case eliminates the need for that. 269 */ 270 len = strlen(a_string); 271 272 /* 273 * Every modification operation will be done 274 * to a new Elf_Data descriptor. 275 */ 276 if (info->mdata == 0) { 277 /* 278 * mdata is not allocated yet. 279 * Allocate the data and set it. 280 */ 281 info->mdata = data = calloc(1, sizeof (Elf_Data)); 282 if (data == NULL) { 283 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); 284 mcs_exit(FAILURE); 285 } 286 *data = *info->data; 287 288 /* 289 * Check if the section is deleted or not. 290 * Or if the size is 0 or not. 291 */ 292 if ((GET_ACTION(info->flags) == ACT_DELETE) || 293 data->d_size == 0) { 294 /* 295 * The section was deleated. 296 * But now, the user wants to add data to this 297 * section. 298 */ 299 data->d_buf = calloc(1, len + 2); 300 if (data->d_buf == NULL) { 301 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, 302 prog); 303 mcs_exit(FAILURE); 304 } 305 tp = (char *)data->d_buf; 306 (void) memcpy(& tp[1], a_string, len + 1); 307 data->d_size = len + 2; 308 } else { 309 /* 310 * The user wants to add data to the section. 311 * I am not going to change the original data. 312 * Do the modification on the new one. 313 */ 314 p = malloc(len + 1 + data->d_size); 315 if (p == NULL) { 316 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, 317 prog); 318 mcs_exit(FAILURE); 319 } 320 (void) memcpy(p, data->d_buf, data->d_size); 321 (void) memcpy(&p[data->d_size], a_string, len + 1); 322 data->d_buf = p; 323 data->d_size = data->d_size + len + 1; 324 } 325 } else { 326 /* 327 * mdata is already allocated. 328 * Modify it. 329 */ 330 data = info->mdata; 331 if ((GET_ACTION(info->flags) == ACT_DELETE) || 332 data->d_size == 0) { 333 /* 334 * The section was deleated. 335 * But now, the user wants to add data to this 336 * section. 337 */ 338 if (data->d_buf) 339 free(data->d_buf); 340 data->d_buf = calloc(1, len + 2); 341 if (data->d_buf == NULL) { 342 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, 343 prog); 344 mcs_exit(FAILURE); 345 } 346 tp = (char *)data->d_buf; 347 (void) memcpy(&tp[1], a_string, len + 1); 348 data->d_size = len + 2; 349 } else { 350 /* 351 * The user wants to add data to the section. 352 * I am not going to change the original data. 353 * Do the modification on the new one. 354 */ 355 p = malloc(len + 1 + data->d_size); 356 if (p == NULL) { 357 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, 358 prog); 359 mcs_exit(FAILURE); 360 } 361 (void) memcpy(p, data->d_buf, data->d_size); 362 (void) memcpy(&p[data->d_size], a_string, len + 1); 363 free(data->d_buf); 364 data->d_buf = p; 365 data->d_size = data->d_size + len + 1; 366 } 367 } 368 } 369 370 /* 371 * ACT_COMPRESS 372 */ 373 #define HALFLONG 16 374 #define low(x) (x&((1L<<HALFLONG)-1)) 375 #define high(x) (x>>HALFLONG) 376 377 static void 378 docompress(section_info_table *info) 379 { 380 Elf_Data *data; 381 size_t size; 382 char *buf; 383 384 if (info->mdata == 0) { 385 /* 386 * mdata is not allocated yet. 387 * Allocate the data and set it. 388 */ 389 char *p; 390 info->mdata = data = calloc(1, sizeof (Elf_Data)); 391 if (data == NULL) { 392 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); 393 mcs_exit(FAILURE); 394 } 395 *data = *info->data; 396 p = malloc(data->d_size); 397 (void) memcpy(p, (char *)data->d_buf, data->d_size); 398 data->d_buf = p; 399 } 400 size = info->mdata->d_size; 401 buf = (char *)info->mdata->d_buf; 402 buf = compress(buf, &size); 403 info->mdata->d_buf = buf; 404 info->mdata->d_size = size; 405 } 406 407 static char * 408 compress(char *str, size_t *size) 409 { 410 int hash; 411 int i; 412 size_t temp_string_size = 0; 413 size_t o_size = *size; 414 char *temp_string = str; 415 416 int *hash_key; 417 size_t hash_num; 418 size_t hash_end; 419 size_t *hash_str; 420 char *strings; 421 size_t next_str; 422 size_t str_size; 423 424 hash_key = malloc(sizeof (int) * 200); 425 hash_end = 200; 426 hash_str = malloc(sizeof (size_t) * 200); 427 str_size = o_size+1; 428 strings = malloc(str_size); 429 430 if (hash_key == NULL || hash_str == NULL || strings == NULL) { 431 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); 432 mcs_exit(FAILURE); 433 } 434 435 hash_num = 0; 436 next_str = 0; 437 438 while (temp_string_size < o_size) { 439 size_t pos; 440 char c; 441 /* 442 * Get a string 443 */ 444 pos = next_str; 445 446 while ((c = *(temp_string++)) != '\0' && 447 (temp_string_size + (next_str - pos)) <= o_size) { 448 if (next_str >= str_size) { 449 str_size *= 2; 450 if ((strings = (char *) 451 realloc(strings, str_size)) == NULL) { 452 error_message(MALLOC_ERROR, PLAIN_ERROR, 453 NULL, prog); 454 mcs_exit(FAILURE); 455 } 456 } 457 strings[next_str++] = c; 458 } 459 460 if (next_str >= str_size) { 461 str_size *= 2; 462 if ((strings = (char *) 463 realloc(strings, str_size)) == NULL) { 464 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, 465 prog); 466 mcs_exit(FAILURE); 467 } 468 } 469 strings[next_str++] = NULL; 470 /* 471 * End get string 472 */ 473 474 temp_string_size += (next_str - pos); 475 hash = dohash(pos + strings); 476 for (i = 0; i < hash_num; i++) { 477 if (hash != hash_key[i]) 478 continue; 479 if (strcmp(pos + strings, hash_str[i] + strings) == 0) 480 break; 481 } 482 if (i != hash_num) { 483 next_str = pos; 484 continue; 485 } 486 if (hash_num == hash_end) { 487 hash_end *= 2; 488 hash_key = realloc((char *)hash_key, 489 hash_end * sizeof (int)); 490 hash_str = realloc((char *)hash_str, 491 hash_end * sizeof (size_t)); 492 if (hash_key == NULL || hash_str == NULL) { 493 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, 494 prog); 495 mcs_exit(FAILURE); 496 } 497 } 498 hash_key[hash_num] = hash; 499 hash_str[hash_num++] = pos; 500 } 501 502 /* 503 * Clean up 504 */ 505 free(hash_key); 506 free(hash_str); 507 508 /* 509 * Return 510 */ 511 if (next_str != o_size) { 512 /* 513 * string compressed. 514 */ 515 *size = next_str; 516 free(str); 517 str = malloc(next_str); 518 (void) memcpy(str, strings, next_str); 519 } 520 free(strings); 521 return (str); 522 } 523 524 static int 525 dohash(char *str) 526 { 527 long sum; 528 unsigned shift; 529 int t; 530 sum = 1; 531 for (shift = 0; (t = *str++) != NULL; shift += 7) { 532 sum += (long)t << (shift %= HALFLONG); 533 } 534 sum = low(sum) + high(sum); 535 /* LINTED */ 536 return ((short)low(sum) + (short)high(sum)); 537 } 538