# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # #ident "%Z%%M% %I% %E% SMI" # # Copyright (c) 1996 by Sun Microsystems, Inc. # All Rights Reserved. # # cmd/sgs/mcs/Makefile # include $(SRC)/cmd/sgs/Makefile.sub # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # PROG= mcs STRIPFILE= strip ROOTLINKS= $(ROOTBIN)/$(STRIPFILE) ROOTSTRIPFILEPROG= $(STRIPFILE:%=$(ROOTCCSBIN)/%) ROOTSTRIPFILEPROG64= $(STRIPFILE:%=$(ROOTCCSBIN64)/%) include $(SRC)/cmd/Makefile.cmd include $(SRC)/cmd/sgs/Makefile.com include $(SRC)/cmd/Makefile.ctf COMOBJS = main.o file.o utils.o global.o \ message.o SGSCOMMONOBJ = alist.o OBJS = $(COMOBJS) $(SGSCOMMONOBJ) LLDFLAGS = '-R$$ORIGIN/../../lib' LLDFLAGS64 = '-R$$ORIGIN/../../../lib/$(MACH64)' LDFLAGS += $(VERSREF) $(LLDFLAGS) LDLIBS += $(CONVLIBDIR) -lconv $(ELFLIBDIR) -lelf CERRWARN += $(CNOWARN_UNINIT) SRCS = $(COMOBJS:%.o=../common/%.c) \ $(SGSCOMMONOBJ:%.o=$(SGSCOMMON)/%.c) CLEANFILES += $(OBJS) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # %.o: ../common/%.c $(COMPILE.c) $< $(POST_PROCESS_O) %.o: $(SGSCOMMON)/%.c $(COMPILE.c) $< $(POST_PROCESS_O) all: $(PROG) $(STRIPFILE) clean: $(RM) $(CLEANFILES) $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) $(STRIPFILE): $(ROOTLINKS): $(ROOTPROG) $(RM) $@ $(LN) $(ROOTPROG) $@ $(ROOTBIN64)/%: % $(INS.file) $(ROOTSTRIPFILEPROG): $(RM) $@ $(SYMLINK) ../../bin/$(STRIPFILE) $@ # Hammerhead: ROOTSTRIPFILEPROG64=ROOTSTRIPFILEPROG (path flattening) # Removed duplicate 64-bit rule with invalid ../../../bin/amd64/ path include $(SRC)/cmd/Makefile.targ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # include ../Makefile.com .KEEP_STATE: LLDFLAGS= $(LLDFLAGS64) CONVLIBDIR= $(CONVLIBDIR64) ELFLIBDIR= $(ELFLIBDIR64) ROOTLINKS= $(ROOTBIN64)/$(STRIPFILE) ROOTPROG= $(ROOTPROG64) # Hammerhead: ROOTPROG64=ROOTPROG, ROOTSTRIPFILEPROG64=ROOTSTRIPFILEPROG, # ROOTCCSBINLINK64=ROOTCCSBINLINK (path flattening) — use non-64 variants install: all $(ROOTPROG64) $(ROOTSTRIPFILEPROG) \ $(ROOTLINKS) $(ROOTCCSBINLINK) include ../Makefile.targ include $(SRC)/Makefile.master.64 /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1988 AT&T * All Rights Reserved * * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _EXTERN_H #define _EXTERN_H extern int actmax; extern Tmp_File elftmpfile; extern Tmp_File artmpfile; extern action *Action; extern int signum[]; extern char *prog; extern S_Name *sect_head; #endif /* _EXTERN_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1988 AT&T * All Rights Reserved * * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. */ #include #include "alist.h" #include "mcs.h" #include "extern.h" #include "gelf.h" /* * Type used to pass state information for the current * file between routines. */ typedef struct { int Sect_exists; int notesegndx; int notesctndx; Seg_Table *b_e_seg_table; section_info_table *sec_table; int64_t *off_table; /* maintains section's offset; set to */ /* retain old offset, else 0 */ int64_t *nobits_table; /* maintains NOBITS sections */ char *new_sec_string; } file_state_t; /* * Function prototypes. */ static void copy_file(int, char *, Tmp_File *); static void copy_non_elf_to_temp_ar(int, Elf *, int, Elf_Arhdr *, char *, Cmd_Info *); static void copy_elf_file_to_temp_ar_file(int, Elf_Arhdr *, char *); static int process_file(Elf *, char *, Cmd_Info *); static void initialize(int shnum, Cmd_Info *, file_state_t *); static int build_segment_table(Elf*, GElf_Ehdr *, file_state_t *); static int traverse_file(Elf *, GElf_Ehdr *, char *, Cmd_Info *, file_state_t *); static uint64_t location(int64_t, int, Elf *, file_state_t *); static uint64_t scn_location(Elf_Scn *, Elf *, file_state_t *); static int build_file(Elf *, GElf_Ehdr *, Cmd_Info *, file_state_t *); static void post_process(Cmd_Info *, file_state_t *); int each_file(char *cur_file, Cmd_Info *cmd_info) { Elf *elf = 0; Elf_Cmd cmd; Elf *arf = 0; Elf_Arhdr *mem_header; char *cur_filenm = NULL; int code = 0; int error = 0, err = 0; int ar_file = 0; int fdartmp; int fd; int oflag; if (CHK_OPT(cmd_info, MIGHT_CHG)) oflag = O_RDWR; else oflag = O_RDONLY; if ((fd = open(cur_file, oflag)) == -1) { error_message(OPEN_ERROR, SYSTEM_ERROR, strerror(errno), prog, cur_file); return (FAILURE); } /* * Note, elf_begin requires ELF_C_READ even if MIGHT_CHK is in effect. * libelf does not allow elf_begin() with ELF_C_RDWR when processing * archive file members. Because we are limited to ELF_C_READ use, any * ELF data modification must be provided by updating a copy of * the data, rather than updating the original file data. */ cmd = ELF_C_READ; if ((arf = elf_begin(fd, cmd, NULL)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); (void) elf_end(arf); (void) close(fd); /* done processing this file */ return (FAILURE); } if ((elf_kind(arf) == ELF_K_AR)) { ar_file = 1; if (CHK_OPT(cmd_info, MIGHT_CHG)) { artmpfile.tmp_name = tempnam(TMPDIR, "mcs2"); if ((fdartmp = open(artmpfile.tmp_name, O_WRONLY | O_APPEND | O_CREAT, (mode_t)0666)) == 0) { error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno), prog, artmpfile); (void) elf_end(arf); (void) close(fd); mcs_exit(FAILURE); } artmpfile.tmp_unlink = 1; /* write magic string to artmpfile */ if ((write(fdartmp, ARMAG, SARMAG)) != SARMAG) { error_message(WRITE_ERROR, SYSTEM_ERROR, strerror(errno), prog, artmpfile.tmp_name, cur_file); mcs_exit(FAILURE); } } } else { ar_file = 0; cur_filenm = cur_file; } /* * Holds temporary file; * if archive, holds the current member file if it has an ehdr, * and there were no errors in * processing the object file. */ elftmpfile.tmp_name = tempnam(TMPDIR, "mcs1"); while ((elf = elf_begin(fd, cmd, arf)) != 0) { if (ar_file) /* get header info */ { size_t len; if ((mem_header = elf_getarhdr(elf)) == NULL) { error_message(GETARHDR_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog, cur_file, elf_getbase(elf)); (void) elf_end(elf); (void) elf_end(arf); (void) close(fd); free_tempfile(&artmpfile); return (FAILURE); } if (cur_filenm != NULL) free(cur_filenm); len = (strlen(cur_file) + 3 + strlen(mem_header->ar_name)); if ((cur_filenm = malloc(len)) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } (void) snprintf(cur_filenm, len, "%s[%s]", cur_file, mem_header->ar_name); } if (elf_kind(elf) == ELF_K_ELF) { if ((code = process_file(elf, cur_filenm, cmd_info)) == FAILURE) { if (!ar_file) { (void) elf_end(arf); (void) elf_end(elf); (void) close(fd); return (FAILURE); } else { copy_non_elf_to_temp_ar(fd, elf, fdartmp, mem_header, cur_file, cmd_info); error++; } } else if (ar_file && CHK_OPT(cmd_info, MIGHT_CHG)) { if (code == DONT_BUILD) copy_non_elf_to_temp_ar(fd, elf, fdartmp, mem_header, cur_file, cmd_info); else copy_elf_file_to_temp_ar_file( fdartmp, mem_header, cur_file); } } else { /* * decide what to do with non-ELF file */ if (!ar_file) { error_message(FILE_TYPE_ERROR, PLAIN_ERROR, NULL, prog, cur_filenm); (void) close(fd); return (FAILURE); } else { if (CHK_OPT(cmd_info, MIGHT_CHG)) copy_non_elf_to_temp_ar(fd, elf, fdartmp, mem_header, cur_file, cmd_info); } } cmd = elf_next(elf); (void) elf_end(elf); } err = elf_errno(); if (err != 0) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(err), prog); error_message(NOT_MANIPULATED_ERROR, PLAIN_ERROR, NULL, prog, cur_file); return (FAILURE); } (void) elf_end(arf); if (ar_file && CHK_OPT(cmd_info, MIGHT_CHG)) { (void) close(fdartmp); /* done writing to ar_temp_file */ /* copy ar_temp_file to FILE */ copy_file(fd, cur_file, &artmpfile); } else if (code != DONT_BUILD && CHK_OPT(cmd_info, MIGHT_CHG)) copy_file(fd, cur_file, &elftmpfile); (void) close(fd); /* done processing this file */ return (error); } static int process_file(Elf *elf, char *cur_file, Cmd_Info *cmd_info) { int error = SUCCESS; int x; GElf_Ehdr ehdr; size_t shnum; file_state_t state; /* * Initialize */ if (gelf_getehdr(elf, &ehdr) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if (elf_getshdrnum(elf, &shnum) == -1) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } /* Initialize per-file state */ state.Sect_exists = 0; state.notesegndx = -1; state.notesctndx = -1; state.b_e_seg_table = NULL; state.sec_table = NULL; state.off_table = 0; state.nobits_table = NULL; state.new_sec_string = NULL; initialize(shnum, cmd_info, &state); if ((ehdr.e_phnum != 0) && (build_segment_table(elf, &ehdr, &state) == FAILURE)) { x = error = FAILURE; } else if ((x = traverse_file(elf, &ehdr, cur_file, cmd_info, &state)) == FAILURE) { error_message(WRN_MANIPULATED_ERROR, PLAIN_ERROR, NULL, prog, cur_file); error = FAILURE; } else if (x != DONT_BUILD && x != FAILURE) { post_process(cmd_info, &state); if (build_file(elf, &ehdr, cmd_info, &state) == FAILURE) { error_message(WRN_MANIPULATED_ERROR, PLAIN_ERROR, NULL, prog, cur_file); error = FAILURE; } } /* Release any dynamicaly allocated buffers */ if (state.b_e_seg_table != NULL) free(state.b_e_seg_table); if (state.sec_table != NULL) free(state.sec_table); if (state.off_table != NULL) free(state.off_table); if (state.nobits_table != NULL) free(state.nobits_table); if (state.new_sec_string != NULL) free(state.new_sec_string); if (x == DONT_BUILD) return (DONT_BUILD); else return (error); } static int traverse_file(Elf *elf, GElf_Ehdr * ehdr, char *cur_file, Cmd_Info *cmd_info, file_state_t *state) { Elf_Scn *scn; Elf_Scn *temp_scn; Elf_Data *data; GElf_Shdr *shdr; char *temp_name; section_info_table *sinfo; GElf_Xword x; int ret = 0, SYM = 0; /* used by strip command */ int phnum = ehdr->e_phnum; unsigned int i, scn_index; size_t shstrndx, shnum; state->Sect_exists = 0; if (elf_getshdrnum(elf, &shnum) == -1) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if (elf_getshdrstrndx(elf, &shstrndx) == -1) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } scn = 0; scn_index = 1; sinfo = &state->sec_table[scn_index]; while ((scn = elf_nextscn(elf, scn)) != 0) { char *name; shdr = &(sinfo->shdr); if (gelf_getshdr(scn, shdr) == NULL) { error_message(NO_SECT_TABLE_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog, cur_file); return (FAILURE); } /* * Note: If the object has problems, name * may be set to NULL by the following. */ name = elf_strptr(elf, shstrndx, (size_t)shdr->sh_name); sinfo->scn = scn; sinfo->secno = scn_index; sinfo->osecno = scn_index; SET_ACTION(sinfo->si_flags, ACT_NOP); sinfo->name = name; if (ehdr->e_phnum == 0) SET_LOC(sinfo->si_flags, NOSEG); else SET_LOC(sinfo->si_flags, scn_location(scn, elf, state)); if (shdr->sh_type == SHT_GROUP) { if (aplist_append(&cmd_info->sh_groups, sinfo, 10) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } } /* * If the target section is pointed by a section * holding relocation infomation, then the * pointing section would be useless if the * target section is removed. */ if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) && (shdr->sh_info != SHN_UNDEF && (temp_scn = elf_getscn(elf, shdr->sh_info)) != 0)) { GElf_Shdr tmp_shdr; if (gelf_getshdr(temp_scn, &tmp_shdr) != NULL) { temp_name = elf_strptr(elf, shstrndx, (size_t)tmp_shdr.sh_name); sinfo->rel_name = temp_name; sinfo->rel_scn_index = shdr->sh_info; if (phnum == 0) sinfo->rel_loc = NOSEG; else sinfo->rel_loc = scn_location(temp_scn, elf, state); } } data = 0; if ((data = elf_getdata(scn, data)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } sinfo->data = data; /* * Check if this section is a candidate for * action to be processes. */ if ((name != NULL) && (sectcmp(name) == 0)) { SET_CANDIDATE(sinfo->si_flags); /* * This flag just shows that there was a * candidate. */ state->Sect_exists++; } /* * Any of the following section types should * also be removed (if possible) if invoked via * the 'strip' command. */ if (CHK_OPT(cmd_info, I_AM_STRIP) && ((shdr->sh_type == SHT_SUNW_DEBUG) || (shdr->sh_type == SHT_SUNW_DEBUGSTR))) { SET_CANDIDATE(sinfo->si_flags); state->Sect_exists++; } /* * Zap this file ? */ if (CHK_OPT(cmd_info, zFLAG) && (shdr->sh_type == SHT_PROGBITS)) { SET_CANDIDATE(sinfo->si_flags); state->Sect_exists++; } x = GET_LOC(sinfo->si_flags); /* * Remember the note section index so that we can * reset the NOTE segment offset to point to it. Depending * on the operation being carried out, the note section may * be assigned a new location in the resulting ELF * image, and the program header needs to reflect that. * * There can be multiple contiguous note sections in * an object, referenced by a single NOTE segment. We * want to be sure and remember the one referenced by * the program header, and not one of the others. */ if ((shdr->sh_type == SHT_NOTE) && (state->notesctndx == -1) && (state->notesegndx != -1) && (state->b_e_seg_table[state->notesegndx].p_offset == shdr->sh_offset)) state->notesctndx = scn_index; if (x == IN || x == PRIOR) state->off_table[scn_index] = shdr->sh_offset; if (shdr->sh_type == SHT_NOBITS) state->nobits_table[scn_index] = 1; /* * If this section satisfies the condition, * apply the actions specified. */ if (ISCANDIDATE(sinfo->si_flags)) { ret += apply_action(sinfo, cur_file, cmd_info); } /* * If I am strip command, determine if symtab can go or not. */ if (CHK_OPT(cmd_info, I_AM_STRIP) && (CHK_OPT(cmd_info, xFLAG) == 0) && (CHK_OPT(cmd_info, lFLAG) == 0)) { if (shdr->sh_type == SHT_SYMTAB && GET_LOC(sinfo->si_flags) == AFTER) { SYM = scn_index; } } scn_index++; sinfo++; } sinfo->scn = (Elf_Scn *) -1; /* * If there were any errors traversing the file, * just return error. */ if (ret != 0) return (FAILURE); /* * Remove symbol table if possible */ if (CHK_OPT(cmd_info, I_AM_STRIP) && SYM != 0) { GElf_Shdr tmp_shdr; (void) gelf_getshdr(state->sec_table[SYM].scn, &tmp_shdr); state->sec_table[SYM].secno = (GElf_Word)DELETED; ++(cmd_info->no_of_nulled); if (state->Sect_exists == 0) ++state->Sect_exists; SET_ACTION(state->sec_table[SYM].si_flags, ACT_DELETE); state->off_table[SYM] = 0; /* * Can I remove section header * string table ? */ if ((tmp_shdr.sh_link < shnum) && (tmp_shdr.sh_link != SHN_UNDEF) && (tmp_shdr.sh_link != shstrndx) && (GET_LOC(state->sec_table[tmp_shdr.sh_link].si_flags) == AFTER)) { state->sec_table[tmp_shdr.sh_link].secno = (GElf_Word)DELETED; ++(cmd_info->no_of_nulled); if (state->Sect_exists == 0) ++state->Sect_exists; SET_ACTION(state->sec_table[tmp_shdr.sh_link].si_flags, ACT_DELETE); state->off_table[tmp_shdr.sh_link] = 0; } } /* * If I only printed the contents, then * just report so. */ if (CHK_OPT(cmd_info, pFLAG) && !CHK_OPT(cmd_info, MIGHT_CHG)) return (DONT_BUILD); /* don't bother creating a new file */ /* since the file has not changed */ /* * I might need to add a new section. Check it. */ if (state->Sect_exists == 0 && CHK_OPT(cmd_info, aFLAG)) { int act = 0; state->new_sec_string = calloc(1, cmd_info->str_size + 1); if (state->new_sec_string == NULL) return (FAILURE); for (act = 0; act < actmax; act++) { if (Action[act].a_action == ACT_APPEND) { (void) strcat(state->new_sec_string, Action[act].a_string); (void) strcat(state->new_sec_string, "\n"); cmd_info->no_of_append = 1; } } } /* * If I did not append any new sections, and I did not * modify/delete any sections, then just report so. */ if ((state->Sect_exists == 0 && cmd_info->no_of_append == 0) || !CHK_OPT(cmd_info, MIGHT_CHG)) return (DONT_BUILD); /* * Found at least one section which was processed. * Deleted or Appended or Compressed. */ if (state->Sect_exists) { /* * First, handle the deleted sections. */ if (cmd_info->no_of_delete != 0 || cmd_info->no_of_nulled != 0) { int acc = 0; int rel_idx; /* * Handle relocation/target * sections. */ sinfo = &(state->sec_table[0]); for (i = 1; i < shnum; i++) { sinfo++; rel_idx = sinfo->rel_scn_index; if (rel_idx == 0) continue; /* * If I am removed, then remove my * target section. */ if (((sinfo->secno == (GElf_Word)DELETED) || (sinfo->secno == (GElf_Word)NULLED)) && sinfo->rel_loc != IN) { if (GET_LOC(state-> sec_table[rel_idx].si_flags) == PRIOR) { state->sec_table[rel_idx]. secno = (GElf_Word)NULLED; } else { state->sec_table[rel_idx]. secno = (GElf_Word)DELETED; } SET_ACTION( state->sec_table[rel_idx].si_flags, ACT_DELETE); } /* * I am not removed. Check if my target is * removed or nulled. If so, let me try to * remove my self. */ if (((state->sec_table[rel_idx].secno == (GElf_Word)DELETED) || (state->sec_table[rel_idx].secno == (GElf_Word)NULLED)) && (GET_LOC(sinfo->si_flags) != IN)) { if (GET_LOC(sinfo->si_flags) == PRIOR) sinfo->secno = (GElf_Word)NULLED; else sinfo->secno = (GElf_Word)DELETED; SET_ACTION(sinfo->si_flags, ACT_DELETE); } } /* * Now, take care of DELETED sections */ sinfo = &(state->sec_table[1]); for (i = 1; i < shnum; i++) { shdr = &(sinfo->shdr); if (sinfo->secno == (GElf_Word)DELETED) { acc++; /* * The SHT_GROUP section which this * section is a member may be able * to be removed. See post_process(). */ if (shdr->sh_flags & SHF_GROUP) { SET_OPT(cmd_info, SHF_GROUP_DEL); } } else { /* * The data buffer of SHT_GROUP this * section is a member needs to be * updated. See post_process(). */ sinfo->secno -= acc; if ((shdr->sh_flags & SHF_GROUP) && (acc != 0)) { SET_OPT(cmd_info, SHF_GROUP_MOVE); } } sinfo++; } } } /* * I know that the file has been modified. * A new file need to be created. */ return (SUCCESS); } static int build_file(Elf *src_elf, GElf_Ehdr *src_ehdr, Cmd_Info *cmd_info, file_state_t *state) { Elf_Scn *src_scn; Elf_Scn *dst_scn; int new_sh_name = 0; /* to hold the offset for the new */ /* section's name */ Elf *dst_elf = 0; Elf_Data *elf_data; Elf_Data *data; int64_t scn_no, x; size_t no_of_symbols = 0; section_info_table *info; unsigned int c = 0; int fdtmp; GElf_Shdr src_shdr; GElf_Shdr dst_shdr; GElf_Ehdr dst_ehdr; GElf_Off new_offset = 0, r; size_t shnum, shstrndx; if (elf_getshdrnum(src_elf, &shnum) == -1) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if (elf_getshdrstrndx(src_elf, &shstrndx) == -1) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if ((fdtmp = open(elftmpfile.tmp_name, O_RDWR | O_TRUNC | O_CREAT, (mode_t)0666)) == -1) { error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno), prog, elftmpfile.tmp_name); return (FAILURE); } elftmpfile.tmp_unlink = 1; if ((dst_elf = elf_begin(fdtmp, ELF_C_WRITE, (Elf *) 0)) == NULL) { error_message(READ_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog, elftmpfile.tmp_name); (void) close(fdtmp); return (FAILURE); } if (gelf_newehdr(dst_elf, gelf_getclass(src_elf)) == 0) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } /* initialize dst_ehdr */ (void) gelf_getehdr(dst_elf, &dst_ehdr); dst_ehdr = *src_ehdr; /* * If we are removing the header string table section, * remove the reference to it from the ELF header. */ if ((shstrndx != SHN_UNDEF) && (state->sec_table[shstrndx].secno == (GElf_Word)DELETED)) dst_ehdr.e_shstrndx = SHN_UNDEF; /* * flush the changes to the ehdr so the ident * array and header string table index are filled in. */ (void) gelf_update_ehdr(dst_elf, &dst_ehdr); if (src_ehdr->e_phnum != 0) { (void) elf_flagelf(dst_elf, ELF_C_SET, ELF_F_LAYOUT); if (gelf_newphdr(dst_elf, src_ehdr->e_phnum) == 0) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } for (x = 0; x < src_ehdr->e_phnum; ++x) { GElf_Phdr dst; GElf_Phdr src; /* LINTED */ (void) gelf_getphdr(src_elf, (int)x, &src); /* LINTED */ (void) gelf_getphdr(dst_elf, (int)x, &dst); (void) memcpy(&dst, &src, sizeof (GElf_Phdr)); /* LINTED */ (void) gelf_update_phdr(dst_elf, (int)x, &dst); } x = location(dst_ehdr.e_phoff, 0, src_elf, state); if (x == AFTER) new_offset = (GElf_Off)src_ehdr->e_ehsize; } scn_no = 1; while ((src_scn = state->sec_table[scn_no].scn) != (Elf_Scn *) -1) { info = &state->sec_table[scn_no]; /* If section should be copied to new file NOW */ if ((info->secno != (GElf_Word)DELETED) && info->secno <= scn_no) { if ((dst_scn = elf_newscn(dst_elf)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) gelf_getshdr(dst_scn, &dst_shdr); (void) gelf_getshdr(info->scn, &src_shdr); (void) memcpy(&dst_shdr, &src_shdr, sizeof (GElf_Shdr)); /* * Update link and info fields * The sh_link field may have special values so * check them first. */ if ((src_shdr.sh_link >= shnum) || (src_shdr.sh_link == 0)) dst_shdr.sh_link = src_shdr.sh_link; else if ((int)state->sec_table[src_shdr.sh_link].secno < 0) dst_shdr.sh_link = 0; else dst_shdr.sh_link = state->sec_table[src_shdr.sh_link].secno; if ((src_shdr.sh_type == SHT_REL) || (src_shdr.sh_type == SHT_RELA)) { if ((src_shdr.sh_info >= shnum) || ((int)state->sec_table[src_shdr. sh_info].secno < 0)) dst_shdr.sh_info = 0; else dst_shdr.sh_info = state-> sec_table[src_shdr.sh_info].secno; } data = state->sec_table[scn_no].data; if ((elf_data = elf_newdata(dst_scn)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } *elf_data = *data; /* * SHT_{DYNSYM, SYMTAB} might need some change, as * they may contain section symbols that reference * removed sections. SHT_SUNW_LDYNSYM does not * contain section symbols, and therefore does not * have this issue. */ if (((src_shdr.sh_type == SHT_SYMTAB) || (src_shdr.sh_type == SHT_DYNSYM)) && src_shdr.sh_entsize != 0 && (cmd_info->no_of_delete != 0 || cmd_info->no_of_nulled != 0)) { char *new_sym; no_of_symbols = src_shdr.sh_size / src_shdr.sh_entsize; new_sym = malloc(no_of_symbols * src_shdr.sh_entsize); if (new_sym == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } /* CSTYLED */ elf_data->d_buf = (void *) new_sym; for (c = 0; c < no_of_symbols; c++) { GElf_Sym csym; (void) gelf_getsym(data, c, &csym); if ((csym.st_shndx < SHN_LORESERVE) && (csym.st_shndx != SHN_UNDEF)) { section_info_table *i; i = &state-> sec_table[csym.st_shndx]; if (((int)i->secno != DELETED) && ((int)i->secno != NULLED)) { csym.st_shndx = i->secno; } else { /* BEGIN CSTYLED */ if (src_shdr.sh_type == SHT_SYMTAB) { /* * The section which * this * symbol relates * to is removed. * There is no way to * specify this fact, * just change the shndx * to 1. */ csym.st_shndx = 1; } else { /* * If this is in a * .dynsym, NULL it out. */ csym.st_shndx = 0; csym.st_name = 0; csym.st_value = 0; csym.st_size = 0; csym.st_info = 0; csym.st_other = 0; csym.st_shndx = 0; } /* END CSTYLED */ } } (void) gelf_update_sym(elf_data, c, &csym); } } /* update SHT_SYMTAB_SHNDX */ if ((src_shdr.sh_type == SHT_SYMTAB_SHNDX) && (src_shdr.sh_entsize != 0) && ((cmd_info->no_of_delete != 0) || (cmd_info->no_of_nulled != 0))) { GElf_Word *oldshndx; GElf_Word *newshndx; uint_t entcnt; entcnt = src_shdr.sh_size / src_shdr.sh_entsize; oldshndx = data->d_buf; newshndx = malloc(entcnt * src_shdr.sh_entsize); if (newshndx == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } elf_data->d_buf = (void *)newshndx; for (c = 0; c < entcnt; c++) { if (oldshndx[c] != SHN_UNDEF) { section_info_table *i; i = &state-> sec_table[oldshndx[c]]; if (((int)i->secno != DELETED) && ((int)i->secno != NULLED)) newshndx[c] = i->secno; else newshndx[c] = oldshndx[c]; } else newshndx[c] = oldshndx[c]; } } /* * If the section is to be updated, * do so. */ if (ISCANDIDATE(info->si_flags)) { if ((GET_LOC(info->si_flags) == PRIOR) && (((int)info->secno == NULLED) || ((int)info->secno == EXPANDED) || ((int)info->secno == SHRUNK))) { /* * The section is updated, * but the position is not too * good. Need to NULL this out. */ dst_shdr.sh_name = 0; dst_shdr.sh_type = SHT_PROGBITS; if ((int)info->secno != NULLED) { (cmd_info->no_of_moved)++; SET_MOVING(info->si_flags); } } else { /* * The section is positioned AFTER, * or there are no segments. * It is safe to update this section. */ data = state->sec_table[scn_no].mdata; *elf_data = *data; dst_shdr.sh_size = elf_data->d_size; } } /* add new section name to shstrtab? */ else if (!state->Sect_exists && (state->new_sec_string != NULL) && (scn_no == shstrndx) && (dst_shdr.sh_type == SHT_STRTAB) && ((src_ehdr->e_phnum == 0) || ((x = scn_location(dst_scn, dst_elf, state)) != IN) || (x != PRIOR))) { size_t sect_len; sect_len = strlen(SECT_NAME); if ((elf_data->d_buf = malloc((dst_shdr.sh_size + sect_len + 1))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } /* put original data plus new data in section */ (void) memcpy(elf_data->d_buf, data->d_buf, data->d_size); (void) memcpy(&((char *)elf_data->d_buf) [data->d_size], SECT_NAME, sect_len + 1); /* LINTED */ new_sh_name = (int)dst_shdr.sh_size; dst_shdr.sh_size += sect_len + 1; elf_data->d_size += sect_len + 1; } /* * Compute offsets. */ if (src_ehdr->e_phnum != 0) { /* * Compute section offset. */ if (state->off_table[scn_no] == 0) { if (dst_shdr.sh_addralign != 0) { r = new_offset % dst_shdr.sh_addralign; if (r) new_offset += dst_shdr. sh_addralign - r; } dst_shdr.sh_offset = new_offset; elf_data->d_off = 0; } else { if (state->nobits_table[scn_no] == 0) new_offset = state->off_table[scn_no]; } if (state->nobits_table[scn_no] == 0) new_offset += dst_shdr.sh_size; } /* flush changes */ (void) gelf_update_shdr(dst_scn, &dst_shdr); } scn_no++; } /* * This is the real new section. */ if (!state->Sect_exists && state->new_sec_string != NULL) { size_t string_size; string_size = strlen(state->new_sec_string) + 1; if ((dst_scn = elf_newscn(dst_elf)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) gelf_getshdr(dst_scn, &dst_shdr); dst_shdr.sh_name = new_sh_name; dst_shdr.sh_type = SHT_PROGBITS; dst_shdr.sh_flags = 0; dst_shdr.sh_addr = 0; if (src_ehdr->e_phnum != 0) dst_shdr.sh_offset = new_offset; else dst_shdr.sh_offset = 0; dst_shdr.sh_size = string_size + 1; dst_shdr.sh_link = 0; dst_shdr.sh_info = 0; dst_shdr.sh_addralign = 1; dst_shdr.sh_entsize = 0; (void) gelf_update_shdr(dst_scn, &dst_shdr); /* flush changes */ if ((elf_data = elf_newdata(dst_scn)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } elf_data->d_size = string_size + 1; if ((elf_data->d_buf = (char *) calloc(1, string_size + 1)) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } (void) memcpy(&((char *)elf_data->d_buf)[1], state->new_sec_string, string_size); elf_data->d_align = 1; new_offset += string_size + 1; } /* * If there are sections which needed to be moved, * then do it here. */ if (cmd_info->no_of_moved != 0) { int cnt; info = &state->sec_table[0]; for (cnt = 0; cnt < shnum; cnt++, info++) { if ((GET_MOVING(info->si_flags)) == 0) continue; if ((src_scn = elf_getscn(src_elf, info->osecno)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if (gelf_getshdr(src_scn, &src_shdr) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if ((dst_scn = elf_newscn(dst_elf)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } if (gelf_getshdr(dst_scn, &dst_shdr) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } dst_shdr = src_shdr; data = info->mdata; dst_shdr.sh_offset = new_offset; /* UPDATE fields */ dst_shdr.sh_size = data->d_size; if ((shnum >= src_shdr.sh_link) || (src_shdr.sh_link == 0)) dst_shdr.sh_link = src_shdr.sh_link; else dst_shdr.sh_link = state->sec_table[src_shdr.sh_link].osecno; if ((shnum >= src_shdr.sh_info) || (src_shdr.sh_info == 0)) dst_shdr.sh_info = src_shdr.sh_info; else dst_shdr.sh_info = state->sec_table[src_shdr.sh_info].osecno; (void) gelf_update_shdr(dst_scn, &dst_shdr); if ((elf_data = elf_newdata(dst_scn)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) memcpy(elf_data, data, sizeof (Elf_Data)); new_offset += data->d_size; } } /* * In the event that the position of the sting table has changed, * as a result of deleted sections, update the ehdr->e_shstrndx. */ if ((shstrndx > 0) && (shnum > 0) && (state->sec_table[shstrndx].secno < shnum)) { if (state->sec_table[shstrndx].secno < SHN_LORESERVE) { dst_ehdr.e_shstrndx = state->sec_table[dst_ehdr.e_shstrndx].secno; } else { Elf_Scn *_scn; GElf_Shdr shdr0; /* * If shstrndx requires 'Extended ELF Sections' * then it is stored in shdr[0].sh_link */ dst_ehdr.e_shstrndx = SHN_XINDEX; if ((_scn = elf_getscn(dst_elf, 0)) == NULL) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) gelf_getshdr(_scn, &shdr0); shdr0.sh_link = state->sec_table[shstrndx].secno; (void) gelf_update_shdr(_scn, &shdr0); } } if (src_ehdr->e_phnum != 0) { size_t align = gelf_fsize(dst_elf, ELF_T_ADDR, 1, EV_CURRENT); /* UPDATE location of program header table */ if (location(dst_ehdr.e_phoff, 0, dst_elf, state) == AFTER) { r = new_offset % align; if (r) new_offset += align - r; dst_ehdr.e_phoff = new_offset; new_offset += dst_ehdr.e_phnum * dst_ehdr.e_phentsize; } /* UPDATE location of section header table */ if ((location(dst_ehdr.e_shoff, 0, src_elf, state) == AFTER) || ((location(dst_ehdr.e_shoff, 0, src_elf, state) == PRIOR) && (!state->Sect_exists && state->new_sec_string != NULL))) { r = new_offset % align; if (r) new_offset += align - r; dst_ehdr.e_shoff = new_offset; } /* * The NOTE segment is the one segment whos * sections might get moved by mcs processing. * Make sure that the NOTE segments offset points * to the .note section. */ if ((state->notesegndx != -1) && (state->notesctndx != -1) && (state->sec_table[state->notesctndx].secno)) { Elf_Scn * notescn; GElf_Shdr nshdr; notescn = elf_getscn(dst_elf, state->sec_table[state->notesctndx].secno); (void) gelf_getshdr(notescn, &nshdr); if (gelf_getclass(dst_elf) == ELFCLASS32) { Elf32_Phdr * ph = elf32_getphdr(dst_elf) + state->notesegndx; /* LINTED */ ph->p_offset = (Elf32_Off)nshdr.sh_offset; } else { Elf64_Phdr * ph = elf64_getphdr(dst_elf) + state->notesegndx; ph->p_offset = (Elf64_Off)nshdr.sh_offset; } } } /* copy ehdr changes back into real ehdr */ (void) gelf_update_ehdr(dst_elf, &dst_ehdr); if (elf_update(dst_elf, ELF_C_WRITE) < 0) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); return (FAILURE); } (void) elf_end(dst_elf); (void) close(fdtmp); return (SUCCESS); } /* * Search through PHT saving the beginning and ending segment offsets */ static int build_segment_table(Elf * elf, GElf_Ehdr * ehdr, file_state_t *state) { unsigned int i; state->b_e_seg_table = (Seg_Table *) calloc(ehdr->e_phnum, sizeof (Seg_Table)); if (state->b_e_seg_table == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } for (i = 0; i < ehdr->e_phnum; i++) { GElf_Phdr ph; (void) gelf_getphdr(elf, i, &ph); /* * remember the note SEGMENTS index so that we can * re-set it's p_offset later if needed. */ if (ph.p_type == PT_NOTE) state->notesegndx = i; state->b_e_seg_table[i].p_offset = ph.p_offset; state->b_e_seg_table[i].p_memsz = ph.p_offset + ph.p_memsz; state->b_e_seg_table[i].p_filesz = ph.p_offset + ph.p_filesz; } return (SUCCESS); } static void copy_elf_file_to_temp_ar_file( int fdartmp, Elf_Arhdr *mem_header, char *cur_file) { char *buf; char mem_header_buf[sizeof (struct ar_hdr) + 1]; int fdtmp3; struct stat stbuf; if ((fdtmp3 = open(elftmpfile.tmp_name, O_RDONLY)) == -1) { error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno), prog, elftmpfile.tmp_name); mcs_exit(FAILURE); } (void) stat(elftmpfile.tmp_name, &stbuf); /* for size of file */ if ((buf = malloc(ROUNDUP(stbuf.st_size))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } if (read(fdtmp3, buf, stbuf.st_size) != stbuf.st_size) { error_message(READ_MANI_ERROR, SYSTEM_ERROR, strerror(errno), prog, elftmpfile.tmp_name, cur_file); mcs_exit(FAILURE); } (void) sprintf(mem_header_buf, FORMAT, mem_header->ar_rawname, mem_header->ar_date, (unsigned)mem_header->ar_uid, (unsigned)mem_header->ar_gid, (unsigned)mem_header->ar_mode, stbuf.st_size, ARFMAG); if (write(fdartmp, mem_header_buf, (unsigned)sizeof (struct ar_hdr)) != (unsigned)sizeof (struct ar_hdr)) { error_message(WRITE_MANI_ERROR, SYSTEM_ERROR, strerror(errno), prog, elftmpfile.tmp_name, cur_file); mcs_exit(FAILURE); } if (stbuf.st_size & 0x1) { buf[stbuf.st_size] = '\n'; if (write(fdartmp, buf, (size_t)ROUNDUP(stbuf.st_size)) != (size_t)ROUNDUP(stbuf.st_size)) { error_message(WRITE_MANI_ERROR, SYSTEM_ERROR, strerror(errno), prog, elftmpfile.tmp_name, cur_file); mcs_exit(FAILURE); } } else if (write(fdartmp, buf, stbuf.st_size) != stbuf.st_size) { error_message(WRITE_MANI_ERROR, SYSTEM_ERROR, strerror(errno), prog, elftmpfile.tmp_name, cur_file); mcs_exit(FAILURE); } free(buf); (void) close(fdtmp3); } static void copy_non_elf_to_temp_ar( int fd, Elf *elf, int fdartmp, Elf_Arhdr *mem_header, char *cur_file, Cmd_Info *cmd_info) { char mem_header_buf[sizeof (struct ar_hdr) + 1]; char *file_buf; if ((strcmp(mem_header->ar_name, "/") != 0) && (strcmp(mem_header->ar_name, "/SYM64/") != 0)) { (void) sprintf(mem_header_buf, FORMAT, mem_header->ar_rawname, mem_header->ar_date, (unsigned)mem_header->ar_uid, (unsigned)mem_header->ar_gid, (unsigned)mem_header->ar_mode, mem_header->ar_size, ARFMAG); if (write(fdartmp, mem_header_buf, sizeof (struct ar_hdr)) != sizeof (struct ar_hdr)) { error_message(WRITE_MANI_ERROR, SYSTEM_ERROR, strerror(errno), prog, cur_file); mcs_exit(FAILURE); } if ((file_buf = malloc(ROUNDUP(mem_header->ar_size))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } if (lseek(fd, elf_getbase(elf), 0) != elf_getbase(elf)) { error_message(WRITE_MANI_ERROR, prog, cur_file); mcs_exit(FAILURE); } if (read(fd, file_buf, (size_t)ROUNDUP(mem_header->ar_size)) != (size_t)ROUNDUP(mem_header->ar_size)) { error_message(READ_MANI_ERROR, SYSTEM_ERROR, strerror(errno), prog, cur_file); mcs_exit(FAILURE); } if (write(fdartmp, file_buf, (size_t)ROUNDUP(mem_header->ar_size)) != (size_t)ROUNDUP(mem_header->ar_size)) { error_message(WRITE_MANI_ERROR, SYSTEM_ERROR, strerror(errno), prog, cur_file); mcs_exit(FAILURE); } free(file_buf); } else if (CHK_OPT(cmd_info, MIGHT_CHG)) { error_message(SYM_TAB_AR_ERROR, PLAIN_ERROR, NULL, prog, cur_file); error_message(EXEC_AR_ERROR, PLAIN_ERROR, NULL, cur_file); } } /* * Replace contents of file * * entry: * ofd - Open file descriptor for file fname * fname - Name of file being processed * temp_file_name - Address of pointer to temporary * file containing new contents for fname. * * exit: * The contents of the file given by temp_file->tmp_name are * copied to the file fname. The temporary file is * unlinked, and temp_file reset. */ static void copy_file(int ofd, char *fname, Tmp_File *temp_file) { enum { MMAP_USED, MMAP_UNUSED } mmap_status; int i; int fdtmp2; struct stat stbuf; char *buf; for (i = 0; signum[i]; i++) /* started writing, cannot interrupt */ (void) signal(signum[i], SIG_IGN); if ((fdtmp2 = open(temp_file->tmp_name, O_RDONLY)) == -1) { error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno), prog, temp_file->tmp_name); mcs_exit(FAILURE); } (void) stat(temp_file->tmp_name, &stbuf); /* for size of file */ /* * Get the contents of the updated file. * First try mmap()'ing. If mmap() fails, * then use the malloc() and read(). */ mmap_status = MMAP_USED; buf = (char *)mmap(0, stbuf.st_size, PROT_READ, MAP_SHARED, fdtmp2, 0); if (buf == (caddr_t)-1) { if ((buf = malloc(stbuf.st_size * sizeof (char))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } if (read(fdtmp2, buf, stbuf.st_size) != stbuf.st_size) { error_message(READ_SYS_ERROR, SYSTEM_ERROR, strerror(errno), prog, temp_file->tmp_name); mcs_exit(FAILURE); } mmap_status = MMAP_UNUSED; } if (ftruncate(ofd, 0) == -1) { error_message(WRITE_MANI_ERROR2, SYSTEM_ERROR, strerror(errno), prog, fname); mcs_exit(FAILURE); } if (lseek(ofd, 0, SEEK_SET) == -1) { error_message(WRITE_MANI_ERROR2, SYSTEM_ERROR, strerror(errno), prog, fname); mcs_exit(FAILURE); } if ((write(ofd, buf, stbuf.st_size)) != stbuf.st_size) { error_message(WRITE_MANI_ERROR2, SYSTEM_ERROR, strerror(errno), prog, fname); mcs_exit(FAILURE); } /* * clean */ if (mmap_status == MMAP_USED) (void) munmap(buf, stbuf.st_size); else free(buf); (void) close(fdtmp2); free_tempfile(temp_file); } static uint64_t location(int64_t offset, int mem_search, Elf * elf, file_state_t *state) { int i; uint64_t upper; GElf_Ehdr ehdr; (void) gelf_getehdr(elf, &ehdr); for (i = 0; i < ehdr.e_phnum; i++) { if (mem_search) upper = state->b_e_seg_table[i].p_memsz; else upper = state->b_e_seg_table[i].p_filesz; if ((offset >= state->b_e_seg_table[i].p_offset) && (offset <= upper)) return (IN); else if (offset < state->b_e_seg_table[i].p_offset) return (PRIOR); } return (AFTER); } static uint64_t scn_location(Elf_Scn * scn, Elf * elf, file_state_t *state) { GElf_Shdr shdr; (void) gelf_getshdr(scn, &shdr); /* * If the section is not a NOTE section and it has no * virtual address then it is not part of a mapped segment. */ if (shdr.sh_addr == 0) return (location(shdr.sh_offset + shdr.sh_size, 0, elf, state)); return (location(shdr.sh_offset + shdr.sh_size, 1, elf, state)); } static void initialize(int shnum, Cmd_Info *cmd_info, file_state_t *state) { /* * Initialize command info */ cmd_info->no_of_append = cmd_info->no_of_delete = cmd_info->no_of_nulled = cmd_info->no_of_compressed = cmd_info->no_of_moved = 0; cmd_info->sh_groups = NULL; state->sec_table = (section_info_table *) calloc(shnum + 1, sizeof (section_info_table)); if (state->sec_table == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } state->off_table = (int64_t *)calloc(shnum, sizeof (int64_t)); if (state->off_table == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } state->nobits_table = (int64_t *)calloc(shnum, sizeof (int64_t)); if (state->nobits_table == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } } /* * Update the contents of SHT_GROUP if needed */ static void post_process(Cmd_Info *cmd_info, file_state_t *state) { Aliste idx; section_info_table *sinfo; Word *grpdata, *ngrpdata; int64_t sno, sno2; Word i, j, num; /* * If no change is required, then return. */ if (!CHK_OPT(cmd_info, SHF_GROUP_MOVE|SHF_GROUP_DEL)) return; /* * If SHF_GROUP sections were removed, we might need to * remove SHT_GROUP sections. */ if (CHK_OPT(cmd_info, SHF_GROUP_DEL)) { Word grpcnt; int deleted = 0; for (APLIST_TRAVERSE(cmd_info->sh_groups, idx, sinfo)) { if (sinfo->secno == (GElf_Word)DELETED) continue; num = (sinfo->shdr).sh_size/sizeof (Word); grpcnt = 0; grpdata = (Word *)(sinfo->data->d_buf); for (i = 1; i < num; i++) { if (state->sec_table[grpdata[i]].secno != (GElf_Word)DELETED) grpcnt++; } /* * All members in this SHT_GROUP were removed. * We can remove this SHT_GROUP. */ if (grpcnt == 0) { sinfo->secno = (GElf_Word)DELETED; (cmd_info->no_of_delete)++; deleted = 1; } } /* * If we deleted a SHT_GROUP section, * we need to reasign section numbers. */ if (deleted) { section_info_table *sinfo; sno = 1; sno2 = 1; while (state->sec_table[sno].scn != (Elf_Scn *)-1) { sinfo = &state->sec_table[sno]; if (sinfo->secno != (GElf_Word) DELETED) sinfo->secno = sno2++; sno++; } } } /* * Now we can update data buffers of the SHT_GROUP sections. */ for (APLIST_TRAVERSE(cmd_info->sh_groups, idx, sinfo)) { if (sinfo->secno == (GElf_Word)DELETED) continue; num = (sinfo->shdr).sh_size/sizeof (Word); /* * Need to generate the updated data buffer */ if ((sinfo->mdata = malloc(sizeof (Elf_Data))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } *(sinfo->mdata) = *(sinfo->data); if ((ngrpdata = sinfo->mdata->d_buf = malloc(sinfo->data->d_size)) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } grpdata = (Word *)(sinfo->data->d_buf); ngrpdata[0] = grpdata[0]; j = 1; for (i = 1; i < num; i++) { if (state->sec_table[grpdata[i]].secno != (GElf_Word)DELETED) { ngrpdata[j++] = state->sec_table[grpdata[i]].secno; } } sinfo->mdata->d_size = j * sizeof (Word); sinfo->data = sinfo->mdata; } free(cmd_info->sh_groups); cmd_info->sh_groups = NULL; } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright(c) 1988 AT&T * All Rights Reserved * * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "mcs.h" #include "extern.h" int actmax = 0; Tmp_File elftmpfile; Tmp_File artmpfile; action *Action; int signum[] = {SIGHUP, SIGINT, SIGQUIT, 0}; char *prog; S_Name *sect_head = NULL; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2012 Nexenta Systems, Inc. All rights reserved. * * Copyright (c) 1988 AT&T * All Rights Reserved * * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. */ #include "stdlib.h" #include "conv.h" #include "mcs.h" #include "extern.h" #define OPTUNIT 100 static size_t optcnt = 0; static size_t optbufsz = OPTUNIT; /* * Function prototypes. */ static void usage(int); static void sigexit(int); static int setup_sectname(char *, int); static void queue(int, char *); int main(int argc, char ** argv, char ** envp) { const char *opt; char *str; int error_count = 0, num_sect = 0, errflag = 0; int c, i, my_prog; Cmd_Info *cmd_info; /* * Check for a binary that better fits this architecture. */ (void) conv_check_native(argv, envp); /* * mcs(1) and strip() are hard linked together, determine which command * was invoked. */ prog = argv[0]; if ((str = strrchr(prog, '/')) != NULL) str++; else str = prog; if (strcmp(str, "mcs") == 0) { my_prog = MCS; opt = "a:cdn:pVz?"; } else if (strcmp(str, "strip") == 0) { my_prog = STRIP; opt = "lxV?"; } else exit(FAILURE); (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); for (i = 0; signum[i]; i++) if (signal(signum[i], SIG_IGN) != SIG_IGN) (void) signal(signum[i], sigexit); if ((Action = malloc(optbufsz * sizeof (struct action))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); exit(FAILURE); } /* * Allocate command info structure */ cmd_info = (Cmd_Info *) calloc(1, sizeof (Cmd_Info)); if (cmd_info == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); exit(FAILURE); } if (my_prog == STRIP) SET_OPT(cmd_info, I_AM_STRIP); while ((c = getopt(argc, argv, (char *)opt)) != EOF) { switch (c) { case 'a': optcnt++; queue(ACT_APPEND, optarg); SET_OPT(cmd_info, MIGHT_CHG | aFLAG); cmd_info->str_size += strlen(optarg) + 1; break; case 'c': optcnt++; queue(ACT_COMPRESS, NULL); SET_OPT(cmd_info, MIGHT_CHG | cFLAG); break; case 'd': optcnt++; if (!CHK_OPT(cmd_info, dFLAG)) queue(ACT_DELETE, NULL); SET_OPT(cmd_info, MIGHT_CHG | dFLAG); break; case 'z': optcnt++; queue(ACT_ZAP, NULL); SET_OPT(cmd_info, MIGHT_CHG | zFLAG); break; case 'n': (void) setup_sectname(optarg, my_prog); num_sect++; break; case 'l': optcnt++; SET_OPT(cmd_info, lFLAG); break; case 'p': optcnt++; queue(ACT_PRINT, NULL); SET_OPT(cmd_info, pFLAG); break; case 'x': optcnt++; SET_OPT(cmd_info, xFLAG); break; case 'V': SET_OPT(cmd_info, VFLAG); (void) fprintf(stderr, "%s: %s %s\n", prog, (const char *)SGU_PKG, (const char *)SGU_REL); break; case '?': errflag++; break; default: break; } } if (errflag) { usage(my_prog); exit(FAILURE); } /* * strip command may not take any options. */ if (my_prog != STRIP) { if (argc == optind && (CHK_OPT(cmd_info, MIGHT_CHG) || CHK_OPT(cmd_info, pFLAG) || argc == 1)) usage(my_prog); else if (!CHK_OPT(cmd_info, MIGHT_CHG) && !CHK_OPT(cmd_info, pFLAG) && !CHK_OPT(cmd_info, VFLAG)) usage(my_prog); } /* * This version only allows multiple section names * only for -d option. */ if ((num_sect >= 2) && (CHK_OPT(cmd_info, pFLAG) || CHK_OPT(cmd_info, aFLAG) || CHK_OPT(cmd_info, cFLAG))) { error_message(USAGE_ERROR, PLAIN_ERROR, (char *)0, prog); exit(FAILURE); } /* * If no -n was specified, * set the default, ".comment". * This is for mcs only. */ if (num_sect == 0 && my_prog == MCS) { (void) setup_sectname(".comment", MCS); } /* * If I am strip command, then add needed * section names. */ if (my_prog == STRIP) { (void) setup_sectname(".line", MCS); if (CHK_OPT(cmd_info, lFLAG) == 0) { (void) setup_sectname(".debug", STRIP); (void) setup_sectname(".stab", STRIP); } if (CHK_OPT(cmd_info, dFLAG) == 0) { queue(ACT_DELETE, NULL); SET_OPT(cmd_info, MIGHT_CHG | dFLAG); } } (void) elf_version(EV_NONE); if (elf_version(EV_CURRENT) == EV_NONE) { error_message(ELFVER_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); exit(FAILURE); } if (CHK_OPT(cmd_info, pFLAG) || CHK_OPT(cmd_info, MIGHT_CHG)) { for (; optind < argc; optind++) { error_count = error_count + (each_file(argv[optind], cmd_info)); } } mcs_exit(error_count); /*NOTREACHED*/ return (0); } /* * Supplementary functions */ static void queue(int activity, char *string) { if (optcnt > optbufsz) { optbufsz = optbufsz * 2; if ((Action = realloc((struct action *)Action, optbufsz * sizeof (struct action))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); mcs_exit(FAILURE); } } Action[actmax].a_action = activity; Action[actmax].a_cnt = 0; Action[actmax].a_string = string; actmax++; } /* * Reset a temporary file descriptor for reuse. * If the file requires unlinking, that is done first. */ void free_tempfile(Tmp_File *temp_file) { if ((temp_file->tmp_name != NULL) && (temp_file->tmp_unlink)) (void) unlink(temp_file->tmp_name); (void) memset(temp_file, 0, sizeof (*temp_file)); } /*ARGSUSED0*/ static void sigexit(int i) { free_tempfile(&artmpfile); free_tempfile(&elftmpfile); exit(100); } static void usage(int me) { if (me == MCS) (void) fprintf(stderr, gettext( "usage: %s [-cdpVz] [-a string] [-n name] file ...\n"), prog); else (void) fprintf(stderr, gettext( "usage: %s [-lVx] file ...\n"), prog); mcs_exit(FAILURE); } void mcs_exit(int val) { free_tempfile(&artmpfile); free_tempfile(&elftmpfile); exit(val); } /* * Insert the section name 'name' into the * section list. */ static int setup_sectname(char *name, int whoami) { S_Name *new; /* * Check if the name is already specified or not. */ if ((whoami == MCS) && (sectcmp(name) == 0)) return (0); /* * Allocate one */ if ((new = malloc(sizeof (S_Name))) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); exit(FAILURE); } new->name = strdup(name); if (new->name == NULL) { error_message(USAGE_ERROR, PLAIN_ERROR, (char *)0, prog); exit(FAILURE); } if (whoami == STRIP) new->flags = SNAME_FLG_STRNCMP; new->next = NULL; /* * Put this one in the list */ new->next = sect_head; sect_head = new; return (0); } /* * Check if the 'name' exists in the section list. * * If found * return 0; * else * return 1 */ int sectcmp(char *name) { /* * Check if the name is already specified or not. */ if (sect_head != NULL) { S_Name *p1 = sect_head; while (p1 != NULL) { if (p1->flags & SNAME_FLG_STRNCMP) { if (strncmp(p1->name, name, strlen(p1->name)) == 0) return (0); } else if (strcmp(p1->name, name) == 0) { return (0); /* silently ignore */ } p1 = p1->next; } } return (1); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1988 AT&T * All Rights Reserved * * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. */ #ifndef _MCS_H #define _MCS_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sgs.h" #include "gelf.h" #define FORMAT "%-16s%-12ld%-6u%-6u%-8o%-10ld%-2s" #define ROUNDUP(x) (((x) + 1) & ~1) #define TMPDIR "/tmp" #define DELETED -1 /* The section will be removed */ #define NULLED -2 /* The section will be nulled */ #define EXPANDED -3 /* The size of the section expanded */ #define SHRUNK -4 /* The section shrinked */ #define ACT_NOP 0x00000000 #define ACT_DELETE 0x00000001 #define ACT_PRINT 0x00000002 #define ACT_COMPRESS 0x00000003 #define ACT_APPEND 0x00000004 #define ACT_ZAP 0x00000005 #define SET_ACTION(x, y) x = (x & 0xfffffff0) | y #define GET_ACTION(x) (x & 0x0000000f) #define NOSEG 0x00000010 #define IN 0x00000020 /* section is IN a segment */ #define PRIOR 0x00000030 /* section is PRIOR to a segment */ #define AFTER 0x00000040 /* section is AFTER a segment */ #define SET_LOC(x, y) x = (x & 0xffffff0f) | y #define GET_LOC(x) (x & 0x000000f0) #define CANDIDATE 0x00000100 #define MOVING 0x00000200 #define MODIFIED 0x00000400 #define UNSET_CANDIDATE(x) x = x & ~CANDIDATE #define SET_CANDIDATE(x) x = x | CANDIDATE #define ISCANDIDATE(x) (x & CANDIDATE) #define SET_MOVING(x) x = (x | MOVING) #define GET_MOVING(x) (x & MOVING) #define SET_MODIFIED(x) x = (x | MODIFIED) #define GET_MODIFIED(x) (x & MODIFIED) #define FAILURE 1 #define SUCCESS 0 #define DONT_BUILD 3 /* this code is used to prevent building a new file */ /* because mcs was given only -p */ #define MCS 1 #define STRIP 2 #define STR_STRIP "strip" /* * Structure to hold section information. */ typedef struct section_info_table { /* * Section information. */ Elf_Scn *scn; /* Section */ Elf_Data *data; /* Original data */ Elf_Data *mdata; /* Modified data */ char *name; /* Section name, or NULL if unknown */ char *rel_name; GElf_Shdr shdr; GElf_Word secno; /* The new index */ GElf_Word osecno; /* The original index */ GElf_Word rel_scn_index; GElf_Xword si_flags; GElf_Xword rel_loc; } section_info_table; /* * Structure to hold action information */ typedef struct action { int a_action; /* Which action to take ? */ int a_cnt; /* Am I applied ? */ char *a_string; /* The string to be added. */ } action; /* * Structure to hold the section names specified. */ typedef struct s_name { char *name; struct s_name *next; unsigned char flags; } S_Name; #define SECT_NAME sect_head->name #define SNAME_FLG_STRNCMP 0x01 /* Use strncmp() instead of strcmp() */ /* for section name comparison. */ /* * Structure to hold command information */ typedef struct cmd_info { APlist *sh_groups; /* list of SHT_GROUP sections */ int no_of_append; int no_of_delete; int no_of_nulled; int no_of_compressed; int no_of_moved; size_t str_size; /* size of string to be appended */ int ci_flags; /* Various flags */ } Cmd_Info; #define MIGHT_CHG 0x0001 #define aFLAG 0x0002 #define cFLAG 0x0004 #define dFLAG 0x0008 #define lFLAG 0x0010 #define pFLAG 0x0020 #define xFLAG 0x0040 #define VFLAG 0x0080 #define zFLAG 0x0100 #define I_AM_STRIP 0x0200 #define SHF_GROUP_MOVE 0x0400 /* SHF_GROUP section moves */ #define SHF_GROUP_DEL 0x0800 /* SHF_GROUP section deleted */ #define CHK_OPT(_x, _y) (((_x)->ci_flags & (_y)) != 0) #define SET_OPT(_x, _y) ((_x)->ci_flags |= (_y)) /* * Segment Table */ typedef struct seg_table { GElf_Off p_offset; GElf_Xword p_memsz; GElf_Xword p_filesz; } Seg_Table; /* * Temporary files */ typedef struct { const char *tmp_name; /* NULL, or name of temp file */ int tmp_unlink; /* True if should unlink prior to exit */ } Tmp_File; /* * Function prototypes. */ int apply_action(section_info_table *, char *, Cmd_Info *); int each_file(char *, Cmd_Info *); void error_message(int, ...); void mcs_exit(int); int sectcmp(char *); void free_tempfile(Tmp_File *); /* * Error messages */ #define MALLOC_ERROR 0 #define USAGE_ERROR 1 #define ELFVER_ERROR 2 #define OPEN_ERROR 3 #define LIBELF_ERROR 4 #define OPEN_TEMP_ERROR 5 #define WRITE_ERROR 6 #define GETARHDR_ERROR 7 #define FILE_TYPE_ERROR 8 #define NOT_MANIPULATED_ERROR 9 #define WRN_MANIPULATED_ERROR 10 #define NO_SECT_TABLE_ERROR 11 #define READ_ERROR 12 #define READ_MANI_ERROR 13 #define WRITE_MANI_ERROR 14 #define LSEEK_MANI_ERROR 15 #define SYM_TAB_AR_ERROR 16 #define EXEC_AR_ERROR 17 #define READ_SYS_ERROR 18 #define OPEN_WRITE_ERROR 19 #define ACT_PRINT_ERROR 20 #define ACT_DELETE1_ERROR 21 #define ACT_DELETE2_ERROR 22 #define ACT_APPEND1_ERROR 23 #define ACT_APPEND2_ERROR 24 #define ACT_COMPRESS1_ERROR 25 #define ACT_COMPRESS2_ERROR 26 #define ACCESS_ERROR 27 #define WRITE_MANI_ERROR2 28 #define PLAIN_ERROR 0 #define LIBelf_ERROR 1 #define SYSTEM_ERROR 2 #ifdef __cplusplus } #endif #endif /* _MCS_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright(c) 1988 AT&T * All Rights Reserved * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "mcs.h" static const char *msg[] = { /* MALLOC_ERROR */ "%s: malloc memory allocation failure.\n", /* USAGE_ERROR */ "%s: multiple -n only allowed for -d option.\n", /* ELFVER_ERROR */ "%s: elf_version() failed - libelf.a out of date.\n", /* OPEN_ERROR */ "%s: %s: cannot open file.\n", /* LIBELF_ERROR */ "%s: libelf error.\n", /* OPEN_TEMP_ERROR */ "%s: %s: cannot open temporary file\n", /* WRITE_ERROR */ "%s: %s: write system failure: %s: file not manipulated.\n", /* GETARHDR_ERROR */ "%s: %s: malformed archive at %ld\n", /* FILE_TYPE_ERROR */ "%s: %s: invalid file type\n", /* NOT_MANIPULATED_ERROR */ "%s: %s: file not manipulated\n", /* WRN_MANIPULATED_ERROR */ "%s: WARNING: %s: Cannot manipulate file.\n", /* NO_SECT_TABLE_ERROR */ "%s: %s: no section header table.\n", /* READ_ERROR */ "%s: %s: trouble reading file\n", /* READ_MANI_ERROR */ "%s: %s: read system failure: %s: file not manipulated.\n", /* WRITE_MANI_ERROR */ "%s: %s: write system failure: %s: file not manipulated.\n", /* LSEEK_MANI_ERROR */ "%s: %s: lseek system failure: %s: file not manipulated.\n", /* SYM_TAB_AR_ERROR */ "%s: WARNING: %s: symbol table deleted from archive \n", /* EXEC_AR_ERROR */ "execute `ar -ts %s` to restore symbol table.\n", /* READ_SYS_ERROR */ "%s: %s: read system failure\n", /* OPEN_WRITE_ERROR */ "%s: %s: can't open file for writing\n", /* ACT_PRINT_ERROR */ "%s: %s: Cannot print contents of a NOBITS section (%s)\n", /* ACT_DELETE1_ERROR */ "%s: %s: Warning: Cannot delete section (%s)\n\t\tfrom a segment.\n", /* ACT_DELETE2_ERROR */ "%s: %s: Warning: Cannot delete section (%s)\n" "\t\tbecause its relocation section (%s) is in a segment\n", /* ACT_APPEND1_ERROR */ "%s: %s: Cannot append to a NOBITS section (%s)\n", /* ACT_APPEND2_ERROR */ "%s: %s: Warning: Cannot append to section (%s)\n\t\tin a segment\n", /* ACT_COMPRESS1_ERROR */ "%s: %s: Cannot compress a NOBITS section (%s)\n", /* ACT_COMPRESS2_ERROR */ "%s: %s: Warning: Cannot compress a section (%s)\n\t\tin a segment\n", /* ACCESS_ERROR */ "%s: %s: access error.\n", /* WRITE_MANI_ERROR2 */ "%s: /ftruncate/lseek/write system failure: %s: file may be destroyed.\n" }; void error_message(int args, ...) { int mes = args; char *message = gettext((char *)msg[mes]); int flag; char *sys_mes; va_list ap; va_start(ap, args); flag = va_arg(ap, int); sys_mes = va_arg(ap, char *); switch (mes) { case MALLOC_ERROR: case USAGE_ERROR: case ELFVER_ERROR: case EXEC_AR_ERROR: case LIBELF_ERROR: /* LINTED */ (void) fprintf(stderr, message, va_arg(ap, char *)); break; case OPEN_ERROR: case ACCESS_ERROR: case OPEN_TEMP_ERROR: case FILE_TYPE_ERROR: case NOT_MANIPULATED_ERROR: case WRN_MANIPULATED_ERROR: case NO_SECT_TABLE_ERROR: case READ_ERROR: case SYM_TAB_AR_ERROR: case READ_SYS_ERROR: case OPEN_WRITE_ERROR: /* LINTED */ (void) fprintf(stderr, message, va_arg(ap, char *), va_arg(ap, char *)); break; case WRITE_ERROR: case READ_MANI_ERROR: case WRITE_MANI_ERROR: case LSEEK_MANI_ERROR: case ACT_PRINT_ERROR: case ACT_DELETE1_ERROR: case ACT_APPEND1_ERROR: case ACT_APPEND2_ERROR: case ACT_COMPRESS1_ERROR: case ACT_COMPRESS2_ERROR: { char *a = va_arg(ap, char *); char *b = va_arg(ap, char *); char *c = va_arg(ap, char *); /* LINTED */ (void) fprintf(stderr, message, a, b, c); break; } case ACT_DELETE2_ERROR: { char *a = va_arg(ap, char *); char *b = va_arg(ap, char *); char *c = va_arg(ap, char *); char *d = va_arg(ap, char *); /* LINTED */ (void) fprintf(stderr, message, a, b, c, d); break; } case GETARHDR_ERROR: { char *a = va_arg(ap, char *); char *b = va_arg(ap, char *); long c = va_arg(ap, long); /* LINTED */ (void) fprintf(stderr, message, a, b, c); break; } default: (void) fprintf(stderr, "internal error: error_message(%d)\n", mes); mcs_exit(100); } if (flag != PLAIN_ERROR) (void) fprintf(stderr, "\t%s\n", sys_mes); va_end(ap); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright(c) 1988 AT&T * All Rights Reserved * */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. */ #include "mcs.h" #include "extern.h" #include "gelf.h" /* * Function prototypes. */ static void docompress(section_info_table *); static char *compress(char *, size_t *); static void doappend(char *, section_info_table *); static void doprint(char *, section_info_table *); static void dozap(section_info_table *); static int dohash(char *); /* * Apply the actions specified by the user. */ int apply_action(section_info_table *info, char *cur_file, Cmd_Info *cmd_info) { int act_index; int ret = 0; GElf_Shdr shdr; (void) gelf_getshdr(info->scn, &shdr); for (act_index = 0; act_index < actmax; act_index++) { Action[act_index].a_cnt++; switch (Action[act_index].a_action) { case ACT_ZAP: if (GET_ACTION(info->si_flags) == ACT_DELETE) break; dozap(info); SET_ACTION(info->si_flags, ACT_ZAP); SET_MODIFIED(info->si_flags); break; case ACT_PRINT: if (GET_ACTION(info->si_flags) == ACT_DELETE) break; if (shdr.sh_type == SHT_NOBITS) { error_message(ACT_PRINT_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME); break; } doprint(cur_file, info); break; case ACT_DELETE: /* * If I am strip command, this is the * only action I can take. */ if (GET_ACTION(info->si_flags) == ACT_DELETE) break; if (GET_LOC(info->si_flags) == IN) { /* * If I am 'strip', I have to * unset the candidate flag and * unset the error return code. */ if (CHK_OPT(cmd_info, I_AM_STRIP)) { ret = 0; UNSET_CANDIDATE(info->si_flags); } else { char *name = info->name; ret++; if (name == NULL) name = gettext(""); error_message(ACT_DELETE1_ERROR, PLAIN_ERROR, NULL, prog, cur_file, name); } break; } else if (info->rel_loc == IN) { /* * If I am 'strip', I have to * unset the candidate flag and * unset the error return code. */ if (CHK_OPT(cmd_info, I_AM_STRIP)) { ret = 0; UNSET_CANDIDATE(info->si_flags); } else { ret++; error_message(ACT_DELETE2_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME, info->rel_name); } break; } else if (GET_LOC(info->si_flags) == PRIOR) { /* * I can not delete this * section. I can only NULL * this out. */ info->secno = (GElf_Word)NULLED; (cmd_info->no_of_nulled)++; } else { info->secno = (GElf_Word)DELETED; (cmd_info->no_of_delete)++; } SET_ACTION(info->si_flags, ACT_DELETE); SET_MODIFIED(info->si_flags); break; case ACT_APPEND: if (shdr.sh_type == SHT_NOBITS) { ret++; error_message(ACT_APPEND1_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME); break; } else if (GET_LOC(info->si_flags) == IN) { ret++; error_message(ACT_APPEND2_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME); break; } doappend(Action[act_index].a_string, info); (cmd_info->no_of_append)++; info->secno = info->osecno; SET_ACTION(info->si_flags, ACT_APPEND); SET_MODIFIED(info->si_flags); if (GET_LOC(info->si_flags) == PRIOR) info->secno = (GElf_Word)EXPANDED; break; case ACT_COMPRESS: /* * If this section is already deleted, * don't do anything. */ if (GET_ACTION(info->si_flags) == ACT_DELETE) break; if (shdr.sh_type == SHT_NOBITS) { ret++; error_message(ACT_COMPRESS1_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME); break; } else if (GET_LOC(info->si_flags) == IN) { ret++; error_message(ACT_COMPRESS2_ERROR, PLAIN_ERROR, NULL, prog, cur_file, SECT_NAME); break; } docompress(info); (cmd_info->no_of_compressed)++; SET_ACTION(info->si_flags, ACT_COMPRESS); SET_MODIFIED(info->si_flags); if (GET_LOC(info->si_flags) == PRIOR) info->secno = (GElf_Word)SHRUNK; break; } } return (ret); } /* * ACT_ZAP */ static void dozap(section_info_table *info) { Elf_Data *data; info->mdata = data = malloc(sizeof (Elf_Data)); if (data == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } *data = *info->data; data->d_buf = calloc(1, data->d_size); if (data->d_buf == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } } /* * ACT_PRINT */ static void doprint(char *cur_file, section_info_table *info) { Elf_Data *data; size_t temp_size; char *temp_string; if (GET_MODIFIED(info->si_flags) == 0) data = info->data; else data = info->mdata; if (data == 0) return; temp_size = data->d_size; temp_string = data->d_buf; if (temp_size == 0) return; (void) fprintf(stdout, "%s:\n", cur_file); while (temp_size--) { char c = *temp_string++; switch (c) { case '\0': (void) putchar('\n'); break; default: (void) putchar(c); break; } } (void) putchar('\n'); } /* * ACT_APPEND */ static void doappend(char *a_string, section_info_table *info) { Elf_Data *data; char *p; size_t len; char *tp; /* * Get the length of the string to be added. We accept any * string (even null), as this is arbitrary user defined text. * * The caller expects this routine to replace a NULL info->mdata * field with a pointer to a freshly allocated copy. Any attempt * to optimize away a null string append would have to deal with * that, as failing to do so will cause a segfault when the NULL * mdata field is dereferenced. Accepting null strings in * this very unimportant case eliminates the need for that. */ len = strlen(a_string); /* * Every modification operation will be done * to a new Elf_Data descriptor. */ if (info->mdata == 0) { /* * mdata is not allocated yet. * Allocate the data and set it. */ info->mdata = data = calloc(1, sizeof (Elf_Data)); if (data == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } *data = *info->data; /* * Check if the section is deleted or not. * Or if the size is 0 or not. */ if ((GET_ACTION(info->si_flags) == ACT_DELETE) || data->d_size == 0) { /* * The section was deleated. * But now, the user wants to add data to this * section. */ data->d_buf = calloc(1, len + 2); if (data->d_buf == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } tp = (char *)data->d_buf; (void) memcpy(& tp[1], a_string, len + 1); data->d_size = len + 2; } else { /* * The user wants to add data to the section. * I am not going to change the original data. * Do the modification on the new one. */ p = malloc(len + 1 + data->d_size); if (p == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } (void) memcpy(p, data->d_buf, data->d_size); (void) memcpy(&p[data->d_size], a_string, len + 1); data->d_buf = p; data->d_size = data->d_size + len + 1; } } else { /* * mdata is already allocated. * Modify it. */ data = info->mdata; if ((GET_ACTION(info->si_flags) == ACT_DELETE) || data->d_size == 0) { /* * The section was deleated. * But now, the user wants to add data to this * section. */ if (data->d_buf) free(data->d_buf); data->d_buf = calloc(1, len + 2); if (data->d_buf == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } tp = (char *)data->d_buf; (void) memcpy(&tp[1], a_string, len + 1); data->d_size = len + 2; } else { /* * The user wants to add data to the section. * I am not going to change the original data. * Do the modification on the new one. */ p = malloc(len + 1 + data->d_size); if (p == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } (void) memcpy(p, data->d_buf, data->d_size); (void) memcpy(&p[data->d_size], a_string, len + 1); free(data->d_buf); data->d_buf = p; data->d_size = data->d_size + len + 1; } } } /* * ACT_COMPRESS */ #define HALFLONG 16 #define low(x) (x&((1L<>HALFLONG) static void docompress(section_info_table *info) { Elf_Data *data; size_t size; char *buf; if (info->mdata == 0) { /* * mdata is not allocated yet. * Allocate the data and set it. */ char *p; info->mdata = data = calloc(1, sizeof (Elf_Data)); if (data == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } *data = *info->data; p = malloc(data->d_size); (void) memcpy(p, (char *)data->d_buf, data->d_size); data->d_buf = p; } size = info->mdata->d_size; buf = (char *)info->mdata->d_buf; buf = compress(buf, &size); info->mdata->d_buf = buf; info->mdata->d_size = size; } static char * compress(char *str, size_t *size) { int hash; int i; size_t temp_string_size = 0; size_t o_size = *size; char *temp_string = str; int *hash_key; size_t hash_num; size_t hash_end; size_t *hash_str; char *strings; size_t next_str; size_t str_size; hash_key = malloc(sizeof (int) * 200); hash_end = 200; hash_str = malloc(sizeof (size_t) * 200); str_size = o_size+1; strings = malloc(str_size); if (hash_key == NULL || hash_str == NULL || strings == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } hash_num = 0; next_str = 0; while (temp_string_size < o_size) { size_t pos; char c; /* * Get a string */ pos = next_str; while ((c = *(temp_string++)) != '\0' && (temp_string_size + (next_str - pos)) <= o_size) { if (next_str >= str_size) { str_size *= 2; if ((strings = (char *) realloc(strings, str_size)) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } } strings[next_str++] = c; } if (next_str >= str_size) { str_size *= 2; if ((strings = (char *) realloc(strings, str_size)) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } } strings[next_str++] = '\0'; /* * End get string */ temp_string_size += (next_str - pos); hash = dohash(pos + strings); for (i = 0; i < hash_num; i++) { if (hash != hash_key[i]) continue; if (strcmp(pos + strings, hash_str[i] + strings) == 0) break; } if (i != hash_num) { next_str = pos; continue; } if (hash_num == hash_end) { hash_end *= 2; hash_key = realloc((char *)hash_key, hash_end * sizeof (int)); hash_str = realloc((char *)hash_str, hash_end * sizeof (size_t)); if (hash_key == NULL || hash_str == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog); mcs_exit(FAILURE); } } hash_key[hash_num] = hash; hash_str[hash_num++] = pos; } /* * Clean up */ free(hash_key); free(hash_str); /* * Return */ if (next_str != o_size) { /* * string compressed. */ *size = next_str; free(str); str = malloc(next_str); (void) memcpy(str, strings, next_str); } free(strings); return (str); } static int dohash(char *str) { long sum; unsigned shift; int t; sum = 1; for (shift = 0; (t = *str++) != 0; shift += 7) { sum += (long)t << (shift %= HALFLONG); } sum = low(sum) + high(sum); /* LINTED */ return ((short)low(sum) + (short)high(sum)); }