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