xref: /illumos-gate/usr/src/cmd/sgs/mcs/common/utils.c (revision 7c478bd9)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  *	Copyright(c) 1988 AT&T
24  *	  All Rights Reserved
25  *
26  */
27 
28 /*
29  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
30  * Use is subject to license terms.
31  */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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->flags) == ACT_DELETE)
67 				break;
68 			dozap(info);
69 			SET_ACTION(info->flags, ACT_ZAP);
70 			SET_MODIFIED(info->flags);
71 			break;
72 		case ACT_PRINT:
73 			if (GET_ACTION(info->flags) == ACT_DELETE)
74 				break;
75 			if (shdr.sh_type == SHT_NOBITS) {
76 				error_message(ACT_PRINT_ERROR,
77 				PLAIN_ERROR, (char *)0,
78 				prog, cur_file, SECT_NAME);
79 				break;
80 			}
81 			doprint(cur_file, info);
82 			break;
83 		case ACT_DELETE:
84 			/*
85 			 * If I am strip command, this is the
86 			 * only action I can take.
87 			 */
88 			if (GET_ACTION(info->flags) == ACT_DELETE)
89 				break;
90 			if (GET_LOC(info->flags) == IN) {
91 				/*
92 				 * If I am 'strip', I have to
93 				 * unset the candidate flag and
94 				 * unset the error return code.
95 				 */
96 				if (CHK_OPT(info, I_AM_STRIP)) {
97 					ret = 0;
98 					UNSET_CANDIDATE(info->flags);
99 				} else {
100 					ret++;
101 					error_message(ACT_DELETE1_ERROR,
102 					PLAIN_ERROR, (char *)0,
103 					prog, cur_file, info->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,
204 		PLAIN_ERROR, (char *)0,
205 		prog);
206 		exit(1);
207 	}
208 	*data = *info->data;
209 	data->d_buf = calloc(1, data->d_size);
210 	if (data->d_buf == NULL) {
211 		error_message(MALLOC_ERROR,
212 		PLAIN_ERROR, (char *)0,
213 		prog);
214 		exit(1);
215 	}
216 }
217 
218 /*
219  * ACT_PRINT
220  */
221 static void
222 doprint(char *cur_file, section_info_table *info)
223 {
224 	Elf_Data *data;
225 	size_t	temp_size;
226 	char	*temp_string;
227 
228 	if (GET_MODIFIED(info->flags) == 0)
229 		data = info->data;
230 	else
231 		data = info->mdata;
232 	if (data == 0)
233 		return;
234 
235 	temp_size = data->d_size;
236 	temp_string = data->d_buf;
237 
238 	if (temp_size == 0)
239 		return;
240 	(void) fprintf(stdout, "%s:\n", cur_file);
241 
242 	while (temp_size--) {
243 		char c = *temp_string++;
244 		switch (c) {
245 		case '\0':
246 			(void) putchar('\n');
247 			break;
248 		default:
249 			(void) putchar(c);
250 			break;
251 		}
252 	}
253 	(void) putchar('\n');
254 }
255 
256 /*
257  * ACT_APPEND
258  */
259 static void
260 doappend(char *a_string, section_info_table *info)
261 {
262 	Elf_Data *data;
263 	char *p;
264 	size_t len;
265 	char *tp;
266 
267 	/*
268 	 * Get the length of the string to be added.
269 	 */
270 	len = strlen(a_string);
271 	if (len == 0)
272 		return;
273 
274 	/*
275 	 * Every modification operation will be done
276 	 * to a new Elf_Data descriptor.
277 	 */
278 	if (info->mdata == 0) {
279 		/*
280 		 * mdata is not allocated yet.
281 		 * Allocate the data and set it.
282 		 */
283 		info->mdata = data = calloc(1, sizeof (Elf_Data));
284 		if (data == NULL) {
285 			error_message(MALLOC_ERROR,
286 			PLAIN_ERROR, (char *)0,
287 			prog);
288 			exit(1);
289 		}
290 		*data = *info->data;
291 
292 		/*
293 		 * Check if the section is deleted or not.
294 		 * Or if the size is 0 or not.
295 		 */
296 		if ((GET_ACTION(info->flags) == ACT_DELETE) ||
297 		    data->d_size == 0) {
298 			/*
299 			 * The section was deleated.
300 			 * But now, the user wants to add data to this
301 			 * section.
302 			 */
303 			data->d_buf = calloc(1, len + 2);
304 			if (data->d_buf == 0) {
305 				error_message(MALLOC_ERROR,
306 				PLAIN_ERROR, (char *)0,
307 				prog);
308 				exit(1);
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,
322 				PLAIN_ERROR, (char *)0,
323 				prog);
324 				exit(1);
325 			}
326 			(void) memcpy(p, data->d_buf, data->d_size);
327 			(void) memcpy(&p[data->d_size], a_string, len + 1);
328 			data->d_buf = p;
329 			data->d_size = data->d_size + len + 1;
330 		}
331 	} else {
332 		/*
333 		 * mdata is already allocated.
334 		 * Modify it.
335 		 */
336 		data = info->mdata;
337 		if ((GET_ACTION(info->flags) == ACT_DELETE) ||
338 		    data->d_size == 0) {
339 			/*
340 			 * The section was deleated.
341 			 * But now, the user wants to add data to this
342 			 * section.
343 			 */
344 			if (data->d_buf)
345 				free(data->d_buf);
346 			data->d_buf = calloc(1, len + 2);
347 			if (data->d_buf == 0) {
348 				error_message(MALLOC_ERROR,
349 				PLAIN_ERROR, (char *)0,
350 				prog);
351 				exit(1);
352 			}
353 			tp = (char *)data->d_buf;
354 			(void) memcpy(&tp[1], a_string, len + 1);
355 			data->d_size = len + 2;
356 		} else {
357 			/*
358 			 * The user wants to add data to the section.
359 			 * I am not going to change the original data.
360 			 * Do the modification on the new one.
361 			 */
362 			p = malloc(len + 1 + data->d_size);
363 			if (p == NULL) {
364 				error_message(MALLOC_ERROR,
365 				PLAIN_ERROR, (char *)0,
366 				prog);
367 				exit(1);
368 			}
369 			(void) memcpy(p, data->d_buf, data->d_size);
370 			(void) memcpy(&p[data->d_size], a_string, len + 1);
371 			free(data->d_buf);
372 			data->d_buf = p;
373 			data->d_size = data->d_size + len + 1;
374 		}
375 	}
376 }
377 
378 /*
379  * ACT_COMPRESS
380  */
381 #define	HALFLONG 16
382 #define	low(x)  (x&((1L<<HALFLONG)-1))
383 #define	high(x) (x>>HALFLONG)
384 
385 static void
386 docompress(section_info_table *info)
387 {
388 	Elf_Data *data;
389 	size_t size;
390 	char *buf;
391 
392 	if (info->mdata == 0) {
393 		/*
394 		 * mdata is not allocated yet.
395 		 * Allocate the data and set it.
396 		 */
397 		char *p;
398 		info->mdata = data = calloc(1, sizeof (Elf_Data));
399 		if (data == NULL) {
400 			error_message(MALLOC_ERROR,
401 			PLAIN_ERROR, (char *)0,
402 			prog);
403 			exit(1);
404 		}
405 		*data = *info->data;
406 		p = malloc(data->d_size);
407 		(void) memcpy(p, (char *)data->d_buf, data->d_size);
408 		data->d_buf = p;
409 	}
410 	size = info->mdata->d_size;
411 	buf = (char *)info->mdata->d_buf;
412 	buf = compress(buf, &size);
413 	info->mdata->d_buf = buf;
414 	info->mdata->d_size = size;
415 }
416 
417 static char *
418 compress(char *str, size_t *size)
419 {
420 	int hash;
421 	int i;
422 	size_t temp_string_size = 0;
423 	size_t o_size = *size;
424 	char *temp_string = str;
425 
426 	int *hash_key;
427 	size_t hash_num;
428 	size_t hash_end;
429 	size_t *hash_str;
430 	char *strings;
431 	size_t next_str;
432 	size_t str_size;
433 
434 	hash_key = malloc(sizeof (int) * 200);
435 	hash_end = 200;
436 	hash_str = malloc(sizeof (size_t) * 200);
437 	str_size = o_size+1;
438 	strings = malloc(str_size);
439 
440 	if (hash_key == NULL || hash_str == NULL || strings == NULL) {
441 		error_message(MALLOC_ERROR,
442 		PLAIN_ERROR, (char *)0,
443 		prog);
444 		mcs_exit(FAILURE);
445 	}
446 
447 	hash_num = 0;
448 	next_str = 0;
449 
450 	while (temp_string_size < o_size)  {
451 		size_t pos;
452 		char c;
453 		/*
454 		 * Get a string
455 		 */
456 		pos = next_str;
457 
458 		while ((c = *(temp_string++)) != '\0' &&
459 		    (temp_string_size + (next_str - pos)) <= o_size) {
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,
465 					PLAIN_ERROR, (char *)0,
466 					prog);
467 					mcs_exit(FAILURE);
468 				}
469 			}
470 			strings[next_str++] = c;
471 		}
472 
473 		if (next_str >= str_size) {
474 			str_size *= 2;
475 			if ((strings = (char *)
476 			    realloc(strings, str_size)) == NULL) {
477 				error_message(MALLOC_ERROR,
478 				PLAIN_ERROR, (char *)0,
479 				prog);
480 				mcs_exit(FAILURE);
481 			}
482 		}
483 		strings[next_str++] = NULL;
484 		/*
485 		 * End get string
486 		 */
487 
488 		temp_string_size += (next_str - pos);
489 		hash = dohash(pos + strings);
490 		for (i = 0; i < hash_num; i++) {
491 			if (hash != hash_key[i])
492 				continue;
493 			if (strcmp(pos + strings, hash_str[i] + strings) == 0)
494 				break;
495 		}
496 		if (i != hash_num) {
497 			next_str = pos;
498 			continue;
499 		}
500 		if (hash_num == hash_end) {
501 			hash_end *= 2;
502 			hash_key = realloc((char *)hash_key,
503 				hash_end * sizeof (int));
504 			hash_str = realloc((char *)hash_str,
505 				hash_end * sizeof (size_t));
506 			if (hash_key == NULL || hash_str == NULL) {
507 				error_message(MALLOC_ERROR,
508 				PLAIN_ERROR, (char *)0,
509 				prog);
510 				mcs_exit(FAILURE);
511 			}
512 		}
513 		hash_key[hash_num] = hash;
514 		hash_str[hash_num++] = pos;
515 	}
516 
517 	/*
518 	 * Clean up
519 	 */
520 	free(hash_key);
521 	free(hash_str);
522 
523 	/*
524 	 * Return
525 	 */
526 	if (next_str != o_size) {
527 		/*
528 		 * string compressed.
529 		 */
530 		*size = next_str;
531 		free(str);
532 		str = malloc(next_str);
533 		(void) memcpy(str, strings, next_str);
534 	}
535 	free(strings);
536 	return (str);
537 }
538 
539 static int
540 dohash(char *str)
541 {
542 	long sum;
543 	unsigned shift;
544 	int t;
545 	sum = 1;
546 	for (shift = 0; (t = *str++) != NULL; shift += 7) {
547 		sum += (long)t << (shift %= HALFLONG);
548 	}
549 	sum = low(sum) + high(sum);
550 	/* LINTED */
551 	return ((short)low(sum) + (short)high(sum));
552 }
553 
554 /*
555  * Append an item to the specified list, and return a pointer to the list
556  * node created.
557  */
558 Listnode *
559 list_appendc(List *lst, const void *item)
560 {
561 	Listnode	*_lnp;
562 
563 	if ((_lnp = malloc(sizeof (Listnode))) == (Listnode *)0)
564 		return (0);
565 
566 	_lnp->data = (void *)item;
567 	_lnp->next = NULL;
568 
569 	if (lst->head == NULL)
570 		lst->tail = lst->head = _lnp;
571 	else {
572 		lst->tail->next = _lnp;
573 		lst->tail = lst->tail->next;
574 	}
575 	return (_lnp);
576 }
577