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