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
apply_action(section_info_table * info,char * cur_file,Cmd_Info * cmd_info)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
dozap(section_info_table * info)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
doprint(char * cur_file,section_info_table * info)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
doappend(char * a_string,section_info_table * info)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
docompress(section_info_table * info)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 *
compress(char * str,size_t * size)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
dohash(char * str)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