xref: /illumos-gate/usr/src/cmd/sgs/mcs/common/file.c (revision fc0105de770cee6a3fd91de949b9927fba6e894b)
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 /*
23  *	Copyright (c) 1988 AT&T
24  *	  All Rights Reserved
25  *
26  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 
30 #include <errno.h>
31 #include "alist.h"
32 #include "mcs.h"
33 #include "extern.h"
34 #include "gelf.h"
35 
36 /*
37  * Type used to pass state information for the current
38  * file between routines.
39  */
40 typedef struct {
41 	int		Sect_exists;
42 	int		notesegndx;
43 	int		notesctndx;
44 	Seg_Table	*b_e_seg_table;
45 	section_info_table *sec_table;
46 	int64_t		*off_table;	/* maintains section's offset; set to */
47 					/* 	retain old offset, else 0 */
48 	int64_t		*nobits_table; 	/* maintains NOBITS sections */
49 	char		*new_sec_string;
50 } file_state_t;
51 
52 
53 /*
54  * Function prototypes.
55  */
56 static void copy_file(int, char *, Tmp_File *);
57 static void
58 copy_non_elf_to_temp_ar(int, Elf *, int, Elf_Arhdr *, char *, Cmd_Info *);
59 static void copy_elf_file_to_temp_ar_file(int, Elf_Arhdr *, char *);
60 static int process_file(Elf *, char *, Cmd_Info *);
61 static void initialize(int shnum, Cmd_Info *, file_state_t *);
62 static int build_segment_table(Elf*, GElf_Ehdr *, file_state_t *);
63 static int traverse_file(Elf *, GElf_Ehdr *, char *, Cmd_Info *,
64     file_state_t *);
65 static uint64_t location(int64_t, int, Elf *, file_state_t *);
66 static uint64_t scn_location(Elf_Scn *, Elf *, file_state_t *);
67 static int build_file(Elf *, GElf_Ehdr *, Cmd_Info *, file_state_t *);
68 static void post_process(Cmd_Info *, file_state_t *);
69 
70 
71 
72 int
73 each_file(char *cur_file, Cmd_Info *cmd_info)
74 {
75 	Elf *elf = 0;
76 	Elf_Cmd cmd;
77 	Elf *arf = 0;
78 	Elf_Arhdr *mem_header;
79 	char *cur_filenm = NULL;
80 	int code = 0;
81 	int error = 0, err = 0;
82 	int ar_file = 0;
83 	int fdartmp;
84 	int fd;
85 	int oflag;
86 
87 	if (cmd_info->flags & MIGHT_CHG)
88 		oflag = O_RDWR;
89 	else
90 		oflag = O_RDONLY;
91 
92 	if ((fd = open(cur_file, oflag)) == -1) {
93 		error_message(OPEN_ERROR, SYSTEM_ERROR, strerror(errno),
94 		    prog, cur_file);
95 		return (FAILURE);
96 	}
97 
98 	/*
99 	 * Note, elf_begin requires ELF_C_READ even if MIGHT_CHK is in effect.
100 	 * libelf does not allow elf_begin() with ELF_C_RDWR when processing
101 	 * archive file members.  Because we are limited to ELF_C_READ use, any
102 	 * ELF data modification must be provided by updating a copy of
103 	 * the data, rather than updating the original file data.
104 	 */
105 	cmd = ELF_C_READ;
106 	if ((arf = elf_begin(fd, cmd, NULL)) == NULL) {
107 		error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
108 		(void) elf_end(arf);
109 		(void) close(fd);   /* done processing this file */
110 		return (FAILURE);
111 	}
112 
113 	if ((elf_kind(arf) == ELF_K_AR)) {
114 		ar_file = 1;
115 		if (CHK_OPT(cmd_info, MIGHT_CHG)) {
116 			artmpfile.tmp_name = tempnam(TMPDIR, "mcs2");
117 			if ((fdartmp = open(artmpfile.tmp_name,
118 			    O_WRONLY | O_APPEND | O_CREAT,
119 			    (mode_t)0666)) == NULL) {
120 				error_message(OPEN_TEMP_ERROR,
121 				    SYSTEM_ERROR, strerror(errno),
122 				    prog, artmpfile);
123 				(void) elf_end(arf);
124 				(void) close(fd);
125 				mcs_exit(FAILURE);
126 			}
127 			artmpfile.tmp_unlink = 1;
128 			/* write magic string to artmpfile */
129 			if ((write(fdartmp, ARMAG, SARMAG)) != SARMAG) {
130 				error_message(WRITE_ERROR,
131 				    SYSTEM_ERROR, strerror(errno),
132 				    prog, artmpfile.tmp_name, cur_file);
133 				mcs_exit(FAILURE);
134 			}
135 		}
136 	} else {
137 		ar_file = 0;
138 		cur_filenm = cur_file;
139 	}
140 
141 	/*
142 	 * Holds temporary file;
143 	 * if archive, holds the current member file if it has an ehdr,
144 	 * and there were no errors in
145 	 * processing the object file.
146 	 */
147 	elftmpfile.tmp_name = tempnam(TMPDIR, "mcs1");
148 
149 	while ((elf = elf_begin(fd, cmd, arf)) != 0) {
150 		if (ar_file) /* get header info */ {
151 			size_t	len;
152 
153 			if ((mem_header = elf_getarhdr(elf)) == NULL) {
154 				error_message(GETARHDR_ERROR, LIBelf_ERROR,
155 				    elf_errmsg(-1), prog, cur_file,
156 				    elf_getbase(elf));
157 				(void) elf_end(elf);
158 				(void) elf_end(arf);
159 				(void) close(fd);
160 				free_tempfile(&artmpfile);
161 				return (FAILURE);
162 			}
163 
164 			if (cur_filenm != NULL)
165 				free(cur_filenm);
166 
167 			len = (strlen(cur_file) + 3 +
168 			    strlen(mem_header->ar_name));
169 
170 			if ((cur_filenm = malloc(len)) == NULL) {
171 				error_message(MALLOC_ERROR,
172 				    PLAIN_ERROR, NULL, prog);
173 				mcs_exit(FAILURE);
174 			}
175 
176 			(void) snprintf(cur_filenm, len, "%s[%s]",
177 			    cur_file, mem_header->ar_name);
178 		}
179 
180 		if (elf_kind(elf) == ELF_K_ELF) {
181 			if ((code = process_file(elf, cur_filenm, cmd_info)) ==
182 			    FAILURE) {
183 				if (!ar_file) {
184 					(void) elf_end(arf);
185 					(void) elf_end(elf);
186 					(void) close(fd);
187 					return (FAILURE);
188 				} else {
189 					copy_non_elf_to_temp_ar(fd, elf,
190 					    fdartmp, mem_header,
191 					    cur_file, cmd_info);
192 					error++;
193 				}
194 			} else if (ar_file && CHK_OPT(cmd_info, MIGHT_CHG)) {
195 				if (code == DONT_BUILD)
196 					copy_non_elf_to_temp_ar(fd, elf,
197 					    fdartmp, mem_header,
198 					    cur_file, cmd_info);
199 				else
200 					copy_elf_file_to_temp_ar_file(
201 					    fdartmp, mem_header, cur_file);
202 			}
203 		} else {
204 			/*
205 			 * decide what to do with non-ELF file
206 			 */
207 			if (!ar_file) {
208 				error_message(FILE_TYPE_ERROR, PLAIN_ERROR,
209 				    NULL, prog, cur_filenm);
210 				(void) close(fd);
211 				return (FAILURE);
212 			} else {
213 				if (CHK_OPT(cmd_info, MIGHT_CHG))
214 					copy_non_elf_to_temp_ar(fd, elf,
215 					    fdartmp, mem_header,
216 					    cur_file, cmd_info);
217 			}
218 		}
219 		cmd = elf_next(elf);
220 		(void) elf_end(elf);
221 	}
222 
223 	err = elf_errno();
224 	if (err != 0) {
225 		error_message(LIBELF_ERROR, LIBelf_ERROR,
226 		    elf_errmsg(err), prog);
227 		error_message(NOT_MANIPULATED_ERROR, PLAIN_ERROR, NULL,
228 		    prog, cur_file);
229 		return (FAILURE);
230 	}
231 
232 	(void) elf_end(arf);
233 
234 	if (ar_file && CHK_OPT(cmd_info, MIGHT_CHG)) {
235 		(void) close(fdartmp); /* done writing to ar_temp_file */
236 		/* copy ar_temp_file to FILE */
237 		copy_file(fd, cur_file, &artmpfile);
238 	} else if (code != DONT_BUILD && CHK_OPT(cmd_info, MIGHT_CHG))
239 		copy_file(fd, cur_file, &elftmpfile);
240 	(void) close(fd);   /* done processing this file */
241 	return (error);
242 }
243 
244 static int
245 process_file(Elf *elf, char *cur_file, Cmd_Info *cmd_info)
246 {
247 	int		error = SUCCESS;
248 	int		x;
249 	GElf_Ehdr	ehdr;
250 	size_t		shnum;
251 	file_state_t	state;
252 
253 	/*
254 	 * Initialize
255 	 */
256 	if (gelf_getehdr(elf, &ehdr) == NULL) {
257 		error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
258 		return (FAILURE);
259 	}
260 
261 	if (elf_getshnum(elf, &shnum) == NULL) {
262 		error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
263 		return (FAILURE);
264 	}
265 
266 	/* Initialize per-file state */
267 	state.Sect_exists = 0;
268 	state.notesegndx = -1;
269 	state.notesctndx = -1;
270 	state.b_e_seg_table = NULL;
271 	state.sec_table = NULL;
272 	state.off_table = 0;
273 	state.nobits_table = NULL;
274 	state.new_sec_string = NULL;
275 
276 	initialize(shnum, cmd_info, &state);
277 
278 	if ((ehdr.e_phnum != 0) &&
279 	    (build_segment_table(elf, &ehdr, &state) == FAILURE)) {
280 		x = error = FAILURE;
281 	} else if ((x = traverse_file(elf, &ehdr, cur_file,
282 	    cmd_info, &state)) == FAILURE) {
283 		error_message(WRN_MANIPULATED_ERROR, PLAIN_ERROR, NULL,
284 		    prog, cur_file);
285 		error = FAILURE;
286 	} else if (x != DONT_BUILD && x != FAILURE) {
287 		post_process(cmd_info, &state);
288 		if (build_file(elf, &ehdr, cmd_info, &state) == FAILURE) {
289 			error_message(WRN_MANIPULATED_ERROR, PLAIN_ERROR,
290 			    NULL, prog, cur_file);
291 			error = FAILURE;
292 		}
293 	}
294 
295 	/* Release any dynamicaly allocated buffers */
296 	if (state.b_e_seg_table != NULL)
297 		free(state.b_e_seg_table);
298 	if (state.sec_table != NULL)
299 		free(state.sec_table);
300 	if (state.off_table != NULL)
301 		free(state.off_table);
302 	if (state.nobits_table != NULL)
303 		free(state.nobits_table);
304 	if (state.new_sec_string != NULL)
305 		free(state.new_sec_string);
306 
307 	if (x == DONT_BUILD)
308 		return (DONT_BUILD);
309 	else
310 		return (error);
311 }
312 
313 static int
314 traverse_file(Elf *elf, GElf_Ehdr * ehdr, char *cur_file, Cmd_Info *cmd_info,
315     file_state_t *state)
316 {
317 	Elf_Scn *	scn;
318 	Elf_Scn *	temp_scn;
319 	Elf_Data *	data;
320 	GElf_Shdr *	shdr;
321 	char 		*temp_name;
322 	section_info_table *	sinfo;
323 	GElf_Xword 	x;
324 	int 		ret = 0, SYM = 0;	/* used by strip command */
325 	int 		phnum = ehdr->e_phnum;
326 	unsigned 	int i, scn_index;
327 	size_t 		shstrndx, shnum;
328 
329 	state->Sect_exists = 0;
330 
331 	if (elf_getshnum(elf, &shnum) == NULL) {
332 		error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
333 		return (FAILURE);
334 	}
335 	if (elf_getshstrndx(elf, &shstrndx) == NULL) {
336 		error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
337 		return (FAILURE);
338 	}
339 
340 	scn = 0;
341 	scn_index = 1;
342 	sinfo = &state->sec_table[scn_index];
343 	while ((scn = elf_nextscn(elf, scn)) != 0) {
344 		char *name;
345 
346 		shdr = &(sinfo->shdr);
347 		if (gelf_getshdr(scn, shdr) == NULL) {
348 			error_message(NO_SECT_TABLE_ERROR,
349 			    LIBelf_ERROR, elf_errmsg(-1), prog, cur_file);
350 			return (FAILURE);
351 		}
352 
353 		/*
354 		 * Note: If the object has problems, name
355 		 * may be set to NULL by the following.
356 		 */
357 		name = elf_strptr(elf, shstrndx, (size_t)shdr->sh_name);
358 
359 		sinfo->scn	= scn;
360 		sinfo->secno	= scn_index;
361 		sinfo->osecno	= scn_index;
362 		SET_ACTION(sinfo->flags, ACT_NOP);
363 		sinfo->name	= name;
364 		if (ehdr->e_phnum == 0)
365 			SET_LOC(sinfo->flags, NOSEG);
366 		else
367 			SET_LOC(sinfo->flags, scn_location(scn, elf, state));
368 
369 		if (shdr->sh_type == SHT_GROUP) {
370 			if (aplist_append(&cmd_info->sh_groups,
371 			    sinfo, 10) == NULL) {
372 				error_message(MALLOC_ERROR, PLAIN_ERROR,
373 				    NULL, prog);
374 				mcs_exit(FAILURE);
375 			}
376 		}
377 
378 		/*
379 		 * If the target section is pointed by a section
380 		 * holding relocation infomation, then the
381 		 * pointing section would be useless if the
382 		 * target section is removed.
383 		 */
384 		if ((shdr->sh_type == SHT_REL ||
385 		    shdr->sh_type == SHT_RELA) &&
386 		    (shdr->sh_info != SHN_UNDEF &&
387 		    (temp_scn = elf_getscn(elf, shdr->sh_info)) != 0)) {
388 			GElf_Shdr tmp_shdr;
389 			if (gelf_getshdr(temp_scn, &tmp_shdr) != NULL) {
390 				temp_name = elf_strptr(elf, shstrndx,
391 				    (size_t)tmp_shdr.sh_name);
392 				sinfo->rel_name = temp_name;
393 				sinfo->rel_scn_index =
394 				    shdr->sh_info;
395 				if (phnum == 0)
396 					sinfo->rel_loc = NOSEG;
397 				else
398 					sinfo->rel_loc =
399 					    scn_location(temp_scn, elf, state);
400 			}
401 		}
402 		data = 0;
403 		if ((data = elf_getdata(scn, data)) == NULL) {
404 			error_message(LIBELF_ERROR,
405 			    LIBelf_ERROR, elf_errmsg(-1), prog);
406 			return (FAILURE);
407 		}
408 		sinfo->data = data;
409 
410 		/*
411 		 * Check if this section is a candidate for
412 		 * action to be processes.
413 		 */
414 		if ((name != NULL) && (sectcmp(name) == 0)) {
415 			SET_CANDIDATE(sinfo->flags);
416 
417 			/*
418 			 * This flag just shows that there was a
419 			 * candidate.
420 			 */
421 			state->Sect_exists++;
422 		}
423 
424 		/*
425 		 * Any of the following section types should
426 		 * also be removed (if possible) if invoked via
427 		 * the 'strip' command.
428 		 */
429 		if (CHK_OPT(cmd_info, I_AM_STRIP) &&
430 		    ((shdr->sh_type == SHT_SUNW_DEBUG) ||
431 		    (shdr->sh_type == SHT_SUNW_DEBUGSTR))) {
432 			SET_CANDIDATE(sinfo->flags);
433 			state->Sect_exists++;
434 		}
435 
436 
437 		/*
438 		 * Zap this file ?
439 		 */
440 		if ((cmd_info->flags & zFLAG) &&
441 		    (shdr->sh_type == SHT_PROGBITS)) {
442 			SET_CANDIDATE(sinfo->flags);
443 			state->Sect_exists++;
444 		}
445 		x = GET_LOC(sinfo->flags);
446 
447 		/*
448 		 * Remember the note section index so that we can
449 		 * reset the NOTE segment offset to point to it. Depending
450 		 * on the operation being carried out, the note section may
451 		 * be assigned a new location in the resulting ELF
452 		 * image, and the program header needs to reflect that.
453 		 *
454 		 * There can be multiple contiguous note sections in
455 		 * an object, referenced by a single NOTE segment. We
456 		 * want to be sure and remember the one referenced by
457 		 * the program header, and not one of the others.
458 		 */
459 		if ((shdr->sh_type == SHT_NOTE) && (state->notesctndx == -1) &&
460 		    (state->notesegndx != -1) &&
461 		    (state->b_e_seg_table[state->notesegndx].p_offset
462 		    == shdr->sh_offset))
463 			state->notesctndx = scn_index;
464 
465 		if (x == IN || x == PRIOR)
466 			state->off_table[scn_index] = shdr->sh_offset;
467 		if (shdr->sh_type == SHT_NOBITS)
468 			state->nobits_table[scn_index] = 1;
469 
470 		/*
471 		 * If this section satisfies the condition,
472 		 * apply the actions specified.
473 		 */
474 		if (ISCANDIDATE(sinfo->flags)) {
475 			ret += apply_action(sinfo, cur_file, cmd_info);
476 		}
477 
478 		/*
479 		 * If I am strip command, determine if symtab can go or not.
480 		 */
481 		if (CHK_OPT(cmd_info, I_AM_STRIP) &&
482 		    (CHK_OPT(cmd_info, xFLAG) == 0) &&
483 		    (CHK_OPT(cmd_info, lFLAG) == 0)) {
484 			if (shdr->sh_type == SHT_SYMTAB &&
485 			    GET_LOC(sinfo->flags) == AFTER) {
486 				SYM = scn_index;
487 			}
488 		}
489 		scn_index++;
490 		sinfo++;
491 	}
492 	sinfo->scn	= (Elf_Scn *) -1;
493 
494 	/*
495 	 * If there were any errors traversing the file,
496 	 * just return error.
497 	 */
498 	if (ret != 0)
499 		return (FAILURE);
500 
501 	/*
502 	 * Remove symbol table if possible
503 	 */
504 	if (CHK_OPT(cmd_info, I_AM_STRIP) && SYM != 0) {
505 		GElf_Shdr tmp_shdr;
506 
507 		(void) gelf_getshdr(state->sec_table[SYM].scn, &tmp_shdr);
508 		state->sec_table[SYM].secno = (GElf_Word)DELETED;
509 		++(cmd_info->no_of_nulled);
510 		if (state->Sect_exists == 0)
511 			++state->Sect_exists;
512 		SET_ACTION(state->sec_table[SYM].flags, ACT_DELETE);
513 		state->off_table[SYM] = 0;
514 		/*
515 		 * Can I remove section header
516 		 * string table ?
517 		 */
518 		if ((tmp_shdr.sh_link < shnum) &&
519 		    (tmp_shdr.sh_link != SHN_UNDEF) &&
520 		    (tmp_shdr.sh_link != shstrndx) &&
521 		    (GET_LOC(state->sec_table[tmp_shdr.sh_link].flags) ==
522 		    AFTER)) {
523 			state->sec_table[tmp_shdr.sh_link].secno =
524 			    (GElf_Word)DELETED;
525 			++(cmd_info->no_of_nulled);
526 			if (state->Sect_exists == 0)
527 				++state->Sect_exists;
528 			SET_ACTION(state->sec_table[tmp_shdr.sh_link].flags,
529 			    ACT_DELETE);
530 			state->off_table[tmp_shdr.sh_link] = 0;
531 		}
532 	}
533 
534 	/*
535 	 * If I only printed the contents, then
536 	 * just report so.
537 	 */
538 	if (CHK_OPT(cmd_info, pFLAG) && !CHK_OPT(cmd_info, MIGHT_CHG))
539 		return (DONT_BUILD); /* don't bother creating a new file */
540 				/* since the file has not changed */
541 
542 	/*
543 	 * I might need to add a new section. Check it.
544 	 */
545 	if (state->Sect_exists == 0 && CHK_OPT(cmd_info, aFLAG)) {
546 		int act = 0;
547 		state->new_sec_string = calloc(1, cmd_info->str_size + 1);
548 		if (state->new_sec_string == NULL)
549 			return (FAILURE);
550 		for (act = 0; act < actmax; act++) {
551 			if (Action[act].a_action == ACT_APPEND) {
552 				(void) strcat(state->new_sec_string,
553 				    Action[act].a_string);
554 				(void) strcat(state->new_sec_string, "\n");
555 				cmd_info->no_of_append = 1;
556 			}
557 		}
558 	}
559 
560 	/*
561 	 * If I did not append any new sections, and I did not
562 	 * modify/delete any sections, then just report so.
563 	 */
564 	if ((state->Sect_exists == 0 && cmd_info->no_of_append == 0) ||
565 	    !CHK_OPT(cmd_info, MIGHT_CHG))
566 		return (DONT_BUILD);
567 
568 	/*
569 	 * Found at least one section which was processed.
570 	 *	Deleted or Appended or Compressed.
571 	 */
572 	if (state->Sect_exists) {
573 		/*
574 		 * First, handle the deleted sections.
575 		 */
576 		if (cmd_info->no_of_delete != 0 ||
577 		    cmd_info->no_of_nulled != 0) {
578 			int acc = 0;
579 			int rel_idx;
580 
581 			/*
582 			 * Handle relocation/target
583 			 * sections.
584 			 */
585 			sinfo = &(state->sec_table[0]);
586 			for (i = 1; i < shnum; i++) {
587 				sinfo++;
588 				rel_idx = sinfo->rel_scn_index;
589 				if (rel_idx == 0)
590 					continue;
591 
592 				/*
593 				 * If I am removed, then remove my
594 				 * target section.
595 				 */
596 				if (((sinfo->secno ==
597 				    (GElf_Word)DELETED) ||
598 				    (sinfo->secno ==
599 				    (GElf_Word)NULLED)) &&
600 				    sinfo->rel_loc != IN) {
601 					if (GET_LOC(state->
602 					    sec_table[rel_idx].flags) == PRIOR)
603 						state->sec_table[rel_idx].
604 						    secno = (GElf_Word)NULLED;
605 					else
606 						state->sec_table[rel_idx].
607 						    secno = (GElf_Word)DELETED;
608 					SET_ACTION(state->sec_table[rel_idx].
609 					    flags, ACT_DELETE);
610 				}
611 
612 				/*
613 				 * I am not removed. Check if my target is
614 				 * removed or nulled. If so, let me try to
615 				 * remove my self.
616 				 */
617 				if (((state->sec_table[rel_idx].secno ==
618 				    (GElf_Word)DELETED) ||
619 				    (state->sec_table[rel_idx].secno ==
620 				    (GElf_Word)NULLED)) &&
621 				    (GET_LOC(sinfo->flags) != IN)) {
622 					if (GET_LOC(sinfo->flags) ==
623 					    PRIOR)
624 						sinfo->secno =
625 						    (GElf_Word)NULLED;
626 					else
627 						sinfo->secno =
628 						    (GElf_Word)DELETED;
629 					SET_ACTION(sinfo->flags, ACT_DELETE);
630 				}
631 			}
632 
633 			/*
634 			 * Now, take care of DELETED sections
635 			 */
636 			sinfo = &(state->sec_table[1]);
637 			for (i = 1; i < shnum; i++) {
638 				shdr = &(sinfo->shdr);
639 				if (sinfo->secno == (GElf_Word)DELETED) {
640 					acc++;
641 					/*
642 					 * The SHT_GROUP section which this
643 					 * section is a member may be able
644 					 * to be removed. See post_process().
645 					 */
646 					if (shdr->sh_flags & SHF_GROUP)
647 						cmd_info->flags |=
648 						    SHF_GROUP_DEL;
649 				} else {
650 					/*
651 					 * The data buffer of SHT_GROUP this
652 					 * section is a member needs to be
653 					 * updated. See post_process().
654 					 */
655 					sinfo->secno -= acc;
656 					if ((shdr->sh_flags & SHF_GROUP) &&
657 					    (acc != 0))
658 						cmd_info->flags |=
659 						    SHF_GROUP_MOVE;
660 				}
661 				sinfo++;
662 			}
663 		}
664 	}
665 
666 	/*
667 	 * I know that the file has been modified.
668 	 * A new file need to be created.
669 	 */
670 	return (SUCCESS);
671 }
672 
673 static int
674 build_file(Elf *src_elf, GElf_Ehdr *src_ehdr, Cmd_Info *cmd_info,
675     file_state_t *state)
676 {
677 	Elf_Scn *src_scn;
678 	Elf_Scn *dst_scn;
679 	int	new_sh_name = 0;	/* to hold the offset for the new */
680 					/* section's name */
681 	Elf *dst_elf = 0;
682 	Elf_Data *elf_data;
683 	Elf_Data *data;
684 	int64_t scn_no, x;
685 	size_t no_of_symbols = 0;
686 	section_info_table *info;
687 	unsigned int    c = 0;
688 	int fdtmp;
689 	GElf_Shdr src_shdr;
690 	GElf_Shdr dst_shdr;
691 	GElf_Ehdr dst_ehdr;
692 	GElf_Off  new_offset = 0, r;
693 	size_t shnum, shstrndx;
694 
695 
696 	if (elf_getshnum(src_elf, &shnum) == NULL) {
697 		error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
698 		return (FAILURE);
699 	}
700 	if (elf_getshstrndx(src_elf, &shstrndx) == NULL) {
701 		error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
702 		return (FAILURE);
703 	}
704 
705 	if ((fdtmp = open(elftmpfile.tmp_name, O_RDWR | O_TRUNC | O_CREAT,
706 	    (mode_t)0666)) == -1) {
707 		error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno),
708 		    prog, elftmpfile.tmp_name);
709 		return (FAILURE);
710 	}
711 	elftmpfile.tmp_unlink = 1;
712 
713 	if ((dst_elf = elf_begin(fdtmp, ELF_C_WRITE, (Elf *) 0)) == NULL) {
714 		error_message(READ_ERROR, LIBelf_ERROR, elf_errmsg(-1),
715 		    prog, elftmpfile.tmp_name);
716 		(void) close(fdtmp);
717 		return (FAILURE);
718 	}
719 
720 	if (gelf_newehdr(dst_elf, gelf_getclass(src_elf)) == NULL) {
721 		error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
722 		return (FAILURE);
723 	}
724 
725 	/* initialize dst_ehdr */
726 	(void) gelf_getehdr(dst_elf, &dst_ehdr);
727 	dst_ehdr = *src_ehdr;
728 
729 	/*
730 	 * If we are removing the header string table section,
731 	 * remove the reference to it from the ELF header.
732 	 */
733 	if ((shstrndx != SHN_UNDEF) &&
734 	    (state->sec_table[shstrndx].secno == (GElf_Word)DELETED))
735 		dst_ehdr.e_shstrndx = SHN_UNDEF;
736 
737 	/*
738 	 * flush the changes to the ehdr so the ident
739 	 * array and header string table index are filled in.
740 	 */
741 	(void) gelf_update_ehdr(dst_elf, &dst_ehdr);
742 
743 
744 	if (src_ehdr->e_phnum != 0) {
745 		(void) elf_flagelf(dst_elf, ELF_C_SET, ELF_F_LAYOUT);
746 
747 		if (gelf_newphdr(dst_elf, src_ehdr->e_phnum) == NULL) {
748 			error_message(LIBELF_ERROR, LIBelf_ERROR,
749 			    elf_errmsg(-1), prog);
750 			return (FAILURE);
751 		}
752 
753 		for (x = 0; x < src_ehdr->e_phnum; ++x) {
754 			GElf_Phdr dst;
755 			GElf_Phdr src;
756 
757 			/* LINTED */
758 			(void) gelf_getphdr(src_elf, (int)x, &src);
759 			/* LINTED */
760 			(void) gelf_getphdr(dst_elf, (int)x, &dst);
761 			(void) memcpy(&dst, &src, sizeof (GElf_Phdr));
762 			/* LINTED */
763 			(void) gelf_update_phdr(dst_elf, (int)x, &dst);
764 		}
765 
766 		x = location(dst_ehdr.e_phoff, 0, src_elf, state);
767 		if (x == AFTER)
768 			new_offset = (GElf_Off)src_ehdr->e_ehsize;
769 	}
770 
771 	scn_no = 1;
772 	while ((src_scn = state->sec_table[scn_no].scn) != (Elf_Scn *) -1) {
773 		info = &state->sec_table[scn_no];
774 		/*  If section should be copied to new file NOW */
775 		if ((info->secno != (GElf_Word)DELETED) &&
776 		    info->secno <= scn_no) {
777 			if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
778 				error_message(LIBELF_ERROR,
779 				    LIBelf_ERROR, elf_errmsg(-1), prog);
780 				return (FAILURE);
781 			}
782 			(void) gelf_getshdr(dst_scn, &dst_shdr);
783 			(void) gelf_getshdr(info->scn, &src_shdr);
784 			(void) memcpy(&dst_shdr, &src_shdr, sizeof (GElf_Shdr));
785 
786 			/*
787 			 * Update link and info fields
788 			 * The sh_link field may have special values so
789 			 * check them first.
790 			 */
791 			if ((src_shdr.sh_link >= shnum) ||
792 			    (src_shdr.sh_link == 0))
793 				dst_shdr.sh_link = src_shdr.sh_link;
794 			else if ((int)state->sec_table[src_shdr.sh_link].secno <
795 			    0)
796 				dst_shdr.sh_link = 0;
797 			else
798 				dst_shdr.sh_link =
799 				    state->sec_table[src_shdr.sh_link].secno;
800 
801 			if ((src_shdr.sh_type == SHT_REL) ||
802 			    (src_shdr.sh_type == SHT_RELA)) {
803 				if ((src_shdr.sh_info >= shnum) ||
804 				    ((int)state->sec_table[src_shdr.
805 				    sh_info].secno < 0))
806 					dst_shdr.sh_info = 0;
807 				else
808 					dst_shdr.sh_info = state->
809 					    sec_table[src_shdr.sh_info].secno;
810 			}
811 
812 			data = state->sec_table[scn_no].data;
813 			if ((elf_data = elf_newdata(dst_scn)) == NULL) {
814 				error_message(LIBELF_ERROR,
815 				    LIBelf_ERROR, elf_errmsg(-1), prog);
816 				return (FAILURE);
817 			}
818 			*elf_data = *data;
819 
820 			/*
821 			 * SHT_{DYNSYM, SYMTAB} might need some change, as
822 			 * they may contain section symbols that reference
823 			 * removed sections. SHT_SUNW_LDYNSYM does not
824 			 * contain section symbols, and therefore does not
825 			 * have this issue.
826 			 */
827 			if (((src_shdr.sh_type == SHT_SYMTAB) ||
828 			    (src_shdr.sh_type == SHT_DYNSYM)) &&
829 			    src_shdr.sh_entsize != 0 &&
830 			    (cmd_info->no_of_delete != 0 ||
831 			    cmd_info->no_of_nulled != 0)) {
832 				char	*new_sym;
833 
834 				no_of_symbols = src_shdr.sh_size /
835 				    src_shdr.sh_entsize;
836 				new_sym = malloc(no_of_symbols *
837 				    src_shdr.sh_entsize);
838 				if (new_sym == NULL) {
839 					error_message(MALLOC_ERROR,
840 					    PLAIN_ERROR, NULL, prog);
841 					mcs_exit(FAILURE);
842 				}
843 
844 				/* CSTYLED */
845 				elf_data->d_buf = (void *) new_sym;
846 				for (c = 0; c < no_of_symbols; c++) {
847 					GElf_Sym csym;
848 
849 					(void) gelf_getsym(data, c, &csym);
850 
851 					if ((csym.st_shndx < SHN_LORESERVE) &&
852 					    (csym.st_shndx != SHN_UNDEF)) {
853 						section_info_table *i;
854 						i = &state->
855 						    sec_table[csym.st_shndx];
856 						if (((int)i->secno !=
857 						    DELETED) &&
858 						    ((int)i->secno != NULLED)) {
859 							csym.st_shndx =
860 							    i->secno;
861 						} else {
862 							/* BEGIN CSTYLED */
863 							if (src_shdr.sh_type ==
864 							    SHT_SYMTAB) {
865 							/*
866 							 * The section which
867 							 * this * symbol relates
868 							 * to is removed.
869 							 * There is no way to
870 							 * specify this fact,
871 							 * just change the shndx
872 							 * to 1.
873 							 */
874 							    csym.st_shndx = 1;
875 							} else {
876 							/*
877 							 * If this is in a
878 							 * .dynsym, NULL it out.
879 							 */
880 							    csym.st_shndx = 0;
881 							    csym.st_name = 0;
882 							    csym.st_value = 0;
883 							    csym.st_size = 0;
884 							    csym.st_info = 0;
885 							    csym.st_other = 0;
886 							    csym.st_shndx = 0;
887 							}
888 							/* END CSTYLED */
889 						}
890 					}
891 
892 					(void) gelf_update_sym(elf_data, c,
893 					    &csym);
894 				}
895 			}
896 
897 			/* update SHT_SYMTAB_SHNDX */
898 			if ((src_shdr.sh_type == SHT_SYMTAB_SHNDX) &&
899 			    (src_shdr.sh_entsize != 0) &&
900 			    ((cmd_info->no_of_delete != 0) ||
901 			    (cmd_info->no_of_nulled != 0))) {
902 				GElf_Word	*oldshndx;
903 				GElf_Word	*newshndx;
904 				uint_t		entcnt;
905 
906 				entcnt = src_shdr.sh_size /
907 				    src_shdr.sh_entsize;
908 				oldshndx = data->d_buf;
909 				newshndx = malloc(entcnt * src_shdr.sh_entsize);
910 				if (newshndx == NULL) {
911 					error_message(MALLOC_ERROR,
912 					    PLAIN_ERROR, NULL, prog);
913 					mcs_exit(FAILURE);
914 				}
915 				elf_data->d_buf = (void *)newshndx;
916 				for (c = 0; c < entcnt; c++) {
917 					if (oldshndx[c] != SHN_UNDEF) {
918 						section_info_table *i;
919 						i = &state->
920 						    sec_table[oldshndx[c]];
921 						if (((int)i->secno !=
922 						    DELETED) &&
923 						    ((int)i->secno != NULLED))
924 							newshndx[c] = i->secno;
925 						else
926 							newshndx[c] =
927 							    oldshndx[c];
928 					} else
929 							newshndx[c] =
930 							    oldshndx[c];
931 				}
932 			}
933 
934 			/*
935 			 * If the section is to be updated,
936 			 * do so.
937 			 */
938 			if (ISCANDIDATE(info->flags)) {
939 				if ((GET_LOC(info->flags) == PRIOR) &&
940 				    (((int)info->secno == NULLED) ||
941 				    ((int)info->secno == EXPANDED) ||
942 				    ((int)info->secno == SHRUNK))) {
943 					/*
944 					 * The section is updated,
945 					 * but the position is not too
946 					 * good. Need to NULL this out.
947 					 */
948 					dst_shdr.sh_name = 0;
949 					dst_shdr.sh_type = SHT_PROGBITS;
950 					if ((int)info->secno != NULLED) {
951 						(cmd_info->no_of_moved)++;
952 						SET_MOVING(info->flags);
953 					}
954 				} else {
955 					/*
956 					 * The section is positioned AFTER,
957 					 * or there are no segments.
958 					 * It is safe to update this section.
959 					 */
960 					data = state->sec_table[scn_no].mdata;
961 					*elf_data = *data;
962 					dst_shdr.sh_size = elf_data->d_size;
963 				}
964 			}
965 			/* add new section name to shstrtab? */
966 			else if (!state->Sect_exists &&
967 			    (state->new_sec_string != NULL) &&
968 			    (scn_no == shstrndx) &&
969 			    (dst_shdr.sh_type == SHT_STRTAB) &&
970 			    ((src_ehdr->e_phnum == 0) ||
971 			    ((x = scn_location(dst_scn, dst_elf, state))
972 			    != IN) ||
973 			    (x != PRIOR))) {
974 				size_t sect_len;
975 
976 				sect_len = strlen(SECT_NAME);
977 				if ((elf_data->d_buf =
978 				    malloc((dst_shdr.sh_size +
979 				    sect_len + 1))) == NULL) {
980 					error_message(MALLOC_ERROR,
981 					    PLAIN_ERROR, NULL, prog);
982 					mcs_exit(FAILURE);
983 				}
984 				/* put original data plus new data in section */
985 				(void) memcpy(elf_data->d_buf,
986 				    data->d_buf, data->d_size);
987 				(void) memcpy(&((char *)elf_data->d_buf)
988 				    [data->d_size], SECT_NAME, sect_len + 1);
989 				/* LINTED */
990 				new_sh_name = (int)dst_shdr.sh_size;
991 				dst_shdr.sh_size += sect_len + 1;
992 				elf_data->d_size += sect_len + 1;
993 			}
994 
995 			/*
996 			 * Compute offsets.
997 			 */
998 			if (src_ehdr->e_phnum != 0) {
999 				/*
1000 				 * Compute section offset.
1001 				 */
1002 				if (state->off_table[scn_no] == 0) {
1003 					if (dst_shdr.sh_addralign != 0) {
1004 						r = new_offset %
1005 						    dst_shdr.sh_addralign;
1006 						if (r)
1007 							new_offset +=
1008 							    dst_shdr.
1009 							    sh_addralign - r;
1010 					}
1011 					dst_shdr.sh_offset = new_offset;
1012 					elf_data->d_off = 0;
1013 				} else {
1014 					if (state->nobits_table[scn_no] == 0)
1015 						new_offset =
1016 						    state->off_table[scn_no];
1017 				}
1018 				if (state->nobits_table[scn_no] == 0)
1019 					new_offset += dst_shdr.sh_size;
1020 			}
1021 
1022 			/* flush changes */
1023 			(void) gelf_update_shdr(dst_scn, &dst_shdr);
1024 		}
1025 		scn_no++;
1026 	}
1027 
1028 	/*
1029 	 * This is the real new section.
1030 	 */
1031 	if (!state->Sect_exists && state->new_sec_string != NULL) {
1032 		size_t string_size;
1033 		string_size = strlen(state->new_sec_string) + 1;
1034 		if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
1035 			error_message(LIBELF_ERROR,
1036 			    LIBelf_ERROR, elf_errmsg(-1), prog);
1037 			return (FAILURE);
1038 		}
1039 		(void) gelf_getshdr(dst_scn, &dst_shdr);
1040 
1041 		dst_shdr.sh_name = new_sh_name;
1042 		dst_shdr.sh_type = SHT_PROGBITS;
1043 		dst_shdr.sh_flags = 0;
1044 		dst_shdr.sh_addr = 0;
1045 		if (src_ehdr->e_phnum != NULL)
1046 			dst_shdr.sh_offset = new_offset;
1047 		else
1048 			dst_shdr.sh_offset = 0;
1049 		dst_shdr.sh_size = string_size + 1;
1050 		dst_shdr.sh_link = 0;
1051 		dst_shdr.sh_info = 0;
1052 		dst_shdr.sh_addralign = 1;
1053 		dst_shdr.sh_entsize = 0;
1054 		(void) gelf_update_shdr(dst_scn, &dst_shdr); /* flush changes */
1055 
1056 		if ((elf_data = elf_newdata(dst_scn)) == NULL) {
1057 			error_message(LIBELF_ERROR,
1058 			    LIBelf_ERROR, elf_errmsg(-1), prog);
1059 			return (FAILURE);
1060 		}
1061 		elf_data->d_size = string_size + 1;
1062 		if ((elf_data->d_buf = (char *)
1063 		    calloc(1, string_size + 1)) == NULL) {
1064 			error_message(MALLOC_ERROR,
1065 			    PLAIN_ERROR, NULL, prog);
1066 			mcs_exit(FAILURE);
1067 		}
1068 		(void) memcpy(&((char *)elf_data->d_buf)[1],
1069 		    state->new_sec_string, string_size);
1070 		elf_data->d_align = 1;
1071 		new_offset += string_size + 1;
1072 	}
1073 
1074 	/*
1075 	 * If there are sections which needed to be moved,
1076 	 * then do it here.
1077 	 */
1078 	if (cmd_info->no_of_moved != 0) {
1079 		int cnt;
1080 		info = &state->sec_table[0];
1081 
1082 		for (cnt = 0; cnt < shnum; cnt++, info++) {
1083 			if ((GET_MOVING(info->flags)) == 0)
1084 				continue;
1085 
1086 			if ((src_scn = elf_getscn(src_elf, info->osecno)) ==
1087 			    NULL) {
1088 				error_message(LIBELF_ERROR,
1089 				    LIBelf_ERROR, elf_errmsg(-1), prog);
1090 				return (FAILURE);
1091 			}
1092 			if (gelf_getshdr(src_scn, &src_shdr) == NULL) {
1093 				error_message(LIBELF_ERROR,
1094 				    LIBelf_ERROR, elf_errmsg(-1), prog);
1095 				return (FAILURE);
1096 			}
1097 			if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
1098 				error_message(LIBELF_ERROR,
1099 				    LIBelf_ERROR, elf_errmsg(-1), prog);
1100 				return (FAILURE);
1101 			}
1102 			if (gelf_getshdr(dst_scn, &dst_shdr) == NULL) {
1103 				error_message(LIBELF_ERROR,
1104 				    LIBelf_ERROR, elf_errmsg(-1), prog);
1105 				return (FAILURE);
1106 			}
1107 			dst_shdr = src_shdr;
1108 
1109 			data = info->mdata;
1110 
1111 			dst_shdr.sh_offset = new_offset;  /* UPDATE fields */
1112 			dst_shdr.sh_size = data->d_size;
1113 
1114 			if ((shnum >= src_shdr.sh_link) ||
1115 			    (src_shdr.sh_link == 0))
1116 				dst_shdr.sh_link = src_shdr.sh_link;
1117 			else
1118 				dst_shdr.sh_link =
1119 				    state->sec_table[src_shdr.sh_link].osecno;
1120 
1121 			if ((shnum >= src_shdr.sh_info) ||
1122 			    (src_shdr.sh_info == 0))
1123 				dst_shdr.sh_info = src_shdr.sh_info;
1124 			else
1125 				dst_shdr.sh_info =
1126 				    state->sec_table[src_shdr.sh_info].osecno;
1127 			(void) gelf_update_shdr(dst_scn, &dst_shdr);
1128 			if ((elf_data = elf_newdata(dst_scn)) == NULL) {
1129 				error_message(LIBELF_ERROR,
1130 				    LIBelf_ERROR, elf_errmsg(-1), prog);
1131 				return (FAILURE);
1132 			}
1133 			(void) memcpy(elf_data, data, sizeof (Elf_Data));
1134 
1135 			new_offset += data->d_size;
1136 		}
1137 	}
1138 
1139 	/*
1140 	 * In the event that the position of the sting table has changed,
1141 	 * as a result of deleted sections, update the ehdr->e_shstrndx.
1142 	 */
1143 	if ((shstrndx > 0) && (shnum > 0) &&
1144 	    (state->sec_table[shstrndx].secno < shnum)) {
1145 		if (state->sec_table[shstrndx].secno < SHN_LORESERVE) {
1146 			dst_ehdr.e_shstrndx =
1147 			    state->sec_table[dst_ehdr.e_shstrndx].secno;
1148 		} else {
1149 			Elf_Scn		*_scn;
1150 			GElf_Shdr	shdr0;
1151 
1152 			/*
1153 			 * If shstrndx requires 'Extended ELF Sections'
1154 			 * then it is stored in shdr[0].sh_link
1155 			 */
1156 			dst_ehdr.e_shstrndx = SHN_XINDEX;
1157 			if ((_scn = elf_getscn(dst_elf, 0)) == NULL) {
1158 				error_message(LIBELF_ERROR,
1159 				    LIBelf_ERROR, elf_errmsg(-1), prog);
1160 				return (FAILURE);
1161 			}
1162 			(void) gelf_getshdr(_scn, &shdr0);
1163 			shdr0.sh_link = state->sec_table[shstrndx].secno;
1164 			(void) gelf_update_shdr(_scn, &shdr0);
1165 		}
1166 	}
1167 
1168 	if (src_ehdr->e_phnum != 0) {
1169 		size_t align = gelf_fsize(dst_elf, ELF_T_ADDR, 1, EV_CURRENT);
1170 
1171 		/* UPDATE location of program header table */
1172 		if (location(dst_ehdr.e_phoff, 0, dst_elf, state) == AFTER) {
1173 			r = new_offset % align;
1174 			if (r)
1175 				new_offset += align - r;
1176 
1177 			dst_ehdr.e_phoff = new_offset;
1178 			new_offset += dst_ehdr.e_phnum * dst_ehdr.e_phentsize;
1179 		}
1180 		/* UPDATE location of section header table */
1181 		if ((location(dst_ehdr.e_shoff, 0, src_elf, state) == AFTER) ||
1182 		    ((location(dst_ehdr.e_shoff, 0, src_elf, state) == PRIOR) &&
1183 		    (!state->Sect_exists && state->new_sec_string != NULL))) {
1184 			r = new_offset % align;
1185 			if (r)
1186 				new_offset += align - r;
1187 
1188 			dst_ehdr.e_shoff = new_offset;
1189 		}
1190 
1191 		/*
1192 		 * The NOTE segment is the one segment whos
1193 		 * sections might get moved by mcs processing.
1194 		 * Make sure that the NOTE segments offset points
1195 		 * to the .note section.
1196 		 */
1197 		if ((state->notesegndx != -1) && (state->notesctndx != -1) &&
1198 		    (state->sec_table[state->notesctndx].secno)) {
1199 			Elf_Scn *	notescn;
1200 			GElf_Shdr	nshdr;
1201 
1202 			notescn = elf_getscn(dst_elf,
1203 			    state->sec_table[state->notesctndx].secno);
1204 			(void) gelf_getshdr(notescn, &nshdr);
1205 
1206 			if (gelf_getclass(dst_elf) == ELFCLASS32) {
1207 				Elf32_Phdr * ph	= elf32_getphdr(dst_elf) +
1208 				    state->notesegndx;
1209 				/* LINTED */
1210 				ph->p_offset	= (Elf32_Off)nshdr.sh_offset;
1211 			} else {
1212 				Elf64_Phdr * ph	= elf64_getphdr(dst_elf) +
1213 				    state->notesegndx;
1214 				ph->p_offset	= (Elf64_Off)nshdr.sh_offset;
1215 			}
1216 		}
1217 	}
1218 
1219 	/* copy ehdr changes back into real ehdr */
1220 	(void) gelf_update_ehdr(dst_elf, &dst_ehdr);
1221 	if (elf_update(dst_elf, ELF_C_WRITE) < 0) {
1222 		error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
1223 		return (FAILURE);
1224 	}
1225 
1226 	(void) elf_end(dst_elf);
1227 	(void) close(fdtmp);
1228 	return (SUCCESS);
1229 }
1230 
1231 /*
1232  * Search through PHT saving the beginning and ending segment offsets
1233  */
1234 static int
1235 build_segment_table(Elf * elf, GElf_Ehdr * ehdr, file_state_t *state)
1236 {
1237 	unsigned int i;
1238 
1239 	state->b_e_seg_table = (Seg_Table *)
1240 	    calloc(ehdr->e_phnum, sizeof (Seg_Table));
1241 	if (state->b_e_seg_table == NULL) {
1242 		error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog);
1243 		mcs_exit(FAILURE);
1244 	}
1245 
1246 	for (i = 0; i < ehdr->e_phnum; i++) {
1247 		GElf_Phdr ph;
1248 
1249 		(void) gelf_getphdr(elf, i, &ph);
1250 
1251 		/*
1252 		 * remember the note SEGMENTS index so that we can
1253 		 * re-set it's p_offset later if needed.
1254 		 */
1255 		if (ph.p_type == PT_NOTE)
1256 			state->notesegndx = i;
1257 
1258 		state->b_e_seg_table[i].p_offset = ph.p_offset;
1259 		state->b_e_seg_table[i].p_memsz  = ph.p_offset + ph.p_memsz;
1260 		state->b_e_seg_table[i].p_filesz = ph.p_offset + ph.p_filesz;
1261 	}
1262 	return (SUCCESS);
1263 }
1264 
1265 
1266 static void
1267 copy_elf_file_to_temp_ar_file(
1268 	int fdartmp,
1269 	Elf_Arhdr *mem_header,
1270 	char *cur_file)
1271 {
1272 	char *buf;
1273 	char mem_header_buf[sizeof (struct ar_hdr) + 1];
1274 	int fdtmp3;
1275 	struct stat stbuf;
1276 
1277 	if ((fdtmp3 = open(elftmpfile.tmp_name, O_RDONLY)) == -1) {
1278 		error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno),
1279 		    prog, elftmpfile.tmp_name);
1280 		mcs_exit(FAILURE);
1281 	}
1282 
1283 	(void) stat(elftmpfile.tmp_name, &stbuf); /* for size of file */
1284 
1285 	if ((buf =
1286 	    malloc(ROUNDUP(stbuf.st_size))) == NULL) {
1287 		error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog);
1288 		mcs_exit(FAILURE);
1289 	}
1290 
1291 	if (read(fdtmp3, buf, stbuf.st_size) != stbuf.st_size) {
1292 		error_message(READ_MANI_ERROR, SYSTEM_ERROR, strerror(errno),
1293 		    prog, elftmpfile.tmp_name, cur_file);
1294 		mcs_exit(FAILURE);
1295 	}
1296 
1297 	(void) sprintf(mem_header_buf, FORMAT, mem_header->ar_rawname,
1298 	    mem_header->ar_date, (unsigned)mem_header->ar_uid,
1299 	    (unsigned)mem_header->ar_gid, (unsigned)mem_header->ar_mode,
1300 	    stbuf.st_size, ARFMAG);
1301 
1302 	if (write(fdartmp, mem_header_buf,
1303 	    (unsigned)sizeof (struct ar_hdr)) !=
1304 	    (unsigned)sizeof (struct ar_hdr)) {
1305 		error_message(WRITE_MANI_ERROR, SYSTEM_ERROR, strerror(errno),
1306 		    prog, elftmpfile.tmp_name, cur_file);
1307 		mcs_exit(FAILURE);
1308 	}
1309 
1310 	if (stbuf.st_size & 0x1) {
1311 		buf[stbuf.st_size] = '\n';
1312 		if (write(fdartmp, buf, (size_t)ROUNDUP(stbuf.st_size)) !=
1313 		    (size_t)ROUNDUP(stbuf.st_size)) {
1314 			error_message(WRITE_MANI_ERROR,	SYSTEM_ERROR,
1315 			    strerror(errno), prog, elftmpfile.tmp_name,
1316 			    cur_file);
1317 			mcs_exit(FAILURE);
1318 		}
1319 	} else if (write(fdartmp, buf, stbuf.st_size) != stbuf.st_size) {
1320 			error_message(WRITE_MANI_ERROR, SYSTEM_ERROR,
1321 			    strerror(errno), prog, elftmpfile.tmp_name,
1322 			    cur_file);
1323 			mcs_exit(FAILURE);
1324 	}
1325 	free(buf);
1326 	(void) close(fdtmp3);
1327 }
1328 
1329 static void
1330 copy_non_elf_to_temp_ar(
1331 	int fd,
1332 	Elf *elf,
1333 	int fdartmp,
1334 	Elf_Arhdr *mem_header,
1335 	char *cur_file,
1336 	Cmd_Info *cmd_info)
1337 {
1338 	char    mem_header_buf[sizeof (struct ar_hdr) + 1];
1339 	char *file_buf;
1340 
1341 	if (strcmp(mem_header->ar_name, "/") != 0) {
1342 		(void) sprintf(mem_header_buf, FORMAT, mem_header->ar_rawname,
1343 		    mem_header->ar_date, (unsigned)mem_header->ar_uid,
1344 		    (unsigned)mem_header->ar_gid, (unsigned)mem_header->ar_mode,
1345 		    mem_header->ar_size, ARFMAG);
1346 
1347 		if (write(fdartmp, mem_header_buf, sizeof (struct ar_hdr)) !=
1348 		    sizeof (struct ar_hdr)) {
1349 			error_message(WRITE_MANI_ERROR, SYSTEM_ERROR,
1350 			    strerror(errno), prog, cur_file);
1351 			mcs_exit(FAILURE);
1352 		}
1353 		if ((file_buf =
1354 		    malloc(ROUNDUP(mem_header->ar_size))) == NULL) {
1355 			error_message(MALLOC_ERROR, PLAIN_ERROR, NULL,
1356 			    prog);
1357 			mcs_exit(FAILURE);
1358 		}
1359 
1360 		if (lseek(fd, elf_getbase(elf), 0) != elf_getbase(elf)) {
1361 			error_message(WRITE_MANI_ERROR, prog, cur_file);
1362 			mcs_exit(FAILURE);
1363 		}
1364 
1365 		if (read(fd, file_buf,
1366 		    (size_t)ROUNDUP(mem_header->ar_size)) !=
1367 		    (size_t)ROUNDUP(mem_header->ar_size)) {
1368 			error_message(READ_MANI_ERROR, SYSTEM_ERROR,
1369 			    strerror(errno), prog, cur_file);
1370 			mcs_exit(FAILURE);
1371 		}
1372 		if (write(fdartmp,
1373 		    file_buf,
1374 		    (size_t)ROUNDUP(mem_header->ar_size)) !=
1375 		    (size_t)ROUNDUP(mem_header->ar_size)) {
1376 			error_message(WRITE_MANI_ERROR, SYSTEM_ERROR,
1377 			    strerror(errno), prog, cur_file);
1378 			mcs_exit(FAILURE);
1379 		}
1380 		free(file_buf);
1381 	} else if (CHK_OPT(cmd_info, MIGHT_CHG)) {
1382 		error_message(SYM_TAB_AR_ERROR, PLAIN_ERROR, NULL,
1383 		    prog, cur_file);
1384 		error_message(EXEC_AR_ERROR, PLAIN_ERROR, NULL, cur_file);
1385 	}
1386 }
1387 
1388 /*
1389  * Replace contents of file
1390  *
1391  * entry:
1392  *	ofd - Open file descriptor for file fname
1393  *	fname - Name of file being processed
1394  *	temp_file_name - Address of pointer to temporary
1395  *		file containing new contents for fname.
1396  *
1397  * exit:
1398  *	The contents of the file given by temp_file->tmp_name are
1399  *	copied to the file fname. The temporary file is
1400  *	unlinked, and temp_file reset.
1401  */
1402 static void
1403 copy_file(int ofd, char *fname, Tmp_File *temp_file)
1404 {
1405 	enum { MMAP_USED, MMAP_UNUSED } mmap_status;
1406 	int		i;
1407 	int		fdtmp2;
1408 	struct stat	stbuf;
1409 	char		*buf;
1410 
1411 	for (i = 0; signum[i]; i++) /* started writing, cannot interrupt */
1412 		(void) signal(signum[i], SIG_IGN);
1413 
1414 	if ((fdtmp2 = open(temp_file->tmp_name, O_RDONLY)) == -1) {
1415 		error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno),
1416 		    prog, temp_file->tmp_name);
1417 		mcs_exit(FAILURE);
1418 	}
1419 
1420 	(void) stat(temp_file->tmp_name, &stbuf); /* for size of file */
1421 
1422 	/*
1423 	 * Get the contents of the updated file.
1424 	 * First try mmap()'ing. If mmap() fails,
1425 	 * then use the malloc() and read().
1426 	 */
1427 	mmap_status = MMAP_USED;
1428 	buf = (char *)mmap(0, stbuf.st_size, PROT_READ, MAP_SHARED, fdtmp2, 0);
1429 	if (buf == (caddr_t)-1) {
1430 		if ((buf =
1431 		    malloc(stbuf.st_size * sizeof (char))) == NULL) {
1432 			error_message(MALLOC_ERROR, PLAIN_ERROR, NULL,
1433 			    prog);
1434 			mcs_exit(FAILURE);
1435 		}
1436 
1437 		if (read(fdtmp2, buf, stbuf.st_size) != stbuf.st_size) {
1438 			error_message(READ_SYS_ERROR, SYSTEM_ERROR,
1439 			    strerror(errno), prog, temp_file->tmp_name);
1440 			mcs_exit(FAILURE);
1441 		}
1442 		mmap_status = MMAP_UNUSED;
1443 	}
1444 
1445 	if (ftruncate(ofd, 0) == -1) {
1446 		error_message(WRITE_MANI_ERROR2, SYSTEM_ERROR, strerror(errno),
1447 		    prog, fname);
1448 		mcs_exit(FAILURE);
1449 	}
1450 	if (lseek(ofd, 0, SEEK_SET) == -1) {
1451 		error_message(WRITE_MANI_ERROR2, SYSTEM_ERROR, strerror(errno),
1452 		    prog, fname);
1453 		mcs_exit(FAILURE);
1454 	}
1455 	if ((write(ofd, buf, stbuf.st_size)) != stbuf.st_size) {
1456 		error_message(WRITE_MANI_ERROR2, SYSTEM_ERROR, strerror(errno),
1457 		    prog, fname);
1458 		mcs_exit(FAILURE);
1459 	}
1460 
1461 	/*
1462 	 * clean
1463 	 */
1464 	if (mmap_status == MMAP_USED)
1465 		(void) munmap(buf, stbuf.st_size);
1466 	else
1467 		free(buf);
1468 	(void) close(fdtmp2);
1469 	free_tempfile(temp_file);
1470 }
1471 
1472 static uint64_t
1473 location(int64_t offset, int mem_search, Elf * elf, file_state_t *state)
1474 {
1475 	int i;
1476 	uint64_t upper;
1477 	GElf_Ehdr ehdr;
1478 
1479 	(void) gelf_getehdr(elf, &ehdr);
1480 
1481 	for (i = 0; i < ehdr.e_phnum; i++) {
1482 		if (mem_search)
1483 			upper = state->b_e_seg_table[i].p_memsz;
1484 		else
1485 			upper = state->b_e_seg_table[i].p_filesz;
1486 		if ((offset >= state->b_e_seg_table[i].p_offset) &&
1487 		    (offset <= upper))
1488 			return (IN);
1489 		else if (offset < state->b_e_seg_table[i].p_offset)
1490 			return (PRIOR);
1491 	}
1492 	return (AFTER);
1493 }
1494 
1495 static uint64_t
1496 scn_location(Elf_Scn * scn, Elf * elf, file_state_t *state)
1497 {
1498 	GElf_Shdr shdr;
1499 
1500 	(void) gelf_getshdr(scn, &shdr);
1501 
1502 	/*
1503 	 * If the section is not a NOTE section and it has no
1504 	 * virtual address then it is not part of a mapped segment.
1505 	 */
1506 	if (shdr.sh_addr == 0)
1507 		return (location(shdr.sh_offset + shdr.sh_size, 0, elf, state));
1508 
1509 	return (location(shdr.sh_offset + shdr.sh_size, 1, elf, state));
1510 }
1511 
1512 static void
1513 initialize(int shnum, Cmd_Info *cmd_info, file_state_t *state)
1514 {
1515 	/*
1516 	 * Initialize command info
1517 	 */
1518 	cmd_info->no_of_append = cmd_info->no_of_delete =
1519 	    cmd_info->no_of_nulled = cmd_info->no_of_compressed =
1520 	    cmd_info->no_of_moved = 0;
1521 	cmd_info->sh_groups = NULL;
1522 
1523 	state->sec_table = (section_info_table *)
1524 	    calloc(shnum + 1, sizeof (section_info_table));
1525 	if (state->sec_table == NULL) {
1526 		error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog);
1527 		mcs_exit(FAILURE);
1528 	}
1529 
1530 	state->off_table = (int64_t *)calloc(shnum, sizeof (int64_t));
1531 	if (state->off_table == NULL) {
1532 		error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog);
1533 		mcs_exit(FAILURE);
1534 	}
1535 
1536 	state->nobits_table = (int64_t *)calloc(shnum, sizeof (int64_t));
1537 	if (state->nobits_table == NULL) {
1538 		error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog);
1539 		mcs_exit(FAILURE);
1540 	}
1541 }
1542 
1543 /*
1544  * Update the contents of SHT_GROUP if needed
1545  */
1546 static void
1547 post_process(Cmd_Info *cmd_info, file_state_t *state)
1548 {
1549 	Aliste			idx;
1550 	section_info_table	*sinfo;
1551 	Word			*grpdata, *ngrpdata;
1552 	int64_t			sno, sno2;
1553 	Word			i, j, num;
1554 
1555 	/*
1556 	 * If no change is required, then return.
1557 	 */
1558 	if ((cmd_info->flags & (SHF_GROUP_MOVE|SHF_GROUP_DEL)) == 0)
1559 		return;
1560 
1561 	/*
1562 	 * If SHF_GROUP sections were removed, we might need to
1563 	 * remove SHT_GROUP sections.
1564 	 */
1565 	if (cmd_info->flags & SHF_GROUP_DEL) {
1566 		Word	grpcnt;
1567 		int	deleted = 0;
1568 
1569 		for (APLIST_TRAVERSE(cmd_info->sh_groups, idx, sinfo)) {
1570 			if (sinfo->secno == (GElf_Word)DELETED)
1571 				continue;
1572 			num = (sinfo->shdr).sh_size/sizeof (Word);
1573 			grpcnt = 0;
1574 			grpdata = (Word *)(sinfo->data->d_buf);
1575 			for (i = 1; i < num; i++) {
1576 				if (state->sec_table[grpdata[i]].secno !=
1577 				    (GElf_Word)DELETED)
1578 					grpcnt++;
1579 			}
1580 
1581 			/*
1582 			 * All members in this SHT_GROUP were removed.
1583 			 * We can remove this SHT_GROUP.
1584 			 */
1585 			if (grpcnt == 0) {
1586 				sinfo->secno = (GElf_Word)DELETED;
1587 				(cmd_info->no_of_delete)++;
1588 				deleted = 1;
1589 			}
1590 		}
1591 
1592 		/*
1593 		 * If we deleted a SHT_GROUP section,
1594 		 * we need to reasign section numbers.
1595 		 */
1596 		if (deleted) {
1597 			section_info_table *sinfo;
1598 
1599 			sno = 1;
1600 			sno2 = 1;
1601 			while (state->sec_table[sno].scn != (Elf_Scn *)-1) {
1602 				sinfo = &state->sec_table[sno];
1603 				if (sinfo->secno != (GElf_Word) DELETED)
1604 					sinfo->secno = sno2++;
1605 				sno++;
1606 			}
1607 		}
1608 	}
1609 
1610 	/*
1611 	 * Now we can update data buffers of the SHT_GROUP sections.
1612 	 */
1613 	for (APLIST_TRAVERSE(cmd_info->sh_groups, idx, sinfo)) {
1614 		if (sinfo->secno == (GElf_Word)DELETED)
1615 			continue;
1616 		num = (sinfo->shdr).sh_size/sizeof (Word);
1617 
1618 		/*
1619 		 * Need to generate the updated data buffer
1620 		 */
1621 		if ((sinfo->mdata = malloc(sizeof (Elf_Data))) == NULL) {
1622 			error_message(MALLOC_ERROR, PLAIN_ERROR, NULL,
1623 			    prog);
1624 			mcs_exit(FAILURE);
1625 		}
1626 		*(sinfo->mdata) = *(sinfo->data);
1627 		if ((ngrpdata = sinfo->mdata->d_buf =
1628 		    malloc(sinfo->data->d_size)) == NULL) {
1629 			error_message(MALLOC_ERROR, PLAIN_ERROR, NULL,
1630 			    prog);
1631 			mcs_exit(FAILURE);
1632 		}
1633 
1634 		grpdata = (Word *)(sinfo->data->d_buf);
1635 		ngrpdata[0] = grpdata[0];
1636 		j = 1;
1637 		for (i = 1; i < num; i++) {
1638 			if (state->sec_table[grpdata[i]].secno !=
1639 			    (GElf_Word)DELETED) {
1640 				ngrpdata[j++] =
1641 				    state->sec_table[grpdata[i]].secno;
1642 			}
1643 		}
1644 		sinfo->mdata->d_size = j * sizeof (Word);
1645 		sinfo->data = sinfo->mdata;
1646 	}
1647 	free(cmd_info->sh_groups);
1648 	cmd_info->sh_groups = NULL;
1649 }
1650