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
apply_action(section_info_table * info,char * cur_file,Cmd_Info * cmd_info)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
dozap(section_info_table * info)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
doprint(char * cur_file,section_info_table * info)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
doappend(char * a_string,section_info_table * info)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
docompress(section_info_table * info)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 *
compress(char * str,size_t * size)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++] = NULL;
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
dohash(char * str)525 dohash(char *str)
526 {
527 long sum;
528 unsigned shift;
529 int t;
530 sum = 1;
531 for (shift = 0; (t = *str++) != NULL; 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