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