xref: /illumos-gate/usr/src/cmd/sgs/mcs/common/utils.c (revision 06e1a714)
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 2006 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. We accept any
269 	 * string (even null), as this is arbitrary user defined text.
270 	 *
271 	 * The caller expects this routine to replace a NULL info->mdata
272 	 * field with a pointer to a freshly allocated copy. Any attempt
273 	 * to optimize away a null string append would have to deal with
274 	 * that, as failing to do so will cause a segfault when the NULL
275 	 * mdata field is dereferenced. Accepting null strings in
276 	 * this very unimportant case eliminates the need for that.
277 	 */
278 	len = strlen(a_string);
279 
280 	/*
281 	 * Every modification operation will be done
282 	 * to a new Elf_Data descriptor.
283 	 */
284 	if (info->mdata == 0) {
285 		/*
286 		 * mdata is not allocated yet.
287 		 * Allocate the data and set it.
288 		 */
289 		info->mdata = data = calloc(1, sizeof (Elf_Data));
290 		if (data == NULL) {
291 			error_message(MALLOC_ERROR,
292 			PLAIN_ERROR, (char *)0,
293 			prog);
294 			exit(1);
295 		}
296 		*data = *info->data;
297 
298 		/*
299 		 * Check if the section is deleted or not.
300 		 * Or if the size is 0 or not.
301 		 */
302 		if ((GET_ACTION(info->flags) == ACT_DELETE) ||
303 		    data->d_size == 0) {
304 			/*
305 			 * The section was deleated.
306 			 * But now, the user wants to add data to this
307 			 * section.
308 			 */
309 			data->d_buf = calloc(1, len + 2);
310 			if (data->d_buf == 0) {
311 				error_message(MALLOC_ERROR,
312 				PLAIN_ERROR, (char *)0,
313 				prog);
314 				exit(1);
315 			}
316 			tp = (char *)data->d_buf;
317 			(void) memcpy(& tp[1], a_string, len + 1);
318 			data->d_size = len + 2;
319 		} else {
320 			/*
321 			 * The user wants to add data to the section.
322 			 * I am not going to change the original data.
323 			 * Do the modification on the new one.
324 			 */
325 			p = malloc(len + 1 + data->d_size);
326 			if (p == NULL) {
327 				error_message(MALLOC_ERROR,
328 				PLAIN_ERROR, (char *)0,
329 				prog);
330 				exit(1);
331 			}
332 			(void) memcpy(p, data->d_buf, data->d_size);
333 			(void) memcpy(&p[data->d_size], a_string, len + 1);
334 			data->d_buf = p;
335 			data->d_size = data->d_size + len + 1;
336 		}
337 	} else {
338 		/*
339 		 * mdata is already allocated.
340 		 * Modify it.
341 		 */
342 		data = info->mdata;
343 		if ((GET_ACTION(info->flags) == ACT_DELETE) ||
344 		    data->d_size == 0) {
345 			/*
346 			 * The section was deleated.
347 			 * But now, the user wants to add data to this
348 			 * section.
349 			 */
350 			if (data->d_buf)
351 				free(data->d_buf);
352 			data->d_buf = calloc(1, len + 2);
353 			if (data->d_buf == 0) {
354 				error_message(MALLOC_ERROR,
355 				PLAIN_ERROR, (char *)0,
356 				prog);
357 				exit(1);
358 			}
359 			tp = (char *)data->d_buf;
360 			(void) memcpy(&tp[1], a_string, len + 1);
361 			data->d_size = len + 2;
362 		} else {
363 			/*
364 			 * The user wants to add data to the section.
365 			 * I am not going to change the original data.
366 			 * Do the modification on the new one.
367 			 */
368 			p = malloc(len + 1 + data->d_size);
369 			if (p == NULL) {
370 				error_message(MALLOC_ERROR,
371 				PLAIN_ERROR, (char *)0,
372 				prog);
373 				exit(1);
374 			}
375 			(void) memcpy(p, data->d_buf, data->d_size);
376 			(void) memcpy(&p[data->d_size], a_string, len + 1);
377 			free(data->d_buf);
378 			data->d_buf = p;
379 			data->d_size = data->d_size + len + 1;
380 		}
381 	}
382 }
383 
384 /*
385  * ACT_COMPRESS
386  */
387 #define	HALFLONG 16
388 #define	low(x)  (x&((1L<<HALFLONG)-1))
389 #define	high(x) (x>>HALFLONG)
390 
391 static void
392 docompress(section_info_table *info)
393 {
394 	Elf_Data *data;
395 	size_t size;
396 	char *buf;
397 
398 	if (info->mdata == 0) {
399 		/*
400 		 * mdata is not allocated yet.
401 		 * Allocate the data and set it.
402 		 */
403 		char *p;
404 		info->mdata = data = calloc(1, sizeof (Elf_Data));
405 		if (data == NULL) {
406 			error_message(MALLOC_ERROR,
407 			PLAIN_ERROR, (char *)0,
408 			prog);
409 			exit(1);
410 		}
411 		*data = *info->data;
412 		p = malloc(data->d_size);
413 		(void) memcpy(p, (char *)data->d_buf, data->d_size);
414 		data->d_buf = p;
415 	}
416 	size = info->mdata->d_size;
417 	buf = (char *)info->mdata->d_buf;
418 	buf = compress(buf, &size);
419 	info->mdata->d_buf = buf;
420 	info->mdata->d_size = size;
421 }
422 
423 static char *
424 compress(char *str, size_t *size)
425 {
426 	int hash;
427 	int i;
428 	size_t temp_string_size = 0;
429 	size_t o_size = *size;
430 	char *temp_string = str;
431 
432 	int *hash_key;
433 	size_t hash_num;
434 	size_t hash_end;
435 	size_t *hash_str;
436 	char *strings;
437 	size_t next_str;
438 	size_t str_size;
439 
440 	hash_key = malloc(sizeof (int) * 200);
441 	hash_end = 200;
442 	hash_str = malloc(sizeof (size_t) * 200);
443 	str_size = o_size+1;
444 	strings = malloc(str_size);
445 
446 	if (hash_key == NULL || hash_str == NULL || strings == NULL) {
447 		error_message(MALLOC_ERROR,
448 		PLAIN_ERROR, (char *)0,
449 		prog);
450 		mcs_exit(FAILURE);
451 	}
452 
453 	hash_num = 0;
454 	next_str = 0;
455 
456 	while (temp_string_size < o_size)  {
457 		size_t pos;
458 		char c;
459 		/*
460 		 * Get a string
461 		 */
462 		pos = next_str;
463 
464 		while ((c = *(temp_string++)) != '\0' &&
465 		    (temp_string_size + (next_str - pos)) <= o_size) {
466 			if (next_str >= str_size) {
467 				str_size *= 2;
468 				if ((strings = (char *)
469 				    realloc(strings, str_size)) == NULL) {
470 					error_message(MALLOC_ERROR,
471 					PLAIN_ERROR, (char *)0,
472 					prog);
473 					mcs_exit(FAILURE);
474 				}
475 			}
476 			strings[next_str++] = c;
477 		}
478 
479 		if (next_str >= str_size) {
480 			str_size *= 2;
481 			if ((strings = (char *)
482 			    realloc(strings, str_size)) == NULL) {
483 				error_message(MALLOC_ERROR,
484 				PLAIN_ERROR, (char *)0,
485 				prog);
486 				mcs_exit(FAILURE);
487 			}
488 		}
489 		strings[next_str++] = NULL;
490 		/*
491 		 * End get string
492 		 */
493 
494 		temp_string_size += (next_str - pos);
495 		hash = dohash(pos + strings);
496 		for (i = 0; i < hash_num; i++) {
497 			if (hash != hash_key[i])
498 				continue;
499 			if (strcmp(pos + strings, hash_str[i] + strings) == 0)
500 				break;
501 		}
502 		if (i != hash_num) {
503 			next_str = pos;
504 			continue;
505 		}
506 		if (hash_num == hash_end) {
507 			hash_end *= 2;
508 			hash_key = realloc((char *)hash_key,
509 				hash_end * sizeof (int));
510 			hash_str = realloc((char *)hash_str,
511 				hash_end * sizeof (size_t));
512 			if (hash_key == NULL || hash_str == NULL) {
513 				error_message(MALLOC_ERROR,
514 				PLAIN_ERROR, (char *)0,
515 				prog);
516 				mcs_exit(FAILURE);
517 			}
518 		}
519 		hash_key[hash_num] = hash;
520 		hash_str[hash_num++] = pos;
521 	}
522 
523 	/*
524 	 * Clean up
525 	 */
526 	free(hash_key);
527 	free(hash_str);
528 
529 	/*
530 	 * Return
531 	 */
532 	if (next_str != o_size) {
533 		/*
534 		 * string compressed.
535 		 */
536 		*size = next_str;
537 		free(str);
538 		str = malloc(next_str);
539 		(void) memcpy(str, strings, next_str);
540 	}
541 	free(strings);
542 	return (str);
543 }
544 
545 static int
546 dohash(char *str)
547 {
548 	long sum;
549 	unsigned shift;
550 	int t;
551 	sum = 1;
552 	for (shift = 0; (t = *str++) != NULL; shift += 7) {
553 		sum += (long)t << (shift %= HALFLONG);
554 	}
555 	sum = low(sum) + high(sum);
556 	/* LINTED */
557 	return ((short)low(sum) + (short)high(sum));
558 }
559 
560 /*
561  * Append an item to the specified list, and return a pointer to the list
562  * node created.
563  */
564 Listnode *
565 list_appendc(List *lst, const void *item)
566 {
567 	Listnode	*_lnp;
568 
569 	if ((_lnp = malloc(sizeof (Listnode))) == (Listnode *)0)
570 		return (0);
571 
572 	_lnp->data = (void *)item;
573 	_lnp->next = NULL;
574 
575 	if (lst->head == NULL)
576 		lst->tail = lst->head = _lnp;
577 	else {
578 		lst->tail->next = _lnp;
579 		lst->tail = lst->tail->next;
580 	}
581 	return (_lnp);
582 }
583