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