xref: /illumos-gate/usr/src/cmd/sgs/mcs/common/utils.c (revision 13b136d3061155363c62c9f6568d25b8b27da8f6)
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++] = '\0';
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++) != 0; 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