/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright(c) 1988 AT&T * All Rights Reserved * */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. */ #include "mcs.h" #include "extern.h" #include "gelf.h" /* * Function prototypes. */ static void docompress(section_info_table *); static char *compress(char *, size_t *); static void doappend(char *, section_info_table *); static void doprint(char *, section_info_table *); static void dozap(section_info_table *); static int dohash(char *); /* * Apply the actions specified by the user. */ int apply_action(section_info_table *info, char *cur_file, Cmd_Info *cmd_info) { int act_index; int ret = 0; GElf_Shdr shdr; (void) gelf_getshdr(info->scn, &shdr); for (act_index = 0; act_index < actmax; act_index++) { Action[act_index].a_cnt++; switch (Action[act_index].a_action) { case ACT_ZAP: if (GET_ACTION(info->si_flags) == ACT_DELETE) break; dozap(info); SET_ACTION(info->si_flags, ACT_ZAP); SET_MODIFIED(info->si_flags); break; case ACT_PRINT: if (GET_ACTION(info->si_flags) == ACT_DELETE) break; if (shdr.sh_type == SHT_NOBITS) { error_message(ACT_PRINT_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME); break; } doprint(cur_file, info); break; case ACT_DELETE: /* * If I am strip command, this is the * only action I can take. */ if (GET_ACTION(info->si_flags) == ACT_DELETE) break; if (GET_LOC(info->si_flags) == IN) { /* * If I am 'strip', I have to * unset the candidate flag and * unset the error return code. */ if (CHK_OPT(cmd_info, I_AM_STRIP)) { ret = 0; UNSET_CANDIDATE(info->si_flags); } else { char *name = info->name; ret++; if (name == NULL) name = gettext(""); error_message(ACT_DELETE1_ERROR, PLAIN_ERROR, NULL, prog, cur_file, name); } break; } else if (info->rel_loc == IN) { /* * If I am 'strip', I have to * unset the candidate flag and * unset the error return code. */ if (CHK_OPT(cmd_info, I_AM_STRIP)) { ret = 0; UNSET_CANDIDATE(info->si_flags); } else { ret++; error_message(ACT_DELETE2_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME, info->rel_name); } break; } else if (GET_LOC(info->si_flags) == PRIOR) { /* * I can not delete this * section. I can only NULL * this out. */ info->secno = (GElf_Word)NULLED; (cmd_info->no_of_nulled)++; } else { info->secno = (GElf_Word)DELETED; (cmd_info->no_of_delete)++; } SET_ACTION(info->si_flags, ACT_DELETE); SET_MODIFIED(info->si_flags); break; case ACT_APPEND: if (shdr.sh_type == SHT_NOBITS) { ret++; error_message(ACT_APPEND1_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME); break; } else if (GET_LOC(info->si_flags) == IN) { ret++; error_message(ACT_APPEND2_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME); break; } doappend(Action[act_index].a_string, info); (cmd_info->no_of_append)++; info->secno = info->osecno; SET_ACTION(info->si_flags, ACT_APPEND); SET_MODIFIED(info->si_flags); if (GET_LOC(info->si_flags) == PRIOR) info->secno = (GElf_Word)EXPANDED; break; case ACT_COMPRESS: /* * If this section is already deleted, * don't do anything. */ if (GET_ACTION(info->si_flags) == ACT_DELETE) break; if (shdr.sh_type == SHT_NOBITS) { ret++; error_message(ACT_COMPRESS1_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME); break; } else if (GET_LOC(info->si_flags) == IN) { ret++; error_message(ACT_COMPRESS2_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME); break; } docompress(info); (cmd_info->no_of_compressed)++; SET_ACTION(info->si_flags, ACT_COMPRESS); SET_MODIFIED(info->si_flags); if (GET_LOC(info->si_flags) == PRIOR) info->secno = (GElf_Word)SHRUNK; break; } } return (ret); } /* * ACT_ZAP */ static void dozap(section_info_table *info) { Elf_Data *data; info->mdata = data = malloc(sizeof (Elf_Data)); if (data == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } *data = *info->data; data->d_buf = calloc(1, data->d_size); if (data->d_buf == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } } /* * ACT_PRINT */ static void doprint(char *cur_file, section_info_table *info) { Elf_Data *data; size_t temp_size; char *temp_string; if (GET_MODIFIED(info->si_flags) == 0) data = info->data; else data = info->mdata; if (data == 0) return; temp_size = data->d_size; temp_string = data->d_buf; if (temp_size == 0) return; (void) fprintf(stdout, "%s:\n", cur_file); while (temp_size--) { char c = *temp_string++; switch (c) { case '\0': (void) putchar('\n'); break; default: (void) putchar(c); break; } } (void) putchar('\n'); } /* * ACT_APPEND */ static void doappend(char *a_string, section_info_table *info) { Elf_Data *data; char *p; size_t len; char *tp; /* * Get the length of the string to be added. We accept any * string (even null), as this is arbitrary user defined text. * * The caller expects this routine to replace a NULL info->mdata * field with a pointer to a freshly allocated copy. Any attempt * to optimize away a null string append would have to deal with * that, as failing to do so will cause a segfault when the NULL * mdata field is dereferenced. Accepting null strings in * this very unimportant case eliminates the need for that. */ len = strlen(a_string); /* * Every modification operation will be done * to a new Elf_Data descriptor. */ if (info->mdata == 0) { /* * mdata is not allocated yet. * Allocate the data and set it. */ info->mdata = data = calloc(1, sizeof (Elf_Data)); if (data == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } *data = *info->data; /* * Check if the section is deleted or not. * Or if the size is 0 or not. */ if ((GET_ACTION(info->si_flags) == ACT_DELETE) || data->d_size == 0) { /* * The section was deleated. * But now, the user wants to add data to this * section. */ data->d_buf = calloc(1, len + 2); if (data->d_buf == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } tp = (char *)data->d_buf; (void) memcpy(& tp[1], a_string, len + 1); data->d_size = len + 2; } else { /* * The user wants to add data to the section. * I am not going to change the original data. * Do the modification on the new one. */ p = malloc(len + 1 + data->d_size); if (p == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } (void) memcpy(p, data->d_buf, data->d_size); (void) memcpy(&p[data->d_size], a_string, len + 1); data->d_buf = p; data->d_size = data->d_size + len + 1; } } else { /* * mdata is already allocated. * Modify it. */ data = info->mdata; if ((GET_ACTION(info->si_flags) == ACT_DELETE) || data->d_size == 0) { /* * The section was deleated. * But now, the user wants to add data to this * section. */ if (data->d_buf) free(data->d_buf); data->d_buf = calloc(1, len + 2); if (data->d_buf == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } tp = (char *)data->d_buf; (void) memcpy(&tp[1], a_string, len + 1); data->d_size = len + 2; } else { /* * The user wants to add data to the section. * I am not going to change the original data. * Do the modification on the new one. */ p = malloc(len + 1 + data->d_size); if (p == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } (void) memcpy(p, data->d_buf, data->d_size); (void) memcpy(&p[data->d_size], a_string, len + 1); free(data->d_buf); data->d_buf = p; data->d_size = data->d_size + len + 1; } } } /* * ACT_COMPRESS */ #define HALFLONG 16 #define low(x) (x&((1L<>HALFLONG) static void docompress(section_info_table *info) { Elf_Data *data; size_t size; char *buf; if (info->mdata == 0) { /* * mdata is not allocated yet. * Allocate the data and set it. */ char *p; info->mdata = data = calloc(1, sizeof (Elf_Data)); if (data == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } *data = *info->data; p = malloc(data->d_size); (void) memcpy(p, (char *)data->d_buf, data->d_size); data->d_buf = p; } size = info->mdata->d_size; buf = (char *)info->mdata->d_buf; buf = compress(buf, &size); info->mdata->d_buf = buf; info->mdata->d_size = size; } static char * compress(char *str, size_t *size) { int hash; int i; size_t temp_string_size = 0; size_t o_size = *size; char *temp_string = str; int *hash_key; size_t hash_num; size_t hash_end; size_t *hash_str; char *strings; size_t next_str; size_t str_size; hash_key = malloc(sizeof (int) * 200); hash_end = 200; hash_str = malloc(sizeof (size_t) * 200); str_size = o_size+1; strings = malloc(str_size); if (hash_key == NULL || hash_str == NULL || strings == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } hash_num = 0; next_str = 0; while (temp_string_size < o_size) { size_t pos; char c; /* * Get a string */ pos = next_str; while ((c = *(temp_string++)) != '\0' && (temp_string_size + (next_str - pos)) <= o_size) { if (next_str >= str_size) { str_size *= 2; if ((strings = (char *) realloc(strings, str_size)) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } } strings[next_str++] = c; } if (next_str >= str_size) { str_size *= 2; if ((strings = (char *) realloc(strings, str_size)) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } } strings[next_str++] = '\0'; /* * End get string */ temp_string_size += (next_str - pos); hash = dohash(pos + strings); for (i = 0; i < hash_num; i++) { if (hash != hash_key[i]) continue; if (strcmp(pos + strings, hash_str[i] + strings) == 0) break; } if (i != hash_num) { next_str = pos; continue; } if (hash_num == hash_end) { hash_end *= 2; hash_key = realloc((char *)hash_key, hash_end * sizeof (int)); hash_str = realloc((char *)hash_str, hash_end * sizeof (size_t)); if (hash_key == NULL || hash_str == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } } hash_key[hash_num] = hash; hash_str[hash_num++] = pos; } /* * Clean up */ free(hash_key); free(hash_str); /* * Return */ if (next_str != o_size) { /* * string compressed. */ *size = next_str; free(str); str = malloc(next_str); (void) memcpy(str, strings, next_str); } free(strings); return (str); } static int dohash(char *str) { long sum; unsigned shift; int t; sum = 1; for (shift = 0; (t = *str++) != 0; shift += 7) { sum += (long)t << (shift %= HALFLONG); } sum = low(sum) + high(sum); /* LINTED */ return ((short)low(sum) + (short)high(sum)); }