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