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