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