Home | History | Annotate | Download | only in common
      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