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