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