# # 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 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # 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 2015 Gary Mills # Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2018, Joyent, Inc. # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # LIBRARY= libelf.a VERS= .1 MACHOBJS= COMOBJS= ar.o begin.o cntl.o cook.o \ data.o end.o fill.o flag.o \ getarhdr.o getarsym.o getbase.o getdata.o \ getehdr.o getident.o getphdr.o getscn.o \ getshdr.o \ getphnum.o getshnum.o getshstrndx.o \ hash.o input.o kind.o \ ndxscn.o newdata.o newehdr.o newphdr.o \ newscn.o next.o nextscn.o output.o \ rand.o rawdata.o rawfile.o rawput.o \ strptr.o update.o error.o gelf.o \ clscook.o checksum.o CLASSOBJS= clscook64.o newehdr64.o newphdr64.o update64.o \ checksum64.o BLTOBJS= msg.o xlate.o xlate64.o MISCOBJS= String.o args.o demangle.o nlist.o \ nplist.o MISCOBJS64= nlist.o OBJECTS= $(BLTOBJS) $(MACHOBJS) $(COMOBJS) $(CLASSOBJS) $(MISCOBJS) include $(SRC)/lib/Makefile.lib include $(SRC)/lib/Makefile.rootfs SRCDIR= $(SRC)/cmd/sgs/libelf # Use the value of M4 set in Makefile.master via Makefile.lib DEMOFILES= Makefile 00README acom.c dcom.c \ pcom.c tpcom.c dispsyms.c DEMOFILESRCDIR= $(SRCDIR)/demo ROOTDEMODIRBASE=$(ROOT)/usr/demo/ELF ROOTDEMODIRS= $(ROOTDEMODIRBASE) include $(SRC)/cmd/sgs/Makefile.com MAPFILES = $(SRCDIR)/common/mapfile-vers DYNFLAGS += $(VERSREF) LDLIBS += $(CONVLIBDIR) -lconv -lc SMOFF += indenting BLTDEFS= msg.h BLTDATA= msg.c BLTMESG= $(SGSMSGDIR)/libelf BLTFILES= $(BLTDEFS) $(BLTDATA) $(BLTMESG) SGSMSGCOM= $(SRCDIR)/common/libelf.msg SGSMSG32= $(SRCDIR)/common/libelf.32.msg SGSMSGTARG= $(SGSMSGCOM) SGSMSGALL= $(SGSMSGCOM) $(SGSMSG32) SGSMSGFLAGS1= $(SGSMSGFLAGS) -m $(BLTMESG) SGSMSGFLAGS2= $(SGSMSGFLAGS) -h $(BLTDEFS) -d $(BLTDATA) -n libelf_msg BLTSRCS= $(BLTOBJS:%.o=%.c) LIBSRCS= $(COMOBJS:%.o=$(SRCDIR)/common/%.c) $(MISCOBJS:%.o=$(SRCDIR)/misc/%.c) \ $(MACHOBJS:%.o=%.c) $(BLTSRCS) LIBS = $(DYNLIB) CLEANFILES += $(BLTSRCS) $(BLTFILES) .PARALLEL: $(LIBS) # # 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) 1994, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2016 RackTop Systems. # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # objs/%.o \ pics/%.o: %.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) objs/%64.o \ pics/%64.o: $(SRCDIR)/common/%.c $(COMPILE.c) -D_ELF64 -o $@ $< $(POST_PROCESS_O) objs/%.o \ pics/%.o: $(SRCDIR)/misc/%.c $(COMPILE.c) -DELF -o $@ $< $(POST_PROCESS_O) objs/%.o \ pics/%.o: $(SRCDIR)/common/%.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) all: $(BLTSRCS) .WAIT $(LIBS) $(LIBLINKS) $(LIBLINKS): $(RM) $(LIBLINKS) $(SYMLINK) $(DYNLIB) $(LIBLINKS) CLOBBERFILES += $(LIBLINKS) # include common library targets # include $(SRC)/lib/Makefile.targ xlate.c: $(SRCDIR)/common/xlate.m4 $(M4) < $(SRCDIR)/common/xlate.m4 > xlate.c xlate64.c: $(SRCDIR)/common/xlate64.m4 $(M4) < $(SRCDIR)/common/xlate64.m4 > xlate64.c objs/msg.o \ pics/msg.o: msg.c objs/error.o \ pics/error.o: msg.h objs/ar.o \ pics/ar.o: msg.h objs/xlate.o \ pics/xlate.o: xlate.c $(PICS): pics # Derived source and header files (messaging). Make sure that the sgsmsg # command is constructed - libelf might not be built with the whole sgs. catalog: $(BLTMESG) chkmsg: $(LIBSRCS) sh $(CHKMSG) $(CHKMSGFLAGS) $(LIBSRCS) # Hammerhead: GNU Make grouped target syntax (&:) - was dmake + syntax $(BLTDEFS) $(BLTDATA) &: $(SGSMSGTARG) $(SGSMSG) $(SGSMSGFLAGS2) $(SGSMSGTARG) $(BLTMESG): $(SGSMSGALL) xlate.c xlate64.c $(SGSMSG) $(SGSMSGFLAGS1) $(SGSMSGALL) FRC: # # 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) 1997, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # objs/%.o \ pics/%.o: %.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) objs/%64.o \ pics/%64.o: ../common/%.c $(COMPILE.c) -D_ELF64 -o $@ $< $(POST_PROCESS_O) objs/%.o \ pics/%.o: ../misc/%.c $(COMPILE.c) -DELF -o $@ $< $(POST_PROCESS_O) objs/%.o \ pics/%.o: ../common/%.c $(COMPILE.c) -o $@ $< $(POST_PROCESS_O) all: $(BLTSRCS) .WAIT $(LIBS) $(LIBLINKS) $(LIBLINKS): $(RM) $(LIBLINKS) $(SYMLINK) $(DYNLIB) $(LIBLINKS) CLOBBERFILES += $(LIBLINKS) # include common library targets # include $(SRC)/lib/Makefile.targ xlate.c: ../common/xlate.m4 $(M4) < ../common/xlate.m4 > xlate.c xlate64.c: ../common/xlate64.m4 $(M4) < ../common/xlate64.m4 > xlate64.c objs/msg.o \ pics/msg.o: msg.c objs/error.o \ pics/error.o: msg.h objs/ar.o \ pics/ar.o: msg.h objs/xlate.o \ pics/xlate.o: xlate.c # Derived source and header files (messaging). Make sure that the sgsmsg # command is constructed - libelf might not be built with the whole sgs. catalog: $(BLTMESG) chkmsg: $(LIBSRCS) sh $(CHKMSG) $(CHKMSGFLAGS) $(LIBSRCS) # Hammerhead: GNU Make grouped target syntax (&:) - was dmake + syntax $(BLTDEFS) $(BLTDATA) &: $(SGSMSGTARG) $(SGSMSG) $(SGSMSGFLAGS2) $(SGSMSGTARG) $(BLTMESG): $(SGSMSGALL) xlate.c xlate64.c $(SGSMSG) $(SGSMSGFLAGS1) $(SGSMSGALL) # # 64-bit overrides # include $(SRC)/Makefile.master.64 FRC: # # 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 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # include ../Makefile.com CONVLIBDIR= $(CONVLIBDIR64) MISCOBJS= $(MISCOBJS64) .KEEP_STATE: install: all .WAIT $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTCOMPATLINKS64) include ../Makefile.targ.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 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # Why 32-bit libelf is not Large File Aware ----------------------------------------- The ELF format uses unsigned 32-bit integers for offsets, so the theoretical limit on a 32-bit ELF object is 4GB. However, libelf imposes a 2GB limit on the objects it can create. The Solaris link-editor and related tools are all based on libelf, so the 32-bit version of the link-editor also has a 2GB limit, despite the theoretical limit of 4GB. Large file support (LFS) is a half step between the 32 and 64-bit worlds, in which an otherwise 32-bit limited process is allowed to read and write data to a file that can be larger than 2GB (the extent of a signed 32-bit integer, as represented by the system type off_t). LFS is useful if the program only needs to access a small subset of the file data at any given time (e.g. /bin/cat). It is less useful if the program needs to access a large amount of data at once --- having been freed from the file limit, the program will simply hit the virtual memory limit (4GB). In particular, the link-editor generally requires twice as much memory as the size of the output object, half to hold the input objects, and half to hold the result. This means that a 32-bit link-editor process will hit the 2GB file size limit and the 4GB address space limit at roughly the same time. As a result, a large file aware 32-bit version of libelf has no significant value. Despite this, the question of what it would take to make libelf large file aware comes up from time to time. The first step would be to provide alternative versions of all public data structures that involve the off_t data type. These structs, found in /usr/include/libelf.h, are: /* * Archive member header */ typedef struct { char *ar_name; time_t ar_date; uid_t ar_uid; gid_t ar_gid; mode_t ar_mode; off_t ar_size; char *ar_rawname; } Elf_Arhdr; /* * Data descriptor */ typedef struct { Elf_Void *d_buf; Elf_Type d_type; size_t d_size; off_t d_off; /* offset into section */ size_t d_align; /* alignment in section */ unsigned d_version; /* elf version */ } Elf_Data; As off_t is a signed type, these alternative versions would have to use an off64_t type instead. In addition to providing alternative large file aware Elf_Arhdr and Elf_Data types, it would be necessary to implement large file aware versions of the public functions that use them, also found in /usr/include/libelf.h: /* * Function declarations */ unsigned elf_flagdata(Elf_Data *, Elf_Cmd, unsigned); Elf_Arhdr *elf_getarhdr(Elf *); off_t elf_getbase(Elf *); Elf_Data *elf_getdata(Elf_Scn *, Elf_Data *); Elf_Data *elf_newdata(Elf_Scn *); Elf_Data *elf_rawdata(Elf_Scn *, Elf_Data *); off_t elf_update(Elf *, Elf_Cmd); Elf_Data *elf32_xlatetof(Elf_Data *, const Elf_Data *, unsigned); Elf_Data *elf32_xlatetom(Elf_Data *, const Elf_Data *, unsigned); Elf_Data *elf64_xlatetof(Elf_Data *, const Elf_Data *, unsigned); Elf_Data *elf64_xlatetom(Elf_Data *, const Elf_Data *, unsigned); It is important to note that these new versions cannot replace the original definitions. Those must continue to be available to support non-large-file-aware programs. These new types and functions would be in addition to the pre-existing versions. When you make code like this large file aware, it is necessary to undertake a careful analysis of the code to ensure that all the surrounding code uses variable types large enough to handle the increased range. Hence, this work is more complicated than simply supplying variants that use a bigger off_t and rebuilding --- that is just the first step. There are two standard preprocessor definitions used to control large file support: _LARGEFILE64_SOURCE _FILE_OFFSET_BITS These preprocessor definitions would be used to determine whether a given program linked against libelf would see the regular, or the large file aware versions of the above types and routines. This is the same approach used in other large file capable software, such as libc. Finally, all the applications that rely on libelf would need to be made large file aware. As with libelf itself, there is more to such an effort than recompiling with preprocessor macros set. The code in these applications would need to be examined carefully. Some of these programs are very old, and were not originally written with such type portability in mind. Such code can be difficult to transition. To work around the 2GB limit in 32-bit libelf: - The fundamental limits of a 32-bit address space mean that a program this large should be 64-bit. Only a 64-bit address space has enough room for that much code, plus the stack and heap needed to do useful work with it. - The 64-bit version of libelf is also able to process 32-bit objects, and does not have a 2GB file size limit. Therefore, the 64-bit link-editor can be used to build a 32-bit executable which is >2GB. The resulting program will consume over half the available address space just to start running. However, there may be enough address space left for it to do useful work. Note that the 32-bit limit for sharable objects remains at 2GB --- imposed by the runtime linker, which is also not large file aware. /* * 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) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright (c) 1988 AT&T * All Rights Reserved */ /* * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include #include "decl.h" #include "msg.h" #include "member.h" #define MANGLE '\177' /* * Archive processing * When processing an archive member, two things can happen * that are a little tricky. * * Sliding * Sliding support is left in for backward compatibility and for * support of Archives produced on other systems. The bundled * ar(1) produces archives with all members on a 4 byte boundry, * so current archives should need no sliding. * * Archive members that are only 2-byte aligned within the file will * be slid. To reuse the file's memory image, the library slides an * archive member into its header to align the bytes. This means * the header must be disposable. * * Header reuse * Because the library can trample the header, it must be preserved to * avoid restrictions on archive member reuse. That is, if the member * header changes, the library may see garbage the next time it looks * at the header. After extracting the original header, the library * appends it to the parents `ed_memlist' list, thus future lookups first * check this list to determine if a member has previously been processed * and whether sliding occured. */ /* * Size check * If the header is too small, the following generates a negative * subscript for x.x and fails to compile. * * The check is based on sizeof (Elf64) because that's always going * to be at least as big as Elf32. */ struct x { char x[sizeof (struct ar_hdr) - 3 * sizeof (Elf64) - 1]; }; static const char fmag[] = ARFMAG; /* * Convert a string starting at 'p' and ending at 'end' into * an integer. Base is the base of the number being converted * (either 8 or 10). * * Returns the converted integer of the string being scaned. */ unsigned long _elf_number(char *p, char *end, int base) { register unsigned c; register unsigned long n = 0; while (p < end) { if ((c = *p - '0') >= base) { while (*p++ == ' ') if (p >= end) return (n); return (0); } n *= base; n += c; ++p; } return (n); } /* * Convert ar_hdr to Member * Converts ascii file representation to the binary memory values. */ Member * _elf_armem(Elf *elf, char *file, size_t fsz) { register struct ar_hdr *f = (struct ar_hdr *)file; register Member *m; register Memlist *l, * ol; register Memident *i; if (fsz < sizeof (struct ar_hdr)) { _elf_seterr(EFMT_ARHDRSZ, 0); return (0); } /* * Determine in this member has already been processed */ for (l = elf->ed_memlist, ol = l; l; ol = l, l = l->m_next) for (i = (Memident *)(l + 1); i < l->m_free; i++) if (i->m_offset == file) return (i->m_member); if (f->ar_fmag[0] != fmag[0] || f->ar_fmag[1] != fmag[1]) { _elf_seterr(EFMT_ARFMAG, 0); return (0); } /* * Allocate a new member structure and assign it to the next free * free memlist ident. */ if ((m = (Member *)malloc(sizeof (Member))) == 0) { _elf_seterr(EMEM_ARMEM, errno); return (0); } if ((elf->ed_memlist == 0) || (ol->m_free == ol->m_end)) { if ((l = (Memlist *)malloc(sizeof (Memlist) + (sizeof (Memident) * MEMIDENTNO))) == 0) { _elf_seterr(EMEM_ARMEM, errno); free(m); return (0); } l->m_next = 0; l->m_free = (Memident *)(l + 1); l->m_end = (Memident *)((uintptr_t)l->m_free + (sizeof (Memident) * MEMIDENTNO)); if (elf->ed_memlist == 0) elf->ed_memlist = l; else ol->m_next = l; ol = l; } ol->m_free->m_offset = file; ol->m_free->m_member = m; ol->m_free++; m->m_err = 0; (void) memcpy(m->m_name, f->ar_name, ARSZ(ar_name)); m->m_name[ARSZ(ar_name)] = '\0'; m->m_hdr.ar_name = m->m_name; (void) memcpy(m->m_raw, f->ar_name, ARSZ(ar_name)); m->m_raw[ARSZ(ar_name)] = '\0'; m->m_hdr.ar_rawname = m->m_raw; m->m_slide = 0; /* * Classify file name. * If a name error occurs, delay until getarhdr(). */ if (f->ar_name[0] != '/') { /* regular name */ register char *p; p = &m->m_name[sizeof (m->m_name)]; while (*--p != '/') if (p <= m->m_name) break; *p = '\0'; } else if (f->ar_name[1] >= '0' && f->ar_name[1] <= '9') { /* strtab */ register unsigned long j; j = _elf_number(&f->ar_name[1], &f->ar_name[ARSZ(ar_name)], 10); if (j < elf->ed_arstrsz) m->m_hdr.ar_name = elf->ed_arstr + j; else { m->m_hdr.ar_name = 0; /*LINTED*/ /* MSG_INTL(EFMT_ARSTRNM) */ m->m_err = (int)EFMT_ARSTRNM; } } else if (f->ar_name[1] == ' ') /* "/" */ m->m_name[1] = '\0'; else if (f->ar_name[1] == '/' && f->ar_name[2] == ' ') /* "//" */ m->m_name[2] = '\0'; else if (f->ar_name[1] == 'S' && f->ar_name[2] == 'Y' && f->ar_name[3] == 'M' && f->ar_name[4] == '6' && f->ar_name[5] == '4' && f->ar_name[6] == '/' && f->ar_name[7] == ' ') /* "/SYM64/" */ m->m_name[7] = '\0'; else { /* "/?" */ m->m_hdr.ar_name = 0; /*LINTED*/ /* MSG_INTL(EFMT_ARUNKNM) */ m->m_err = (int)EFMT_ARUNKNM; } m->m_hdr.ar_date = (time_t)_elf_number(f->ar_date, &f->ar_date[ARSZ(ar_date)], 10); /* LINTED */ m->m_hdr.ar_uid = (uid_t)_elf_number(f->ar_uid, &f->ar_uid[ARSZ(ar_uid)], 10); /* LINTED */ m->m_hdr.ar_gid = (gid_t)_elf_number(f->ar_gid, &f->ar_gid[ARSZ(ar_gid)], 10); /* LINTED */ m->m_hdr.ar_mode = (mode_t)_elf_number(f->ar_mode, &f->ar_mode[ARSZ(ar_mode)], 8); m->m_hdr.ar_size = (off_t)_elf_number(f->ar_size, &f->ar_size[ARSZ(ar_size)], 10); return (m); } /* * Initial archive processing * An archive may have two special members. * * A symbol table, named / or /SYM64/, must be first if it is present. * Both forms use the same layout differing in the width of the * integer type used (32 or 64-bit respectively). * * A long name string table, named //, must precede all "normal" * members. This string table is used to hold the names of archive * members with names that are longer than 15 characters. It should not * be confused with the string table found at the end of the symbol * table, which is used to hold symbol names. * * This code "peeks" at headers but doesn't change them. * Later processing wants original headers. * * String table is converted, changing '/' name terminators * to nulls. The last byte in the string table, which should * be '\n', is set to nil, guaranteeing null termination. That * byte should be '\n', but this code doesn't check. * * The symbol table conversion is delayed until needed. */ void _elf_arinit(Elf * elf) { char *base = elf->ed_ident; register char *end = base + elf->ed_fsz; register struct ar_hdr *a; register char *hdr = base + SARMAG; register char *mem; int j; size_t sz = SARMAG; elf->ed_status = ES_COOKED; elf->ed_nextoff = SARMAG; for (j = 0; j < 2; ++j) { /* 2 special members */ unsigned long n; if (((end - hdr) < sizeof (struct ar_hdr)) || (_elf_vm(elf, (size_t)(SARMAG), sizeof (struct ar_hdr)) != OK_YES)) return; a = (struct ar_hdr *)hdr; mem = (char *)a + sizeof (struct ar_hdr); n = _elf_number(a->ar_size, &a->ar_size[ARSZ(ar_size)], 10); if ((end - mem < n) || (a->ar_name[0] != '/') || ((sz = n) != n)) { return; } hdr = mem + sz; if (a->ar_name[1] == ' ') { /* 32-bit symbol table */ elf->ed_arsym = mem; elf->ed_arsymsz = sz; elf->ed_arsymoff = (char *)a - base; } else if (a->ar_name[1] == '/' && a->ar_name[2] == ' ') { /* Long name string table */ int k; if (_elf_vm(elf, (size_t)(mem - elf->ed_ident), sz) != OK_YES) return; if (elf->ed_vm == 0) { char *nmem; if ((nmem = malloc(sz)) == 0) { _elf_seterr(EMEM_ARSTR, errno); return; } (void) memcpy(nmem, mem, sz); elf->ed_myflags |= EDF_ASTRALLOC; mem = nmem; } elf->ed_arstr = mem; elf->ed_arstrsz = sz; elf->ed_arstroff = (char *)a - base; for (k = 0; k < sz; k++) { if (*mem == '/') *mem = '\0'; ++mem; } *(mem - 1) = '\0'; } else if (a->ar_name[1] == 'S' && a->ar_name[2] == 'Y' && a->ar_name[3] == 'M' && a->ar_name[4] == '6' && a->ar_name[5] == '4' && a->ar_name[6] == '/' && a->ar_name[7] == ' ') { /* 64-bit symbol table */ elf->ed_arsym = mem; elf->ed_arsymsz = sz; elf->ed_arsymoff = (char *)a - base; elf->ed_myflags |= EDF_ARSYM64; } else { return; } hdr += sz & 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 1988 AT&T * All Rights Reserved */ #include #include #include #include #include #include #include "decl.h" #include "member.h" #include "msg.h" static const char armag[] = ARMAG; /* * Initialize archive member */ Elf * _elf_member(int fd, Elf * ref, unsigned flags) { register Elf *elf; Member *mh; size_t base; if (ref->ed_nextoff >= ref->ed_fsz) return (0); if (ref->ed_fd == -1) /* disabled */ fd = -1; if (flags & EDF_WRITE) { _elf_seterr(EREQ_ARRDWR, 0); return (0); } if (ref->ed_fd != fd) { _elf_seterr(EREQ_ARMEMFD, 0); return (0); } if ((_elf_vm(ref, ref->ed_nextoff, sizeof (struct ar_hdr)) != OK_YES) || ((mh = _elf_armem(ref, ref->ed_ident + ref->ed_nextoff, ref->ed_fsz)) == 0)) return (0); base = ref->ed_nextoff + sizeof (struct ar_hdr); if (ref->ed_fsz - base < mh->m_hdr.ar_size) { _elf_seterr(EFMT_ARMEMSZ, 0); return (0); } if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) { _elf_seterr(EMEM_ELF, errno); return (0); } ++ref->ed_activ; elf->ed_parent = ref; elf->ed_fd = fd; elf->ed_myflags |= flags; elf->ed_armem = mh; elf->ed_fsz = mh->m_hdr.ar_size; elf->ed_baseoff = ref->ed_baseoff + base; elf->ed_memoff = base - mh->m_slide; elf->ed_siboff = base + elf->ed_fsz + (elf->ed_fsz & 1); ref->ed_nextoff = elf->ed_siboff; elf->ed_image = ref->ed_image; elf->ed_imagesz = ref->ed_imagesz; elf->ed_vm = ref->ed_vm; elf->ed_vmsz = ref->ed_vmsz; elf->ed_ident = ref->ed_ident + base - mh->m_slide; /* * If this member is the archive string table, * we've already altered the bytes. */ if (ref->ed_arstroff == ref->ed_nextoff) elf->ed_status = ES_COOKED; return (elf); } Elf * _elf_regular(int fd, unsigned flags) /* initialize regular file */ { Elf *elf; if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) { _elf_seterr(EMEM_ELF, errno); return (0); } elf->ed_fd = fd; elf->ed_myflags |= flags; if (_elf_inmap(elf) != OK_YES) { free(elf); return (0); } return (elf); } Elf * _elf_config(Elf * elf) { char *base; unsigned encode; ELFRWLOCKINIT(&elf->ed_rwlock); /* * Determine if this is a ELF file. */ base = elf->ed_ident; if ((elf->ed_fsz >= EI_NIDENT) && (_elf_vm(elf, (size_t)0, (size_t)EI_NIDENT) == OK_YES) && (base[EI_MAG0] == ELFMAG0) && (base[EI_MAG1] == ELFMAG1) && (base[EI_MAG2] == ELFMAG2) && (base[EI_MAG3] == ELFMAG3)) { elf->ed_kind = ELF_K_ELF; elf->ed_class = base[EI_CLASS]; elf->ed_encode = base[EI_DATA]; if ((elf->ed_version = base[EI_VERSION]) == 0) elf->ed_version = 1; elf->ed_identsz = EI_NIDENT; /* * Allow writing only if originally specified read only. * This is only necessary if the file must be translating * from one encoding to another. */ ELFACCESSDATA(encode, _elf_encode) if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) && (elf->ed_encode != encode)) { if (mprotect((char *)elf->ed_image, elf->ed_imagesz, PROT_READ|PROT_WRITE) == -1) { _elf_seterr(EIO_VM, errno); return (0); } } return (elf); } /* * Determine if this is an Archive */ if ((elf->ed_fsz >= SARMAG) && (_elf_vm(elf, (size_t)0, (size_t)SARMAG) == OK_YES) && (memcmp(base, armag, SARMAG) == 0)) { _elf_arinit(elf); elf->ed_kind = ELF_K_AR; elf->ed_identsz = SARMAG; return (elf); } /* * Return a few ident bytes, but not so many that * getident() must read a large file. 512 is arbitrary. */ elf->ed_kind = ELF_K_NONE; if ((elf->ed_identsz = elf->ed_fsz) > 512) elf->ed_identsz = 512; return (elf); } Elf * elf_memory(char *image, size_t sz) { Elf *elf; unsigned work; /* * version() no called yet? */ ELFACCESSDATA(work, _elf_work) if (work == EV_NONE) { _elf_seterr(ESEQ_VER, 0); return (0); } if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) { _elf_seterr(EMEM_ELF, errno); return (0); } elf->ed_fd = -1; elf->ed_myflags |= EDF_READ | EDF_MEMORY; elf->ed_image = elf->ed_ident = image; elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz; elf->ed_kind = ELF_K_ELF; elf->ed_class = image[EI_CLASS]; elf->ed_encode = image[EI_DATA]; if ((elf->ed_version = image[EI_VERSION]) == 0) elf->ed_version = 1; elf->ed_identsz = EI_NIDENT; elf->ed_activ = 1; elf = _elf_config(elf); return (elf); } /* * The following is a private interface between the linkers (ld & ld.so.1) * and libelf. * * elf_begin(0, ELF_C_IMAGE, ref) * Return a new elf_descriptor which uses the memory image from * ref as the base image of the elf file. Before this elf_begin() * is called an elf_update(ref, ELF_C_WRIMAGE) must have been * done to the ref elf descriptor. * The ELF_C_IMAGE is unique in that modificatino of the Elf structure * is illegal (no elf_new*()) but you can modify the actual * data image of the file in question. * * When you are done processing this file you can then perform a * elf_end() on it. * * NOTE: if an elf_update(ref, ELF_C_WRITE) is done on the ref Elf * descriptor then the memory image that the ELF_C_IMAGE * is using has been discarded. The proper calling convention * for this is as follows: * * elf1 = elf_begin(fd, ELF_C_WRITE, 0); * ... * elf_update(elf1, ELF_C_WRIMAGE); build memory image * elf2 = elf_begin(0, ELF_C_IMAGE, elf1); * ... * elf_end(elf2); * elf_updage(elf1, ELF_C_WRITE); flush memory image to disk * elf_end(elf1); * * * elf_begin(0, ELF_C_IMAGE, 0); * returns a pointer to an elf descriptor as if it were opened * with ELF_C_WRITE except that it has no file descriptor and it * will not create a file. It's to be used with the command: * * elf_update(elf, ELF_C_WRIMAGE) * * which will build a memory image instead of a file image. * The memory image is allocated via dynamic memory (malloc) and * can be free with a subsequent call to * * elf_update(elf, ELF_C_WRITE) * * NOTE: that if elf_end(elf) is called it will not free the * memory image if it is still allocated. It is then * the callers responsiblity to free it via a call * to free(). * * Here is a potential calling sequence for this interface: * * elf1 = elf_begin(0, ELF_C_IMAGE, 0); * ... * elf_update(elf1, ELF_C_WRIMAGE); build memory image * elf2 = elf_begin(0, ELF_C_IMAGE, elf1); * ... * image_ptr = elf32_getehdr(elf2); get pointer to image * elf_end(elf2); * elf_end(elf1); * ... * use image * ... * free(image_ptr); */ Elf * elf_begin(int fd, Elf_Cmd cmd, Elf *ref) { register Elf *elf; unsigned work; unsigned flags = 0; ELFACCESSDATA(work, _elf_work) if (work == EV_NONE) /* version() not called yet */ { _elf_seterr(ESEQ_VER, 0); return (0); } switch (cmd) { default: _elf_seterr(EREQ_BEGIN, 0); return (0); case ELF_C_NULL: return (0); case ELF_C_IMAGE: if (ref) { char *image; size_t imagesz; ELFRLOCK(ref); if ((image = ref->ed_wrimage) == 0) { _elf_seterr(EREQ_NOWRIMAGE, 0); ELFUNLOCK(ref); return (0); } imagesz = ref->ed_wrimagesz; ELFUNLOCK(ref); return (elf_memory(image, imagesz)); } /* FALLTHROUGH */ case ELF_C_WRITE: if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) { _elf_seterr(EMEM_ELF, errno); return (0); } ELFRWLOCKINIT(&elf->ed_rwlock); elf->ed_fd = fd; elf->ed_activ = 1; elf->ed_myflags |= EDF_WRITE; if (cmd == ELF_C_IMAGE) elf->ed_myflags |= EDF_WRALLOC; return (elf); case ELF_C_RDWR: flags = EDF_WRITE | EDF_READ; break; case ELF_C_READ: flags = EDF_READ; break; } /* * A null ref asks for a new file * Non-null ref bumps the activation count * or gets next archive member */ if (ref == 0) { if ((elf = _elf_regular(fd, flags)) == 0) return (0); } else { ELFWLOCK(ref); if ((ref->ed_myflags & flags) != flags) { _elf_seterr(EREQ_RDWR, 0); ELFUNLOCK(ref); return (0); } /* * new activation ? */ if (ref->ed_kind != ELF_K_AR) { ++ref->ed_activ; ELFUNLOCK(ref); return (ref); } if ((elf = _elf_member(fd, ref, flags)) == 0) { ELFUNLOCK(ref); return (0); } ELFUNLOCK(ref); } elf->ed_activ = 1; elf = _elf_config(elf); return (elf); } /* * 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 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* Copyright (c) 1987, 1988 Microsoft Corporation */ /* All Rights Reserved */ #include #include #include "decl.h" #include "msg.h" /* * Routines for generating a checksum for an elf image. Typically used to create * a DT_CHECKSUM entry. This checksum is intended to remain constant after * operations such as strip(1)/mcs(1), thus only allocatable sections are * processed, and of those, any that might be modified by these external * commands are skipped. */ #define MSW(l) (((l) >> 16) & 0x0000ffffL) #define LSW(l) ((l) & 0x0000ffffL) /* * update and epilogue sum functions (stolen from libcmd) */ static long sumupd(long sum, char *cp, unsigned long cnt) { if ((cp == 0) || (cnt == 0)) return (sum); while (cnt--) sum += *cp++ & 0x00ff; return (sum); } static long sumepi(long sum) { long _sum; _sum = LSW(sum) + MSW(sum); return ((ushort_t)(LSW(_sum) + MSW(_sum))); } /* * This module is compiled twice, the second time having * -D_ELF64 defined. The following set of macros represent * the differences between the two compilations. Be * careful *not* to add any class dependent code (anything * that has elf32 or elf64 in the name) to this code * without hiding it behind a switchable macro like these. */ #if defined(_ELF64) #define elf_checksum elf64_checksum #define Elf_Ehdr Elf64_Ehdr #define Elf_Shdr Elf64_Shdr #define getehdr elf64_getehdr #define getshdr elf64_getshdr #else /* else ELF32 */ #define elf_checksum elf32_checksum #define Elf_Ehdr Elf32_Ehdr #define Elf_Shdr Elf32_Shdr #define getehdr elf32_getehdr #define getshdr elf32_getshdr #endif /* ELF64 */ long elf_checksum(Elf * elf) { long sum = 0; Elf_Ehdr * ehdr; Elf_Shdr * shdr; Elf_Scn * scn; Elf_Data * data, * (* getdata)(Elf_Scn *, Elf_Data *); size_t shnum; if ((ehdr = getehdr(elf)) == 0) return (0); /* * Determine the data information to retrieve. When called from ld() * we're processing an ELF_C_IMAGE (memory) image and thus need to use * elf_getdata(), as there is not yet a file image (or raw data) backing * this. When called from utilities like elfdump(1) we're processing a * file image and thus using the elf_rawdata() allows the same byte * stream to be processed from different architectures - presently this * is irrelevant, as the checksum simply sums the data bytes, their * order doesn't matter. But being uncooked is slightly less overhead. * * If the file is writable, the raw data will not reflect any * changes made in the process, so the uncooked version is only * for readonly files. */ if ((elf->ed_myflags & (EDF_MEMORY | EDF_WRITE)) != 0) getdata = elf_getdata; else getdata = elf_rawdata; for (shnum = 1; shnum < ehdr->e_shnum; shnum++) { if ((scn = elf_getscn(elf, shnum)) == 0) return (0); if ((shdr = getshdr(scn)) == 0) return (0); /* Exclude strippable sections */ if (!(shdr->sh_flags & SHF_ALLOC)) continue; /* * Exclude allocable sections that can change: * - The .dynsym section can contain section symbols * that strip might remove. * - The .dynamic section is modified by the setting of * this checksum value. * - The .SUNW_dof section uses ftok(3C), which returns * different values, to define a key for the * objects in that section. */ if ((shdr->sh_type == SHT_DYNSYM) || (shdr->sh_type == SHT_DYNAMIC) || (shdr->sh_type == SHT_SUNW_dof)) continue; data = 0; while ((data = (*getdata)(scn, data)) != 0) sum = sumupd(sum, data->d_buf, data->d_size); } return (sumepi(sum)); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * This stuff used to live in cook.c, but was moved out to * facilitate dual (Elf32 and Elf64) compilation. See block * comment in cook.c for more info. */ #include #include #include #include #include #include "decl.h" #include "member.h" #include "msg.h" /* * This module is compiled twice, the second time having * -D_ELF64 defined. The following set of macros, along * with machelf.h, represent the differences between the * two compilations. Be careful *not* to add any class- * dependent code (anything that has elf32 or elf64 in the * name) to this code without hiding it behind a switch- * able macro like these. */ #if defined(_ELF64) #define Snode Snode64 #define ELFCLASS ELFCLASS64 #define ElfField Elf64 #define _elf_snode_init _elf64_snode_init #define _elf_prepscan _elf64_prepscan #define _elf_cookscn _elf64_cookscn #define _elf_mtype _elf64_mtype #define _elf_msize _elf64_msize #define elf_fsize elf64_fsize #define _elf_snode _elf64_snode #define _elf_ehdr _elf64_ehdr #define elf_xlatetom elf64_xlatetom #define _elf_phdr _elf64_phdr #define _elf_shdr _elf64_shdr #define _elf_prepscn _elf64_prepscn #else /* Elf32 */ #define Snode Snode32 #define ELFCLASS ELFCLASS32 #define ElfField Elf32 #define _elf_snode_init _elf32_snode_init #define _elf_prepscan _elf32_prepscan #define _elf_cookscn _elf32_cookscn #define _elf_mtype _elf32_mtype #define _elf_msize _elf32_msize #define elf_fsize elf32_fsize #define _elf_snode _elf32_snode #define _elf_ehdr _elf32_ehdr #define elf_xlatetom elf32_xlatetom #define _elf_phdr _elf32_phdr #define _elf_shdr _elf32_shdr #define _elf_prepscn _elf32_prepscn #endif /* _ELF64 */ static Okay _elf_prepscn(Elf *elf, size_t cnt) { Elf_Scn * s; Elf_Scn * end; if (cnt == 0) return (OK_YES); if ((s = malloc(cnt * sizeof (Elf_Scn))) == 0) { _elf_seterr(EMEM_SCN, errno); return (OK_NO); } elf->ed_scntabsz = cnt; end = s + cnt; elf->ed_hdscn = s; do { *s = _elf_snode_init.sb_scn; s->s_elf = elf; s->s_next = s + 1; s->s_index = s - elf->ed_hdscn; s->s_shdr = (Shdr*)s->s_elf->ed_shdr + s->s_index; ELFMUTEXINIT(&s->s_mutex); /* * Section has not yet been cooked! * * We don't cook a section until it's data is actually * referenced. */ s->s_myflags = 0; } while (++s < end); elf->ed_tlscn = --s; s->s_next = 0; /* * Section index SHN_UNDEF (0) does not and cannot * have a data buffer. Fix it here. Also mark the * initial section as being allocated for the block */ s = elf->ed_hdscn; s->s_myflags = SF_ALLOC; s->s_hdnode = 0; s->s_tlnode = 0; return (OK_YES); } Okay _elf_cookscn(Elf_Scn * s) { Elf * elf; Shdr * sh; register Dnode * d = &s->s_dnode; size_t fsz, msz; unsigned work; s->s_hdnode = s->s_tlnode = d; s->s_err = 0; s->s_shflags = 0; s->s_uflags = 0; /* * Prepare d_data for inspection, but don't actually * translate data until needed. Leave the READY * flag off. NOBITS sections see zero size. */ elf = s->s_elf; sh = s->s_shdr; d->db_scn = s; d->db_off = sh->sh_offset; d->db_data.d_align = sh->sh_addralign; d->db_data.d_version = elf->ed_version; ELFACCESSDATA(work, _elf_work) d->db_data.d_type = _elf_mtype(elf, sh->sh_type, work); d->db_data.d_buf = 0; d->db_data.d_off = 0; fsz = elf_fsize(d->db_data.d_type, 1, elf->ed_version); msz = _elf_msize(d->db_data.d_type, elf->ed_version); d->db_data.d_size = MAX(sh->sh_size, (sh->sh_size / fsz) * msz); d->db_shsz = sh->sh_size; d->db_raw = 0; d->db_buf = 0; d->db_uflags = 0; d->db_myflags = 0; d->db_next = 0; if (sh->sh_type != SHT_NOBITS) d->db_fsz = sh->sh_size; else d->db_fsz = 0; s->s_myflags |= SF_READY; return (OK_YES); } Snode * _elf_snode() { register Snode *s; if ((s = malloc(sizeof (Snode))) == 0) { _elf_seterr(EMEM_SNODE, errno); return (0); } *s = _elf_snode_init; ELFMUTEXINIT(&s->sb_scn.s_mutex); s->sb_scn.s_myflags = SF_ALLOC | SF_READY; s->sb_scn.s_shdr = &s->sb_shdr; return (s); } int _elf_ehdr(Elf * elf, int inplace) { register size_t fsz; /* field size */ Elf_Data dst, src; fsz = elf_fsize(ELF_T_EHDR, 1, elf->ed_version); if (fsz > elf->ed_fsz) { _elf_seterr(EFMT_EHDRSZ, 0); return (-1); } if (inplace && (fsz >= sizeof (Ehdr))) { /* * The translated Ehdr will fit over the original Ehdr. */ /* LINTED */ elf->ed_ehdr = (Ehdr *)elf->ed_ident; elf->ed_status = ES_COOKED; } else { elf->ed_ehdr = malloc(sizeof (Ehdr)); if (elf->ed_ehdr == 0) { _elf_seterr(EMEM_EHDR, errno); return (-1); } elf->ed_myflags |= EDF_EHALLOC; } /* * Memory size >= fsz, because otherwise the memory version * loses information and cannot accurately implement the * file. */ src.d_buf = (Elf_Void *)elf->ed_ident; src.d_type = ELF_T_EHDR; src.d_size = fsz; src.d_version = elf->ed_version; dst.d_buf = (Elf_Void *)elf->ed_ehdr; dst.d_size = sizeof (Ehdr); dst.d_version = EV_CURRENT; if ((_elf_vm(elf, (size_t)0, fsz) != OK_YES) || (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) { if (elf->ed_myflags & EDF_EHALLOC) { elf->ed_myflags &= ~EDF_EHALLOC; free(elf->ed_ehdr); } elf->ed_ehdr = 0; return (-1); } if (((Ehdr*)elf->ed_ehdr)->e_ident[EI_CLASS] != ELFCLASS) { _elf_seterr(EREQ_CLASS, 0); if (elf->ed_myflags & EDF_EHALLOC) { elf->ed_myflags &= ~EDF_EHALLOC; free(elf->ed_ehdr); } elf->ed_ehdr = 0; return (-1); } if (((Ehdr*)elf->ed_ehdr)->e_version != elf->ed_version) { _elf_seterr(EFMT_VER2, 0); if (elf->ed_myflags & EDF_EHALLOC) { elf->ed_myflags &= ~EDF_EHALLOC; free(elf->ed_ehdr); } elf->ed_ehdr = 0; return (-1); } return (0); } int _elf_phdr(Elf * elf, int inplace) { register size_t fsz, msz; Elf_Data dst, src; Ehdr * eh = elf->ed_ehdr; /* must be present */ unsigned work; if (eh->e_phnum == 0) return (0); fsz = elf_fsize(ELF_T_PHDR, 1, elf->ed_version); if (eh->e_phentsize != fsz) { _elf_seterr(EFMT_PHDRSZ, 0); return (-1); } fsz *= eh->e_phnum; ELFACCESSDATA(work, _elf_work) msz = _elf_msize(ELF_T_PHDR, work) * eh->e_phnum; if ((eh->e_phoff == 0) || (elf->ed_fsz <= eh->e_phoff) || (elf->ed_fsz - eh->e_phoff < fsz)) { _elf_seterr(EFMT_PHTAB, 0); return (-1); } if (inplace && fsz >= msz && eh->e_phoff % sizeof (ElfField) == 0) { elf->ed_phdr = (Elf_Void *)(elf->ed_ident + eh->e_phoff); elf->ed_status = ES_COOKED; } else { if ((elf->ed_phdr = malloc(msz)) == 0) { _elf_seterr(EMEM_PHDR, errno); return (-1); } elf->ed_myflags |= EDF_PHALLOC; } src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_phoff); src.d_type = ELF_T_PHDR; src.d_size = fsz; src.d_version = elf->ed_version; dst.d_buf = elf->ed_phdr; dst.d_size = msz; dst.d_version = work; if ((_elf_vm(elf, (size_t)eh->e_phoff, fsz) != OK_YES) || (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) { if (elf->ed_myflags & EDF_PHALLOC) { elf->ed_myflags &= ~EDF_PHALLOC; free(elf->ed_phdr); } elf->ed_phdr = 0; return (-1); } elf->ed_phdrsz = msz; return (0); } int _elf_shdr(Elf * elf, int inplace) { register size_t fsz, msz; size_t scncnt; Elf_Data dst, src; register Ehdr *eh = elf->ed_ehdr; /* must be present */ if ((eh->e_shnum == 0) && (eh->e_shoff == 0)) return (0); fsz = elf_fsize(ELF_T_SHDR, 1, elf->ed_version); if (eh->e_shentsize != fsz) { _elf_seterr(EFMT_SHDRSZ, 0); return (-1); } /* * If we are dealing with a file with 'extended section * indexes' - then we need to load the first section * header. The actual section count is stored in * Shdr[0].sh_size. */ if ((scncnt = eh->e_shnum) == 0) { Shdr sh; if ((eh->e_shoff == 0) || (elf->ed_fsz <= eh->e_shoff) || (elf->ed_fsz - eh->e_shoff < fsz)) { _elf_seterr(EFMT_SHTAB, 0); return (-1); } src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff); src.d_type = ELF_T_SHDR; src.d_size = fsz; src.d_version = elf->ed_version; dst.d_buf = (Elf_Void *)&sh; dst.d_size = sizeof (Shdr); dst.d_version = EV_CURRENT; if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) || (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) { return (-1); } scncnt = sh.sh_size; } fsz *= scncnt; msz = scncnt * sizeof (Shdr); if ((eh->e_shoff == 0) || (elf->ed_fsz <= eh->e_shoff) || (elf->ed_fsz - eh->e_shoff < fsz)) { _elf_seterr(EFMT_SHTAB, 0); return (-1); } if (inplace && (fsz >= msz) && ((eh->e_shoff % sizeof (ElfField)) == 0)) { /* LINTED */ elf->ed_shdr = (Shdr *)(elf->ed_ident + eh->e_shoff); elf->ed_status = ES_COOKED; } else { if ((elf->ed_shdr = malloc(msz)) == 0) { _elf_seterr(EMEM_SHDR, errno); return (-1); } elf->ed_myflags |= EDF_SHALLOC; } src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff); src.d_type = ELF_T_SHDR; src.d_size = fsz; src.d_version = elf->ed_version; dst.d_buf = (Elf_Void *)elf->ed_shdr; dst.d_size = msz; dst.d_version = EV_CURRENT; if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) || (elf_xlatetom(&dst, &src, elf->ed_encode) == 0) || (_elf_prepscn(elf, scncnt) != OK_YES)) { if (elf->ed_myflags & EDF_SHALLOC) { elf->ed_myflags &= ~EDF_SHALLOC; free(elf->ed_shdr); } elf->ed_shdr = 0; return (-1); } return (0); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" #include "msg.h" int elf_cntl(Elf * elf, Elf_Cmd cmd) { if (elf == 0) return (0); ELFWLOCK(elf); switch (cmd) { case ELF_C_FDREAD: { int j = 0; if ((elf->ed_myflags & EDF_READ) == 0) { _elf_seterr(EREQ_CNTLWRT, 0); ELFUNLOCK(elf); return (-1); } if ((elf->ed_status != ES_FROZEN) && ((_elf_cook(elf) != OK_YES) || (_elf_vm(elf, (size_t)0, elf->ed_fsz) != OK_YES))) j = -1; elf->ed_fd = -1; ELFUNLOCK(elf); return (j); } case ELF_C_FDDONE: if ((elf->ed_myflags & EDF_READ) == 0) { _elf_seterr(EREQ_CNTLWRT, 0); ELFUNLOCK(elf); return (-1); } elf->ed_fd = -1; ELFUNLOCK(elf); return (0); default: _elf_seterr(EREQ_CNTLCMD, 0); break; } ELFUNLOCK(elf); 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #include #include "decl.h" #include "member.h" #include "msg.h" #include /* * Cook the input file. * These functions take the input file buffer and extract * the Ehdr, Phdr table, and the Shdr table. They keep track * of the buffer status as "fresh," "cooked," or "frozen." * * fresh The file buffer is in its original state and * nothing has yet referenced it. * * cooked The application asked for translated data first * and caused the library to return a pointer into * the file buffer. After this happens, all "raw" * operations must go back to the disk. * * frozen The application first did a "raw" operation that * prohibits reusing the file buffer. This effectively * freezes the buffer, and all "normal" operations must * duplicate their data. * * For archive handling, these functions conspire to align the * file buffer to the host memory format. Archive members * are guaranteed only even byte alignment, but the file uses * objects at least 4 bytes long. If an archive member is about * to be cooked and is not aligned in memory, these functions * "slide" the buffer up into the archive member header. * This sliding never occurs for frozen files. * * Some processors might not need sliding at all, if they have * no alignment constraints on memory references. This code * ignores that possibility for two reasons. First, even machines * that have no constraints usually handle aligned objects faster * than unaligned. Forcing alignment here probably leads to better * performance. Second, there's no way to test at run time whether * alignment is required or not. The safe thing is to align in * all cases. * * This sliding relies on the archive header being disposable. * Only archive members that are object files ever slide. * They're also the only ones that ever need to. Archives never * freeze to make headers disposable. Any program peculiar enough * to want a frozen archive pays the penalty. * * The library itself inspects the Ehdr and the Shdr table * from the file. Consequently, it converts the file's data * to EV_CURRENT version, not the working version. This is * transparent to the user. The library never looks at the * Phdr table; so that's kept in the working version. */ Dnode * _elf_dnode() { register Dnode *d; if ((d = (Dnode *)malloc(sizeof (Dnode))) == 0) { _elf_seterr(EMEM_DNODE, errno); return (0); } *d = _elf_dnode_init; d->db_myflags = DBF_ALLOC; return (d); } int _elf_slide(Elf * elf) { Elf *par = elf->ed_parent; size_t sz, szof; register char *dst; register char *src = elf->ed_ident; if (par == 0 || par->ed_kind != ELF_K_AR) return (0); /* * This code relies on other code to ensure * the ar_hdr is big enough to move into. */ if (elf->ed_ident[EI_CLASS] == ELFCLASS64) szof = sizeof (Elf64); else szof = sizeof (Elf32); if ((sz = (size_t)(src - (char *)elf->ed_image) % szof) == 0) return (0); dst = src - sz; elf->ed_ident -= sz; elf->ed_memoff -= sz; elf->ed_armem->m_slide = sz; if (_elf_vm(par, elf->ed_memoff, sz + elf->ed_fsz) != OK_YES) return (-1); /* * If the archive has been mmaped in, and we're going to slide it, * and it wasn't open for write in the first place, and we've never * done the mprotect() operation before, then do it now. */ if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) && ((elf->ed_myflags & EDF_MPROTECT) == 0)) { if (mprotect((char *)elf->ed_image, elf->ed_imagesz, PROT_READ|PROT_WRITE) == -1) { _elf_seterr(EIO_VM, errno); return (-1); } elf->ed_myflags |= EDF_MPROTECT; } if (memmove((void *)dst, (const void *)src, elf->ed_fsz) != (void *)dst) return (-1); else return (0); } Okay _elf_cook(Elf * elf) { register int inplace = 1; if (elf->ed_kind != ELF_K_ELF) return (OK_YES); if ((elf->ed_status == ES_COOKED) || ((elf->ed_myflags & EDF_READ) == 0)) return (OK_YES); /* * Here's where the unaligned archive member gets fixed. */ if (elf->ed_status == ES_FRESH && _elf_slide(elf) != 0) return (OK_NO); if (elf->ed_status == ES_FROZEN) inplace = 0; /* * This is the first time we've actually looked at the file * contents. We need to know whether or not this is an * Elf32 or Elf64 file before we can decode the header. * But it's the header that tells us which is which. * * Resolve the chicken-and-egg problem by peeking at the * 'class' byte in the ident string. */ if (elf->ed_ident[EI_CLASS] == ELFCLASS32) { if (_elf32_ehdr(elf, inplace) != 0) return (OK_NO); if (_elf32_phdr(elf, inplace) != 0) goto xehdr; if (_elf32_shdr(elf, inplace) != 0) goto xphdr; elf->ed_class = ELFCLASS32; } else if (elf->ed_ident[EI_CLASS] == ELFCLASS64) { if (_elf64_ehdr(elf, inplace) != 0) return (OK_NO); if (_elf64_phdr(elf, inplace) != 0) goto xehdr; if (_elf64_shdr(elf, inplace) != 0) goto xphdr; elf->ed_class = ELFCLASS64; } else return (OK_NO); return (OK_YES); xphdr: if (elf->ed_myflags & EDF_PHALLOC) { elf->ed_myflags &= ~EDF_PHALLOC; free(elf->ed_phdr); } elf->ed_phdr = 0; xehdr: if (elf->ed_myflags & EDF_EHALLOC) { elf->ed_myflags &= ~EDF_EHALLOC; free(elf->ed_ehdr); } elf->ed_ehdr = 0; return (OK_NO); } Okay _elf_cookscn(Elf_Scn * s) { Elf * elf = s->s_elf; if (elf->ed_class == ELFCLASS32) { return (_elf32_cookscn(s)); } else if (elf->ed_class == ELFCLASS64) { return (_elf64_cookscn(s)); } _elf_seterr(EREQ_CLASS, 0); return (OK_NO); } /* * 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 (c) 1988 AT&T */ /* All Rights Reserved */ #include #include "decl.h" /* * Global data * _elf_byte Fill byte for file padding. See elf_fill(). * _elf32_ehdr_init Clean copy for to initialize new headers. * _elf64_ehdr_init Clean copy for to initialize new class-64 headers. * _elf_encode Host/internal data encoding. If the host has * an encoding that matches one known for the * ELF format, this changes. An machine with an * unknown encoding keeps ELFDATANONE and forces * conversion for host/target translation. * _elf_work Working version given to the lib by application. * See elf_version(). * _elf_globals_mutex mutex to protect access to all global data items. * _elf_execfill_func Fill function for file padding of SHF_EXECINSTR * sections. See _elf_execfill(). */ /* * __libc_threaded is a private symbol exported from libc in Solaris 10. * It is used to tell if we are running in a threaded world or not. * Between Solaris 2.5 and Solaris 9, this was named __threaded. * The name had to be changed because the Sun Workshop 6 update 1 * compilation system used it to mean "we are linked with libthread" * rather than its true meaning in Solaris 10, "more than one thread exists". */ #pragma weak __libc_threaded extern int __libc_threaded; int _elf_byte = 0; const Elf32_Ehdr _elf32_ehdr_init = { 0 }; const Elf64_Ehdr _elf64_ehdr_init = { 0 }; unsigned _elf_encode = ELFDATANONE; _elf_execfill_func_t *_elf_execfill_func = NULL; const Snode32 _elf32_snode_init = { 0 }; const Snode64 _elf64_snode_init = { 0 }; const Dnode _elf_dnode_init = { 0 }; unsigned _elf_work = EV_NONE; mutex_t _elf_globals_mutex = DEFAULTMUTEX; int *_elf_libc_threaded = &__libc_threaded; /* * 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) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _DECL_H #define _DECL_H #include #include <_libelf.h> #include #include #ifdef __cplusplus extern "C" { #endif typedef struct Member Member; typedef struct Memlist Memlist; typedef struct Memident Memident; typedef struct Dnode Dnode; typedef struct Snode32 Snode32; typedef struct Snode64 Snode64; /* * Data alignment * An elf file is defined to have its structures aligned on * appropriate boundaries. The following type lets the * library test whether the file's alignment meets its own * constraints in memory. This assumes every machine uses * an alignment that is no greater than an object's size. * The pointer isn't relevant for the file, but the code uses * it to get memory alignment. ANSI C void * holds any pointer, * making it appropriate here. */ typedef union { Elf32_Word w; Elf32_Addr a; Elf32_Off o; } Elf32; typedef union { Elf64_Xword x; Elf64_Word w; Elf64_Addr a; Elf64_Off o; Elf_Void *p; } Elf64; /* * Memory allocation * Structures are obtained several ways: file mapping, * malloc(), from the user. A status bit in the structures * tells whether an object was obtained with malloc() and * therefore should be released with free(). The bits * named ...ALLOC indicate this. */ /* * Data descriptor * db_data must be first in the Dnode structure, because * &db_data must == &Dnode. * * db_buf is a pointer to an allocated buffer. The same value * goes into db_data.d_buf originally, but the user can touch * it. If the data buffer is not to be freed, db_buf is null. * * When "reading" an input file's buffer, the data are left * alone until needed. When they've been converted to internal * form, the READY flag is set. * * db_raw points to a parallel raw buffer. Raw buffers * have null db_raw. */ struct Dnode { Elf_Data db_data; Elf_Scn *db_scn; /* section parent */ Dnode *db_next; Dnode *db_raw; /* raw data */ off_t db_off; /* orig file offset, 0 o/w */ size_t db_fsz; /* orig file size, 0 o/w */ size_t db_shsz; /* orig shdr size, 0 o/w */ size_t db_osz; /* output size for update */ Elf_Void *db_buf; /* allocated data buffer */ unsigned db_uflags; /* user flags: ELF_F_... */ unsigned db_myflags; /* internal flags: DBF_... */ Elf64_Off db_xoff; /* extended offset for 32-bit Elf64 */ }; #define DBF_ALLOC 0x1 /* applies to Dnode itself */ #define DBF_READY 0x2 /* buffer ready */ /* * Section descriptor * These are sometimes allocated in a block. If the SF_ALLOC * bit is set in the flags, the Scn address may be passed to free. * The caller must first follow the s_next list to the next freeable * node, because free can clobber the s_next value in the block. */ struct Elf_Scn { mutex_t s_mutex; Elf_Scn *s_next; /* next section */ Elf *s_elf; /* parent file */ Dnode *s_hdnode; /* head Dnode */ Dnode *s_tlnode; /* tail Dnode */ Elf_Void *s_shdr; /* Elf32 or Elf64 scn header */ size_t s_index; /* section index */ int s_err; /* for delaying data error */ unsigned s_shflags; /* user shdr flags */ unsigned s_uflags; /* user flags */ unsigned s_myflags; /* SF_... */ Dnode s_dnode; /* every scn needs one */ }; /* * Designates whether or not we are in a threaded_app. */ extern int *_elf_libc_threaded; #define elf_threaded (_elf_libc_threaded && *_elf_libc_threaded) #define SCNLOCK(x) \ if (elf_threaded) \ (void) mutex_lock(&((Elf_Scn *)x)->s_mutex); #define SCNUNLOCK(x) \ if (elf_threaded) \ (void) mutex_unlock(&((Elf_Scn *)x)->s_mutex); #define UPGRADELOCKS(e, s)\ if (elf_threaded) { \ (void) mutex_unlock(&((Elf_Scn *)s)->s_mutex); \ (void) rw_unlock(&((Elf *)e)->ed_rwlock); \ (void) rw_wrlock(&((Elf *)e)->ed_rwlock); \ } #define DOWNGRADELOCKS(e, s)\ if (elf_threaded) { \ (void) rw_unlock(&((Elf *)e)->ed_rwlock); \ (void) rw_rdlock(&((Elf *)e)->ed_rwlock); \ (void) mutex_lock(&((Elf_Scn *)s)->s_mutex); \ } #define READLOCKS(e, s) \ if (elf_threaded) { \ (void) rw_rdlock(&((Elf *)e)->ed_rwlock); \ (void) mutex_lock(&((Elf_Scn *)s)->s_mutex); \ } #define READUNLOCKS(e, s) \ if (elf_threaded) { \ (void) mutex_unlock(&((Elf_Scn *)s)->s_mutex); \ (void) rw_unlock(&((Elf *)e)->ed_rwlock); \ } #define SF_ALLOC 0x1 /* applies to Scn */ #define SF_READY 0x2 /* has section been cooked */ struct Snode32 { Elf_Scn sb_scn; /* must be first */ Elf32_Shdr sb_shdr; }; struct Snode64 { Elf_Scn sb_scn; /* must be first */ Elf64_Shdr sb_shdr; }; /* * A file's status controls how the library can use file data. * This is important to keep "raw" operations and "cooked" * operations from interfering with each other. * * A file's status is "fresh" until something touches it. * If the first thing is a raw operation, we freeze the data * and force all cooking operations to make a copy. If the * first operation cooks, raw operations use the file system. */ typedef enum { ES_FRESH = 0, /* unchanged */ ES_COOKED, /* translated */ ES_FROZEN /* raw, can't be translated */ } Status; /* * Elf descriptor * The major handle between user code and the library. * * Descriptors can have parents: archive members reference * the archive itself. Relevant "offsets:" * * ed_baseoff The file offset, relative to zero, to the first * byte in the file. For all files, this gives * the lseek(fd, ed_baseoff, 0) value. * * ed_memoff The offset from the beginning of the nesting file * to the bytes of a member. For an archive member, * this is the offset from the beginning of the * archive to the member bytes (not the hdr). If an * archive member slides, memoff changes. * * ed_siboff Similar to ed_memoff, this gives the offset from * the beginning of the nesting file to the following * sibling's header (not the sibling's bytes). This * value is necessary, because of archive sliding. * * ed_nextoff For an archive, this gives the offset of the next * member to process on elf_begin. That is, * (ed_ident + ed_nextoff) gives pointer to member hdr. * * Keeping these absolute and relative offsets allows nesting of * files, including archives within archives, etc. The only current * nesting file is archive, but others might be supported. * * ed_image This is a pointer to the base memory image holding * the file. Library code assumes the image is aligned * to a boundary appropriate for any object. This must * be true, because we get an image only from malloc * or mmap, both of which guarantee alignment. */ struct Elf { rwlock_t ed_rwlock; Elf *ed_parent; /* archive parent */ int ed_activ; /* activation count */ int ed_fd; /* file descriptor */ Status ed_status; /* file's memory status */ off_t ed_baseoff; /* base file offset, zero based */ size_t ed_memoff; /* offset within archive */ size_t ed_siboff; /* sibling offset with archive */ size_t ed_nextoff; /* next archive member hdr offset */ char *ed_image; /* pointer to file image */ size_t ed_imagesz; /* # bytes in ed_image */ char *ed_wrimage; /* pointer to output image */ size_t ed_wrimagesz; /* # bytes in ed_wrimagesz */ char *ed_ident; /* file start, getident() bytes */ size_t ed_identsz; /* # bytes for getident() */ char *ed_raw; /* raw file ptr */ size_t ed_fsz; /* file size */ unsigned *ed_vm; /* virtual memory map */ size_t ed_vmsz; /* # regions in vm */ unsigned ed_encode; /* data encoding */ unsigned ed_version; /* file version */ int ed_class; /* file class */ Elf_Kind ed_kind; /* file type */ Elf_Void *ed_ehdr; /* Elf{32,64}_Ehdr elf header */ Elf_Void *ed_phdr; /* Elf{32,64}_Phdr phdr table */ size_t ed_phdrsz; /* sizeof phdr table */ Elf_Void *ed_shdr; /* Elf{32,64}_Shdr shdr table */ Elf_Scn *ed_hdscn; /* head scn */ Elf_Scn *ed_tlscn; /* tail scn */ size_t ed_scntabsz; /* number sects. alloc. in table */ Memlist *ed_memlist; /* list of archive member nodes */ Member *ed_armem; /* archive member header */ Elf_Void *ed_arsym; /* archive symbol table */ size_t ed_arsymsz; /* archive symbol table size */ size_t ed_arsymoff; /* archive symbol table hdr offset */ char *ed_arstr; /* archive string table */ size_t ed_arstrsz; /* archive string table size */ size_t ed_arstroff; /* archive string table hdr offset */ unsigned ed_myflags; /* EDF_... */ unsigned ed_ehflags; /* ehdr flags */ unsigned ed_phflags; /* phdr flags */ unsigned ed_uflags; /* elf descriptor flags */ }; #define ELFRLOCK(e) \ if (elf_threaded) \ (void) rw_rdlock(&((Elf *)e)->ed_rwlock); #define ELFWLOCK(e) \ if (elf_threaded) \ (void) rw_wrlock(&((Elf *)e)->ed_rwlock); #define ELFUNLOCK(e) \ if (elf_threaded) \ (void) rw_unlock(&((Elf *)e)->ed_rwlock); #define EDF_ASALLOC 0x1 /* applies to ed_arsym */ #define EDF_EHALLOC 0x2 /* applies to ed_ehdr */ #define EDF_PHALLOC 0x4 /* applies to ed_phdr */ #define EDF_SHALLOC 0x8 /* applies to ed_shdr */ #define EDF_COFFAOUT 0x10 /* original file was coff a.out */ #define EDF_RAWALLOC 0x20 /* applies to ed_raw */ #define EDF_READ 0x40 /* file can be read */ #define EDF_WRITE 0x80 /* file can be written */ #define EDF_MEMORY 0x100 /* file opened via elf_memory() */ #define EDF_ASTRALLOC 0x200 /* applies to ed_arstr */ #define EDF_MPROTECT 0x400 /* applies to slideable archives */ #define EDF_IMALLOC 0x800 /* wrimage dynamically allocated */ #define EDF_WRALLOC 0x1000 /* wrimage is to by dyn allocated */ #define EDF_ARSYM64 0x2000 /* archive symbol table is 64-bit format */ typedef enum { OK_YES = 0, OK_NO = ~0 } Okay; #define _(a) a /* * Max size for an Elf error message string */ #define MAXELFERR 1024 /* * General thread management macros */ #define ELFACCESSDATA(a, b) \ if (elf_threaded) { \ (void) mutex_lock(&_elf_globals_mutex); \ a = b; \ (void) mutex_unlock(&_elf_globals_mutex); \ } else \ a = b; #define ELFRWLOCKINIT(lock) \ if (elf_threaded) { \ (void) rwlock_init((lock), USYNC_THREAD, 0); \ } #define ELFMUTEXINIT(lock) \ if (elf_threaded) { \ (void) mutex_init(lock, USYNC_THREAD, 0); \ } extern Member *_elf_armem(Elf *, char *, size_t); extern void _elf_arinit(Elf *); extern Okay _elf_cook(Elf *); extern Okay _elf_cookscn(Elf_Scn * s); extern Okay _elf32_cookscn(Elf_Scn * s); extern Okay _elf64_cookscn(Elf_Scn * s); extern Dnode *_elf_dnode(void); extern Elf_Data *_elf_locked_getdata(Elf_Scn *, Elf_Data *); extern size_t _elf32_entsz(Elf *elf, Elf32_Word, unsigned); extern size_t _elf64_entsz(Elf *elf, Elf64_Word, unsigned); extern Okay _elf_inmap(Elf *); extern char *_elf_outmap(int, size_t, unsigned *); extern size_t _elf_outsync(int, char *, size_t, unsigned); extern size_t _elf32_msize(Elf_Type, unsigned); extern size_t _elf64_msize(Elf_Type, unsigned); extern Elf_Type _elf32_mtype(Elf *, Elf32_Word, unsigned); extern Elf_Type _elf64_mtype(Elf *, Elf64_Word, unsigned); extern char *_elf_read(int, off_t, size_t); extern Snode32 *_elf32_snode(void); extern Snode64 *_elf64_snode(void); extern void _elf_unmap(char *, size_t); extern Okay _elf_vm(Elf *, size_t, size_t); extern int _elf32_ehdr(Elf *, int); extern int _elf32_phdr(Elf *, int); extern int _elf32_shdr(Elf *, int); extern int _elf64_ehdr(Elf *, int); extern int _elf64_phdr(Elf *, int); extern int _elf64_shdr(Elf *, int); extern int _elf_byte; extern const Elf32_Ehdr _elf32_ehdr_init; extern const Elf64_Ehdr _elf64_ehdr_init; extern unsigned _elf_encode; extern _elf_execfill_func_t *_elf_execfill_func; extern void _elf_seterr(Msg, int); extern const Snode32 _elf32_snode_init; extern const Snode64 _elf64_snode_init; extern const Dnode _elf_dnode_init; extern unsigned _elf_work; extern mutex_t _elf_globals_mutex; extern off_t _elf64_update(Elf * elf, Elf_Cmd cmd); extern int _elf64_swap_wrimage(Elf *elf); #ifdef __cplusplus } #endif #endif /* _DECL_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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include #include "libelf.h" #include "decl.h" #include "member.h" int elf_end(Elf *elf) { Elf_Scn *s; Dnode *d; Elf_Void *trail = NULL; int rc; if (elf == NULL) return (0); ELFWLOCK(elf) if (--elf->ed_activ != 0) { rc = elf->ed_activ; ELFUNLOCK(elf) return (rc); } while (elf->ed_activ == 0) { for (s = elf->ed_hdscn; s != NULL; s = s->s_next) { if (s->s_myflags & SF_ALLOC) { if (trail != NULL) free(trail); trail = (Elf_Void *)s; } if ((s->s_myflags & SF_READY) == 0) continue; for (d = s->s_hdnode; d != NULL; ) { register Dnode *t; if (d->db_buf != NULL) free(d->db_buf); if ((t = d->db_raw) != NULL) { if (t->db_buf != NULL) free(t->db_buf); if (t->db_myflags & DBF_ALLOC) free(t); } t = d->db_next; if (d->db_myflags & DBF_ALLOC) free(d); d = t; } } if (trail != NULL) { free(trail); trail = NULL; } { register Memlist *l; register Memident *i; for (l = elf->ed_memlist; l != NULL; l = (Memlist *)trail) { trail = (Elf_Void *)l->m_next; for (i = (Memident *)(l + 1); i < l->m_free; i++) free(i->m_member); free(l); } } if (elf->ed_myflags & EDF_EHALLOC) free(elf->ed_ehdr); if (elf->ed_myflags & EDF_PHALLOC) free(elf->ed_phdr); if (elf->ed_myflags & EDF_SHALLOC) free(elf->ed_shdr); if (elf->ed_myflags & EDF_RAWALLOC) free(elf->ed_raw); if (elf->ed_myflags & EDF_ASALLOC) free(elf->ed_arsym); if (elf->ed_myflags & EDF_ASTRALLOC) free(elf->ed_arstr); /* * Don't release the image until the last reference dies. * If the image was introduced via elf_memory() then * we don't release it at all, it's not ours to release. */ if (elf->ed_parent == NULL) { if (elf->ed_vm != NULL) free(elf->ed_vm); else if ((elf->ed_myflags & EDF_MEMORY) == 0) _elf_unmap(elf->ed_image, elf->ed_imagesz); } trail = (Elf_Void *)elf; elf = elf->ed_parent; ELFUNLOCK(trail) free(trail); trail = NULL; if (elf == NULL) break; /* * If parent is inactive we close * it too, so we need to lock it too. */ ELFWLOCK(elf) --elf->ed_activ; } if (elf != NULL) { ELFUNLOCK(elf) } return (0); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include "msg.h" #include "decl.h" #define ELFERRSHIFT 16 #define SYSERRMASK 0xffff /* * _elf_err has two values encoded in it, both the _elf_err # and * the system errno value (if relevant). These values are encoded * in the upper & lower 16 bits of the 4 byte integer. */ static int _elf_err = 0; static thread_key_t errkey = THR_ONCE_KEY; static thread_key_t bufkey = THR_ONCE_KEY; const char * _libelf_msg(Msg mid) { return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid))); } void _elf_seterr(Msg lib_err, int sys_err) { /*LINTED*/ intptr_t encerr = ((int)lib_err << ELFERRSHIFT) | (sys_err & SYSERRMASK); if (thr_main()) { _elf_err = (int)encerr; return; } (void) thr_keycreate_once(&errkey, 0); (void) thr_setspecific(errkey, (void *)encerr); } int _elf_geterr() { if (thr_main()) return (_elf_err); return ((uintptr_t)pthread_getspecific(errkey)); } const char * elf_errmsg(int err) { char *errno_str; char *elferr_str; char *buffer = 0; int syserr; int elferr; static char intbuf[MAXELFERR]; if (err == 0) { if ((err = _elf_geterr()) == 0) return (0); } else if (err == -1) { if ((err = _elf_geterr()) == 0) /*LINTED*/ /* MSG_INTL(EINF_NULLERROR) */ err = (int)EINF_NULLERROR << ELFERRSHIFT; } if (thr_main()) buffer = intbuf; else { /* * If this is a threaded APP then we store the * errmsg buffer in Thread Specific Storage. * * Each thread has its own private buffer. */ if (thr_keycreate_once(&bufkey, free) != 0) return (MSG_INTL(EBUG_THRDKEY)); buffer = pthread_getspecific(bufkey); if (!buffer) { if ((buffer = malloc(MAXELFERR)) == 0) return (MSG_INTL(EMEM_ERRMSG)); if (thr_setspecific(bufkey, buffer) != 0) { free(buffer); return (MSG_INTL(EBUG_THRDSET)); } } } elferr = (int)((uint_t)err >> ELFERRSHIFT); syserr = err & SYSERRMASK; /*LINTED*/ elferr_str = (char *)MSG_INTL(elferr); if (syserr && (errno_str = strerror(syserr))) (void) snprintf(buffer, MAXELFERR, MSG_ORIG(MSG_FMT_ERR), elferr_str, errno_str); else { (void) strncpy(buffer, elferr_str, MAXELFERR - 1); buffer[MAXELFERR - 1] = '\0'; } return (buffer); } int elf_errno() { int rc = _elf_geterr(); _elf_seterr(0, 0); return (rc); } /* * 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 (c) 1988 AT&T */ /* All Rights Reserved */ #include #include "decl.h" void elf_fill(int fill) { ELFACCESSDATA(_elf_byte, fill) } void _elf_execfill(_elf_execfill_func_t *execfill_func) { ELFACCESSDATA(_elf_execfill_func, execfill_func) } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" #include "msg.h" unsigned elf_flagdata(Elf_Data * data, Elf_Cmd cmd, unsigned flags) { unsigned rc = 0; Elf * elf; Elf_Scn * scn; Dnode * d; if (data == 0) return (0); d = (Dnode *) data; scn = d->db_scn; elf = scn->s_elf; READLOCKS(elf, scn) if (cmd == ELF_C_SET) { rc = d->db_uflags |= flags; } else if (cmd == ELF_C_CLR) { rc = d->db_uflags &= ~flags; } else _elf_seterr(EREQ_FLAG, 0); READUNLOCKS(elf, scn) return (rc); } unsigned int elf_flagehdr(Elf * elf, Elf_Cmd cmd, unsigned flags) { int rc; if (elf == 0) return (0); if (cmd == ELF_C_SET) { ELFWLOCK(elf) rc = elf->ed_ehflags |= flags; ELFUNLOCK(elf) return (rc); } if (cmd == ELF_C_CLR) { ELFWLOCK(elf) rc = elf->ed_ehflags &= ~flags; ELFUNLOCK(elf) return (rc); } _elf_seterr(EREQ_FLAG, 0); return (0); } unsigned elf_flagelf(Elf * elf, Elf_Cmd cmd, unsigned flags) { int rc; if (elf == 0) return (0); if (cmd == ELF_C_SET) { ELFWLOCK(elf) rc = elf->ed_uflags |= flags; ELFUNLOCK(elf) return (rc); } if (cmd == ELF_C_CLR) { ELFWLOCK(elf) rc = elf->ed_uflags &= ~flags; ELFUNLOCK(elf) return (rc); } _elf_seterr(EREQ_FLAG, 0); return (0); } unsigned elf_flagphdr(Elf * elf, Elf_Cmd cmd, unsigned flags) { int rc; if (elf == 0) return (0); if (cmd == ELF_C_SET) { ELFWLOCK(elf); rc = elf->ed_phflags |= flags; ELFUNLOCK(elf); return (rc); } if (cmd == ELF_C_CLR) { ELFWLOCK(elf); rc = elf->ed_phflags &= ~flags; ELFUNLOCK(elf); return (rc); } _elf_seterr(EREQ_FLAG, 0); return (0); } unsigned elf_flagscn(Elf_Scn * scn, Elf_Cmd cmd, unsigned flags) { unsigned rc; Elf * elf; if (scn == 0) return (0); elf = scn->s_elf; if (cmd == ELF_C_SET) { READLOCKS(elf, scn) rc = scn->s_uflags |= flags; READUNLOCKS(elf, scn) return (rc); } if (cmd == ELF_C_CLR) { READLOCKS(elf, scn) rc = scn->s_uflags &= ~flags; READUNLOCKS(elf, scn) return (rc); } _elf_seterr(EREQ_FLAG, 0); return (0); } unsigned elf_flagshdr(Elf_Scn * scn, Elf_Cmd cmd, unsigned flags) { unsigned rc; Elf * elf; if (scn == 0) return (0); elf = scn->s_elf; if (cmd == ELF_C_SET) { READLOCKS(elf, scn) rc = scn->s_shflags |= flags; READUNLOCKS(elf, scn) return (rc); } if (cmd == ELF_C_CLR) { READLOCKS(elf, scn) rc = scn->s_shflags &= ~flags; READUNLOCKS(elf, scn) return (rc); } _elf_seterr(EREQ_FLAG, 0); return (0); } /* * 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. */ #include #include "_libelf.h" #include "decl.h" #include "msg.h" /* * Find elf or it's class from a pointer to an Elf_Data struct. * Warning: this Assumes that the Elf_Data is part of a libelf * Dnode structure, which is expected to be true for any Elf_Data * passed into libelf *except* for the xlatetof() and xlatetom() functions. */ #define EDATA_CLASS(edata) \ (((Dnode *)(edata))->db_scn->s_elf->ed_class) #define EDATA_ELF(edata) \ (((Dnode *)(edata))->db_scn->s_elf) #define EDATA_SCN(edata) \ (((Dnode *)(edata))->db_scn) #define EDATA_READLOCKS(edata) \ READLOCKS(EDATA_ELF((edata)), EDATA_SCN((edata))) #define EDATA_READUNLOCKS(edata) \ READUNLOCKS(EDATA_ELF((edata)), EDATA_SCN((edata))) size_t gelf_fsize(Elf * elf, Elf_Type type, size_t count, unsigned ver) { int class; if (elf == NULL) return (0); class = gelf_getclass(elf); if (class == ELFCLASS32) return (elf32_fsize(type, count, ver)); else if (class == ELFCLASS64) return (elf64_fsize(type, count, ver)); _elf_seterr(EREQ_CLASS, 0); return (0); } int gelf_getclass(Elf *elf) { if (elf == NULL) return (0); /* * Don't rely on the idents, a new ehdr doesn't have it! */ return (elf->ed_class); } GElf_Ehdr * gelf_getehdr(Elf *elf, GElf_Ehdr *dst) { int class; if (elf == NULL) return (NULL); class = gelf_getclass(elf); if (class == ELFCLASS32) { Elf32_Ehdr * e = elf32_getehdr(elf); if (e == NULL) return (NULL); ELFRLOCK(elf); (void) memcpy(dst->e_ident, e->e_ident, EI_NIDENT); dst->e_type = e->e_type; dst->e_machine = e->e_machine; dst->e_version = e->e_version; dst->e_entry = (Elf64_Addr)e->e_entry; dst->e_phoff = (Elf64_Off)e->e_phoff; dst->e_shoff = (Elf64_Off)e->e_shoff; dst->e_flags = e->e_flags; dst->e_ehsize = e->e_ehsize; dst->e_phentsize = e->e_phentsize; dst->e_phnum = e->e_phnum; dst->e_shentsize = e->e_shentsize; dst->e_shnum = e->e_shnum; dst->e_shstrndx = e->e_shstrndx; ELFUNLOCK(elf); return (dst); } else if (class == ELFCLASS64) { Elf64_Ehdr * e = elf64_getehdr(elf); if (e == NULL) return (NULL); ELFRLOCK(elf); *dst = *e; ELFUNLOCK(elf); return (dst); } _elf_seterr(EREQ_CLASS, 0); return (NULL); } int gelf_update_ehdr(Elf *elf, GElf_Ehdr *src) { int class; if (elf == NULL) return (0); /* * In case elf isn't cooked. */ class = gelf_getclass(elf); if (class == ELFCLASSNONE) class = src->e_ident[EI_CLASS]; if (class == ELFCLASS32) { Elf32_Ehdr * d = elf32_getehdr(elf); if (d == NULL) return (0); ELFWLOCK(elf); (void) memcpy(d->e_ident, src->e_ident, EI_NIDENT); d->e_type = src->e_type; d->e_machine = src->e_machine; d->e_version = src->e_version; /* LINTED */ d->e_entry = (Elf32_Addr)src->e_entry; /* LINTED */ d->e_phoff = (Elf32_Off)src->e_phoff; /* LINTED */ d->e_shoff = (Elf32_Off)src->e_shoff; /* could memcpy the rest of these... */ d->e_flags = src->e_flags; d->e_ehsize = src->e_ehsize; d->e_phentsize = src->e_phentsize; d->e_phnum = src->e_phnum; d->e_shentsize = src->e_shentsize; d->e_shnum = src->e_shnum; d->e_shstrndx = src->e_shstrndx; ELFUNLOCK(elf); return (1); } else if (class == ELFCLASS64) { Elf64_Ehdr * d = elf64_getehdr(elf); if (d == NULL) return (0); ELFWLOCK(elf); *d = *(Elf64_Ehdr *)src; ELFUNLOCK(elf); return (1); } _elf_seterr(EREQ_CLASS, 0); return (0); } unsigned long gelf_newehdr(Elf *elf, int class) { if (elf == NULL) return (0); if (class == ELFCLASS32) return ((unsigned long)elf32_newehdr(elf)); else if (class == ELFCLASS64) return ((unsigned long)elf64_newehdr(elf)); _elf_seterr(EREQ_CLASS, 0); return (0); } GElf_Phdr * gelf_getphdr(Elf *elf, int ndx, GElf_Phdr *dst) { int class; size_t phnum; if (elf == NULL) return (NULL); if (elf_getphdrnum(elf, &phnum) == -1) return (NULL); if (phnum <= ndx) { _elf_seterr(EREQ_RAND, 0); return (NULL); } class = gelf_getclass(elf); if ((class != ELFCLASS32) && (class != ELFCLASS64)) { _elf_seterr(EREQ_CLASS, 0); return (NULL); } if (class == ELFCLASS32) { Elf32_Phdr *p = &((Elf32_Phdr *)elf32_getphdr(elf))[ndx]; ELFRLOCK(elf); dst->p_type = p->p_type; dst->p_flags = p->p_flags; dst->p_offset = (Elf64_Off)p->p_offset; dst->p_vaddr = (Elf64_Addr)p->p_vaddr; dst->p_paddr = (Elf64_Addr)p->p_paddr; dst->p_filesz = (Elf64_Xword)p->p_filesz; dst->p_memsz = (Elf64_Xword)p->p_memsz; dst->p_align = (Elf64_Xword)p->p_align; ELFUNLOCK(elf); } else if (class == ELFCLASS64) { Elf64_Phdr *phdrs = elf64_getphdr(elf); ELFRLOCK(elf); *dst = ((GElf_Phdr *)phdrs)[ndx]; ELFUNLOCK(elf); } return (dst); } int gelf_update_phdr(Elf *elf, int ndx, GElf_Phdr *src) { int class; size_t phnum; if (elf == NULL) return (0); if (elf_getphdrnum(elf, &phnum) == -1) return (0); if (phnum < ndx) { _elf_seterr(EREQ_RAND, 0); return (0); } class = gelf_getclass(elf); if (class == ELFCLASS32) { Elf32_Phdr *dst = &((Elf32_Phdr *)elf32_getphdr(elf))[ndx]; ELFWLOCK(elf); dst->p_type = src->p_type; dst->p_flags = src->p_flags; /* LINTED */ dst->p_offset = (Elf32_Off)src->p_offset; /* LINTED */ dst->p_vaddr = (Elf32_Addr)src->p_vaddr; /* LINTED */ dst->p_paddr = (Elf32_Addr)src->p_paddr; /* LINTED */ dst->p_filesz = (Elf32_Word)src->p_filesz; /* LINTED */ dst->p_memsz = (Elf32_Word)src->p_memsz; /* LINTED */ dst->p_align = (Elf32_Word)src->p_align; ELFUNLOCK(elf); } else if (class == ELFCLASS64) { Elf64_Phdr *dst = elf64_getphdr(elf); ELFWLOCK(elf); dst[ndx] = *(GElf_Phdr *)src; ELFUNLOCK(elf); } else { _elf_seterr(EREQ_CLASS, 0); return (0); } return (1); } unsigned long gelf_newphdr(Elf *elf, size_t phnum) { int class; if (elf == NULL) return (0); class = gelf_getclass(elf); if (class == ELFCLASS32) return ((unsigned long)elf32_newphdr(elf, phnum)); else if (class == ELFCLASS64) return ((unsigned long)elf64_newphdr(elf, phnum)); _elf_seterr(EREQ_CLASS, 0); return (0); } GElf_Shdr * gelf_getshdr(Elf_Scn *scn, GElf_Shdr *dst) { if (scn == NULL) return (NULL); if (scn->s_elf->ed_class == ELFCLASS32) { Elf32_Shdr *s = elf32_getshdr(scn); if (s == NULL) return (NULL); READLOCKS(scn->s_elf, scn); dst->sh_name = s->sh_name; dst->sh_type = s->sh_type; dst->sh_flags = (Elf64_Xword)s->sh_flags; dst->sh_addr = (Elf64_Addr)s->sh_addr; dst->sh_offset = (Elf64_Off)s->sh_offset; dst->sh_size = (Elf64_Xword)s->sh_size; dst->sh_link = s->sh_link; dst->sh_info = s->sh_info; dst->sh_addralign = (Elf64_Xword)s->sh_addralign; dst->sh_entsize = (Elf64_Xword)s->sh_entsize; READUNLOCKS(scn->s_elf, scn); return (dst); } else if (scn->s_elf->ed_class == ELFCLASS64) { Elf64_Shdr *s = elf64_getshdr(scn); if (s == NULL) return (NULL); READLOCKS(scn->s_elf, scn); *dst = *(Elf64_Shdr *)s; READUNLOCKS(scn->s_elf, scn); return (dst); } _elf_seterr(EREQ_CLASS, 0); return (NULL); } int gelf_update_shdr(Elf_Scn *scn, GElf_Shdr *src) { if (scn == NULL) return (0); if (scn->s_elf->ed_class == ELFCLASS32) { Elf32_Shdr *dst = elf32_getshdr(scn); if (dst == NULL) return (0); ELFWLOCK(scn->s_elf); dst->sh_name = src->sh_name; dst->sh_type = src->sh_type; /* LINTED */ dst->sh_flags = (Elf32_Word)src->sh_flags; /* LINTED */ dst->sh_addr = (Elf32_Addr)src->sh_addr; /* LINTED */ dst->sh_offset = (Elf32_Off) src->sh_offset; /* LINTED */ dst->sh_size = (Elf32_Word)src->sh_size; dst->sh_link = src->sh_link; dst->sh_info = src->sh_info; /* LINTED */ dst->sh_addralign = (Elf32_Word)src->sh_addralign; /* LINTED */ dst->sh_entsize = (Elf32_Word)src->sh_entsize; ELFUNLOCK(scn->s_elf); return (1); } else if (scn->s_elf->ed_class == ELFCLASS64) { Elf64_Shdr * dst = elf64_getshdr(scn); if (dst == NULL) return (0); ELFWLOCK(scn->s_elf); *dst = *(Elf64_Shdr *)src; ELFUNLOCK(scn->s_elf); return (1); } _elf_seterr(EREQ_CLASS, 0); return (0); } /* * gelf_xlatetof/gelf_xlatetom use 'elf' to find the class * because these are the odd case where the Elf_Data structs * might not have been allocated by libelf (and therefore * don't have Dnode's associated with them). */ Elf_Data * gelf_xlatetof(Elf *elf, Elf_Data *dst, const Elf_Data *src, unsigned encode) { int class; if ((elf == NULL) || (dst == NULL) || (src == NULL)) return (NULL); class = gelf_getclass(elf); if (class == ELFCLASS32) return (elf32_xlatetof(dst, src, encode)); else if (class == ELFCLASS64) return (elf64_xlatetof(dst, src, encode)); _elf_seterr(EREQ_CLASS, 0); return (NULL); } Elf_Data * gelf_xlatetom(Elf *elf, Elf_Data *dst, const Elf_Data *src, unsigned encode) { int class; if ((elf == NULL) || (dst == NULL) || (src == NULL)) return (NULL); class = gelf_getclass(elf); if (class == ELFCLASS32) return (elf32_xlatetom(dst, src, encode)); else if (class == ELFCLASS64) return (elf64_xlatetom(dst, src, encode)); _elf_seterr(EREQ_CLASS, 0); return (NULL); } GElf_Sym * gelf_getsym(Elf_Data * data, int ndx, GElf_Sym * dst) { int class; size_t entsize; if (data == NULL) return (NULL); class = EDATA_CLASS(data); if (class == ELFCLASS32) entsize = sizeof (Elf32_Sym); else if (class == ELFCLASS64) entsize = sizeof (GElf_Sym); else { _elf_seterr(EREQ_CLASS, 0); return (NULL); } EDATA_READLOCKS(data); if ((entsize * ndx) >= data->d_size) { _elf_seterr(EREQ_RAND, 0); dst = NULL; } else if (class == ELFCLASS32) { Elf32_Sym *s; s = &(((Elf32_Sym *)data->d_buf)[ndx]); dst->st_name = s->st_name; dst->st_value = (Elf64_Addr)s->st_value; dst->st_size = (Elf64_Xword)s->st_size; dst->st_info = ELF64_ST_INFO(ELF32_ST_BIND(s->st_info), ELF32_ST_TYPE(s->st_info)); dst->st_other = s->st_other; dst->st_shndx = s->st_shndx; } else *dst = ((GElf_Sym *)data->d_buf)[ndx]; EDATA_READUNLOCKS(data); return (dst); } int gelf_update_sym(Elf_Data *dst, int ndx, GElf_Sym *src) { int class, rc = 1; size_t entsize; if (dst == NULL) return (0); class = EDATA_CLASS(dst); if (class == ELFCLASS32) entsize = sizeof (Elf32_Sym); else if (class == ELFCLASS64) entsize = sizeof (GElf_Sym); else { _elf_seterr(EREQ_CLASS, 0); return (0); } ELFWLOCK(EDATA_ELF(dst)); if ((entsize * ndx) >= dst->d_size) { _elf_seterr(EREQ_RAND, 0); rc = 0; } else if (class == ELFCLASS32) { Elf32_Sym * d; d = &(((Elf32_Sym *)dst->d_buf)[ndx]); d->st_name = src->st_name; /* LINTED */ d->st_value = (Elf32_Addr)src->st_value; /* LINTED */ d->st_size = (Elf32_Word)src->st_size; d->st_info = ELF32_ST_INFO(ELF64_ST_BIND(src->st_info), ELF64_ST_TYPE(src->st_info)); d->st_other = src->st_other; d->st_shndx = src->st_shndx; } else ((Elf64_Sym *)dst->d_buf)[ndx] = *((Elf64_Sym *)src); ELFUNLOCK(EDATA_ELF(dst)); return (rc); } GElf_Syminfo * gelf_getsyminfo(Elf_Data *data, int ndx, GElf_Syminfo *dst) { int class; size_t entsize; if (data == NULL) return (NULL); class = EDATA_CLASS(data); if (class == ELFCLASS32) entsize = sizeof (Elf32_Syminfo); else if (class == ELFCLASS64) entsize = sizeof (GElf_Syminfo); else { _elf_seterr(EREQ_CLASS, 0); return (NULL); } EDATA_READLOCKS(data); if ((entsize * ndx) >= data->d_size) { _elf_seterr(EREQ_RAND, 0); dst = NULL; } else if (class == ELFCLASS32) { Elf32_Syminfo * si; si = &(((Elf32_Syminfo *)data->d_buf)[ndx]); dst->si_boundto = si->si_boundto; dst->si_flags = si->si_flags; } else *dst = ((GElf_Syminfo *)data->d_buf)[ndx]; EDATA_READUNLOCKS(data); return (dst); } int gelf_update_syminfo(Elf_Data *dst, int ndx, GElf_Syminfo *src) { int class, rc = 1; size_t entsize; if (dst == NULL) return (0); class = EDATA_CLASS(dst); if (class == ELFCLASS32) entsize = sizeof (Elf32_Syminfo); else if (class == ELFCLASS64) entsize = sizeof (GElf_Syminfo); else { _elf_seterr(EREQ_CLASS, 0); return (0); } ELFWLOCK(EDATA_ELF(dst)); if ((entsize * ndx) >= dst->d_size) { _elf_seterr(EREQ_RAND, 0); rc = 0; } else if (class == ELFCLASS32) { Elf32_Syminfo * d = &(((Elf32_Syminfo *)dst->d_buf)[ndx]); d->si_boundto = src->si_boundto; d->si_flags = src->si_flags; } else ((Elf64_Syminfo *)dst->d_buf)[ndx] = *((Elf64_Syminfo *)src); ELFUNLOCK(EDATA_ELF(dst)); return (rc); } GElf_Dyn * gelf_getdyn(Elf_Data *data, int ndx, GElf_Dyn *dst) { int class; size_t entsize; if (data == NULL) return (NULL); class = EDATA_CLASS(data); if (class == ELFCLASS32) entsize = sizeof (Elf32_Dyn); else if (class == ELFCLASS64) entsize = sizeof (GElf_Dyn); else { _elf_seterr(EREQ_CLASS, 0); return (NULL); } EDATA_READLOCKS(data); if ((entsize * ndx) >= data->d_size) { _elf_seterr(EREQ_RAND, 0); dst = NULL; } else if (class == ELFCLASS32) { Elf32_Dyn * d = &((Elf32_Dyn *)data->d_buf)[ndx]; dst->d_tag = (Elf32_Sword)d->d_tag; dst->d_un.d_val = (Elf32_Word) d->d_un.d_val; } else *dst = ((Elf64_Dyn *)data->d_buf)[ndx]; EDATA_READUNLOCKS(data); return (dst); } int gelf_update_dyn(Elf_Data *dst, int ndx, GElf_Dyn *src) { int class, rc = 1; size_t entsize; if (dst == NULL) return (0); class = EDATA_CLASS(dst); if (class == ELFCLASS32) entsize = sizeof (Elf32_Dyn); else if (class == ELFCLASS64) entsize = sizeof (GElf_Dyn); else { _elf_seterr(EREQ_CLASS, 0); return (0); } ELFWLOCK(EDATA_ELF(dst)); if ((entsize * ndx) >= dst->d_size) { _elf_seterr(EREQ_RAND, 0); rc = 0; } else if (class == ELFCLASS32) { Elf32_Dyn * d = &((Elf32_Dyn *)dst->d_buf)[ndx]; /* LINTED */ d->d_tag = (Elf32_Word)src->d_tag; /* LINTED */ d->d_un.d_val = (Elf32_Word)src->d_un.d_val; } else ((Elf64_Dyn *)dst->d_buf)[ndx] = *(Elf64_Dyn*)src; ELFUNLOCK(EDATA_ELF(dst)); return (rc); } GElf_Sym * gelf_getsymshndx(Elf_Data *symdata, Elf_Data *shndxdata, int ndx, GElf_Sym *symptr, Elf32_Word *xshndx) { if (gelf_getsym(symdata, ndx, symptr) == 0) return (NULL); if (shndxdata && xshndx) { EDATA_READLOCKS(shndxdata); if ((ndx * sizeof (Elf32_Word)) >= shndxdata->d_size) { _elf_seterr(EREQ_RAND, 0); EDATA_READUNLOCKS(shndxdata); return (NULL); } *xshndx = (((Elf32_Word *)shndxdata->d_buf)[ndx]); EDATA_READUNLOCKS(shndxdata); } else { *xshndx = 0; } return (symptr); } int gelf_update_symshndx(Elf_Data *symdata, Elf_Data *shndxdata, int ndx, GElf_Sym *symptr, Elf32_Word xshndx) { if (gelf_update_sym(symdata, ndx, symptr) == 0) return (0); if (shndxdata) { ELFWLOCK(EDATA_ELF(shndxdata)); if ((ndx * sizeof (Elf32_Word)) >= shndxdata->d_size) { _elf_seterr(EREQ_RAND, 0); ELFUNLOCK(EDATA_ELF(shndxdata)); return (0); } ((Elf32_Word *)shndxdata->d_buf)[ndx] = xshndx; ELFUNLOCK(EDATA_ELF(shndxdata)); } return (1); } GElf_Move * gelf_getmove(Elf_Data *src, int ndx, GElf_Move *dst) { int class; size_t entsize; if (src == NULL) return (NULL); class = EDATA_CLASS(src); if (class == ELFCLASS32) entsize = sizeof (Elf32_Move); else if (class == ELFCLASS64) entsize = sizeof (GElf_Move); else { _elf_seterr(EREQ_CLASS, 0); return (NULL); } EDATA_READLOCKS(src); if ((entsize * ndx) >= src->d_size) { _elf_seterr(EREQ_RAND, 0); dst = NULL; } else if (class == ELFCLASS32) { Elf32_Move * m = &((Elf32_Move *)src->d_buf)[ndx]; dst->m_poffset = (Elf64_Word)m->m_poffset; dst->m_repeat = (Elf64_Xword)m->m_repeat; dst->m_stride = (Elf64_Half)m->m_stride; dst->m_value = (Elf64_Xword)m->m_value; dst->m_info = ELF64_M_INFO(ELF32_M_SYM(m->m_info), ELF32_M_SIZE(m->m_info)); } else { *dst = ((Elf64_Move *)src->d_buf)[ndx]; } EDATA_READUNLOCKS(src); return (dst); } int gelf_update_move(Elf_Data *dest, int ndx, GElf_Move *src) { int class, rc = 1; size_t entsize; if (dest == NULL) return (0); class = EDATA_CLASS(dest); if (class == ELFCLASS32) entsize = sizeof (Elf32_Move); else if (class == ELFCLASS64) entsize = sizeof (GElf_Move); else { _elf_seterr(EREQ_CLASS, 0); return (0); } ELFWLOCK(EDATA_ELF(dest)); if ((entsize * ndx) >= dest->d_size) { _elf_seterr(EREQ_RAND, 0); rc = 0; } else if (class == ELFCLASS32) { Elf32_Move * m = &((Elf32_Move *)dest->d_buf)[ndx]; m->m_poffset = (Elf32_Word)src->m_poffset; m->m_repeat = (Elf32_Half)src->m_repeat; m->m_stride = (Elf32_Half)src->m_stride; m->m_value = (Elf32_Lword)src->m_value; m->m_info = (Elf32_Word)ELF32_M_INFO(ELF64_M_SYM(src->m_info), ELF64_M_SIZE(src->m_info)); } else { ((Elf64_Move *)dest->d_buf)[ndx] = *(Elf64_Move *)src; } ELFUNLOCK(EDATA_ELF(dest)); return (rc); } GElf_Rela * gelf_getrela(Elf_Data *src, int ndx, GElf_Rela *dst) { int class; size_t entsize; if (src == NULL) return (NULL); class = EDATA_CLASS(src); if (class == ELFCLASS32) entsize = sizeof (Elf32_Rela); else if (class == ELFCLASS64) entsize = sizeof (GElf_Rela); else { _elf_seterr(EREQ_CLASS, 0); return (NULL); } EDATA_READLOCKS(src); if ((entsize * ndx) >= src->d_size) { _elf_seterr(EREQ_RAND, 0); dst = NULL; } else if (class == ELFCLASS32) { Elf32_Rela * r = &((Elf32_Rela *)src->d_buf)[ndx]; dst->r_offset = (GElf_Addr)r->r_offset; dst->r_addend = (GElf_Addr)r->r_addend; /* * Elf32 will never have the extra data field that * Elf64's r_info field can have, so ignore it. */ /* LINTED */ dst->r_info = ELF64_R_INFO( ELF32_R_SYM(r->r_info), ELF32_R_TYPE(r->r_info)); } else *dst = ((Elf64_Rela *)src->d_buf)[ndx]; EDATA_READUNLOCKS(src); return (dst); } int gelf_update_rela(Elf_Data *dst, int ndx, GElf_Rela *src) { int class, rc = 1; size_t entsize; if (dst == NULL) return (0); class = EDATA_CLASS(dst); if (class == ELFCLASS32) entsize = sizeof (Elf32_Rela); else if (class == ELFCLASS64) entsize = sizeof (GElf_Rela); else { _elf_seterr(EREQ_CLASS, 0); return (0); } ELFWLOCK(EDATA_ELF(dst)); if ((entsize * ndx) >= dst->d_size) { _elf_seterr(EREQ_RAND, 0); rc = 0; } else if (class == ELFCLASS32) { Elf32_Rela * r = &((Elf32_Rela *)dst->d_buf)[ndx]; /* LINTED */ r->r_offset = (Elf32_Addr) src->r_offset; /* LINTED */ r->r_addend = (Elf32_Sword)src->r_addend; /* * Elf32 will never have the extra data field that * Elf64's r_info field can have, so ignore it. */ /* LINTED */ r->r_info = ELF32_R_INFO(ELF64_R_SYM(src->r_info), ELF64_R_TYPE(src->r_info)); } else { ((Elf64_Rela *)dst->d_buf)[ndx] = *(Elf64_Rela *)src; } ELFUNLOCK(EDATA_ELF(dst)); return (rc); } GElf_Rel * gelf_getrel(Elf_Data *src, int ndx, GElf_Rel *dst) { int class; size_t entsize; if (src == NULL) return (NULL); class = EDATA_CLASS(src); if (class == ELFCLASS32) entsize = sizeof (Elf32_Rel); else if (class == ELFCLASS64) entsize = sizeof (GElf_Rel); else { _elf_seterr(EREQ_CLASS, 0); return (NULL); } EDATA_READLOCKS(src); if ((entsize * ndx) >= src->d_size) { _elf_seterr(EREQ_RAND, 0); dst = NULL; } else if (class == ELFCLASS32) { Elf32_Rel * r = &((Elf32_Rel *)src->d_buf)[ndx]; dst->r_offset = (GElf_Addr)r->r_offset; /* * Elf32 will never have the extra data field that * Elf64's r_info field can have, so ignore it. */ /* LINTED */ dst->r_info = ELF64_R_INFO(ELF32_R_SYM(r->r_info), ELF32_R_TYPE(r->r_info)); } else *dst = ((Elf64_Rel *)src->d_buf)[ndx]; EDATA_READUNLOCKS(src); return (dst); } int gelf_update_rel(Elf_Data *dst, int ndx, GElf_Rel *src) { int class, rc = 1; size_t entsize; if (dst == NULL) return (0); class = EDATA_CLASS(dst); if (class == ELFCLASS32) entsize = sizeof (Elf32_Rel); else if (class == ELFCLASS64) entsize = sizeof (GElf_Rel); else { _elf_seterr(EREQ_CLASS, 0); return (0); } ELFWLOCK(EDATA_ELF(dst)); if ((entsize * ndx) >= dst->d_size) { _elf_seterr(EREQ_RAND, 0); rc = 0; } else if (class == ELFCLASS32) { Elf32_Rel * r = &((Elf32_Rel *)dst->d_buf)[ndx]; /* LINTED */ r->r_offset = (Elf32_Addr) src->r_offset; /* * Elf32 will never have the extra data field that * Elf64's r_info field can have, so ignore it. */ /* LINTED */ r->r_info = ELF32_R_INFO(ELF64_R_SYM(src->r_info), ELF64_R_TYPE(src->r_info)); } else { ((Elf64_Rel *)dst->d_buf)[ndx] = *(Elf64_Rel *)src; } ELFUNLOCK(EDATA_ELF(dst)); return (rc); } long gelf_checksum(Elf *elf) { int class = gelf_getclass(elf); if (class == ELFCLASS32) return (elf32_checksum(elf)); else if (class == ELFCLASS64) return (elf64_checksum(elf)); _elf_seterr(EREQ_CLASS, 0); return (0); } GElf_Cap * gelf_getcap(Elf_Data *data, int ndx, GElf_Cap *dst) { int class; size_t entsize; if (data == NULL) return (NULL); class = EDATA_CLASS(data); if (class == ELFCLASS32) entsize = sizeof (Elf32_Cap); else if (class == ELFCLASS64) entsize = sizeof (GElf_Cap); else { _elf_seterr(EREQ_CLASS, 0); return (NULL); } EDATA_READLOCKS(data); if ((entsize * ndx) >= data->d_size) { _elf_seterr(EREQ_RAND, 0); dst = NULL; } else if (class == ELFCLASS32) { Elf32_Cap *c = &(((Elf32_Cap *)data->d_buf)[ndx]); dst->c_tag = (Elf64_Xword)c->c_tag; dst->c_un.c_val = (Elf64_Xword)c->c_un.c_val; } else *dst = ((GElf_Cap *)data->d_buf)[ndx]; EDATA_READUNLOCKS(data); return (dst); } int gelf_update_cap(Elf_Data *dst, int ndx, GElf_Cap *src) { int class, rc = 1; size_t entsize; if (dst == NULL) return (0); class = EDATA_CLASS(dst); if (class == ELFCLASS32) entsize = sizeof (Elf32_Cap); else if (class == ELFCLASS64) entsize = sizeof (GElf_Cap); else { _elf_seterr(EREQ_CLASS, 0); return (0); } ELFWLOCK(EDATA_ELF(dst)); if ((entsize * ndx) >= dst->d_size) { _elf_seterr(EREQ_RAND, 0); rc = 0; } else if (class == ELFCLASS32) { Elf32_Cap *c = &(((Elf32_Cap *)dst->d_buf)[ndx]); c->c_tag = (Elf32_Word)src->c_tag; c->c_un.c_val = (Elf32_Word)src->c_un.c_val; } else ((Elf64_Cap *)dst->d_buf)[ndx] = *((Elf64_Cap *)src); ELFUNLOCK(EDATA_ELF(dst)); return (rc); } /* * If the specified object has a dynamic section, and that section * contains a DT_FLAGS_1 entry, then return the value of that entry. * Otherwise, return 0. */ GElf_Xword _gelf_getdynval(Elf *elf, GElf_Sxword tag) { Elf_Scn *scn = NULL; Elf_Data *data; GElf_Shdr shdr; GElf_Dyn dyn; int i, n; while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) == NULL) break; if (shdr.sh_type != SHT_DYNAMIC) continue; data = elf_getdata(scn, NULL); if (data != NULL) { n = shdr.sh_size / shdr.sh_entsize; for (i = 0; i < n; i++) { (void) gelf_getdyn(data, i, &dyn); if (dyn.d_tag == tag) { return (dyn.d_un.d_val); } } } break; } return (0); } GElf_Xword _gelf_getdyndtflags_1(Elf *elf) { return (_gelf_getdynval(elf, DT_FLAGS_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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include "libelf.h" #include "decl.h" #include "member.h" #include "msg.h" Elf_Arhdr * elf_getarhdr(Elf * elf) { Member * mh; Elf_Arhdr * rc; if (elf == 0) return (0); ELFRLOCK(elf) if ((mh = elf->ed_armem) == 0) { ELFUNLOCK(elf) _elf_seterr(EREQ_AR, 0); return (0); } if (mh->m_err != 0) { ELFUNLOCK(elf); /*LINTED*/ _elf_seterr((Msg)mh->m_err, 0); return (0); } rc = &elf->ed_armem->m_hdr; ELFUNLOCK(elf) return (rc); } /* * 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) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include #include #include "decl.h" #include "msg.h" /* * Convert archive symbol table to memory format * * This takes a pointer to file's archive symbol table, alignment * unconstrained. Returns null terminated vector of Elf_Arsym * structures. Elf_Arsym uses size_t to represent offsets, which * will be 32-bit in 32-bit versions, and 64-bits otherwise. * * There are two forms of archive symbol table, the original 32-bit * form, and a 64-bit form originally found in IRIX64. The two formats * differ only in the width of the integer word: * * # offsets 4/8-byte word * offset[0...] 4/8-byte word each * strings null-terminated, for offset[x] * * By default, the 64-bit form is only used when the archive exceeds * the limits of 32-bits (4GB) in size. However, this is not required, * and the ar -S option can be used to create a 64-bit symbol table in * an archive that is under 4GB. * * Both 32 and 64-bit versions of libelf can read the 32-bit format * without loss of information. Similarly, a 64-bit version of libelf * will have no problem reading a 64-bit symbol table. This leaves the * case where a 32-bit libelf reads a 64-bit symbol table, which requires * some explanation. The offsets in a 64-bit symbol table will have zeros * in the upper half of the words until the size of the archive exceeds 4GB. * However, 32-bit libelf is unable to read any files larger than 2GB * (see comments in update.c). As such, any archive that the 32-bit version * of this code will encounter will be under 4GB in size. The upper 4 * bytes of each word will be zero, and can be safely ignored. */ /* * Offsets in archive headers are written in MSB (large endian) order * on all platforms, regardless of native byte order. These macros read * 4 and 8 byte values from unaligned memory. * * note: * - The get8() macro for 32-bit code can ignore the first 4 bytes of * of the word, because they are known to be 0. * * - The inner most value in these macros is cast to an unsigned integer * of the final width in order to prevent the C comilier from doing * unwanted sign extension when the topmost bit of a byte is set. */ #define get4(p) (((((((uint32_t)p[0]<<8)+p[1])<<8)+p[2])<<8)+p[3]) #ifdef _LP64 #define get8(p) (((((((((((((((uint64_t)p[0]<<8)+p[1])<<8)+p[2])<<8)+ \ p[3])<<8)+p[4])<<8)+p[5])<<8)+p[6])<<8)+p[7]) #else #define get8(p) (((((((uint64_t)p[4]<<8)+p[5])<<8)+p[6])<<8)+p[7]) #endif static Elf_Void * arsym(Byte *off, size_t sz, size_t *e, int is64) { char *endstr = (char *)off + sz; char *str = NULL; Byte *endoff; Elf_Void *oas; size_t eltsize = is64 ? 8 : 4; { size_t n; if (is64) { if (sz < 8 || (sz - 8) / 8 < (n = get8(off))) { _elf_seterr(EFMT_ARSYMSZ, 0); return (NULL); } } else { if (sz < 4 || (sz - 4) / 4 < (n = get4(off))) { _elf_seterr(EFMT_ARSYMSZ, 0); return (NULL); } } off += eltsize; endoff = off + n * eltsize; /* * If there are symbols in the symbol table, a * string table must be present and NULL terminated. * * The format dictates that the string table must always be * present, however in the case of an archive containing no * symbols GNU ar will not create one. We are permissive for * the sake of compatibility. */ if ((n > 0) && (((str = (char *)endoff) >= endstr) || (*(endstr - 1) != '\0'))) { _elf_seterr(EFMT_ARSYM, 0); return (NULL); } /* * There is always at least one entry returned if a symtab * exists since the table's last entry is an artificial one * with a NULL as_name, but is included in the count. * * overflow can occur here, but not likely */ *e = n + 1; if ((oas = calloc(n + 1, sizeof (Elf_Arsym))) == NULL) { _elf_seterr(EMEM_ARSYM, errno); return (NULL); } } { Elf_Arsym *as = (Elf_Arsym *)oas; while (off < endoff) { if (str >= endstr) { _elf_seterr(EFMT_ARSYMSTR, 0); free(oas); return (NULL); } if (is64) as->as_off = get8(off); else as->as_off = get4(off); as->as_name = str; as->as_hash = elf_hash(str); ++as; off += eltsize; while (*str++ != '\0') /* LINTED */ ; } as->as_name = NULL; as->as_off = 0; as->as_hash = ~(unsigned long)0L; } return (oas); } Elf_Arsym * elf_getarsym(Elf *elf, size_t *ptr) { Byte *as; size_t sz; Elf_Arsym *rc; int is64; if (ptr != 0) *ptr = 0; if (elf == NULL) return (0); ELFRLOCK(elf); if (elf->ed_kind != ELF_K_AR) { ELFUNLOCK(elf); _elf_seterr(EREQ_AR, 0); return (0); } if ((as = (Byte *)elf->ed_arsym) == 0) { ELFUNLOCK(elf); return (0); } if (elf->ed_myflags & EDF_ASALLOC) { if (ptr != 0) *ptr = elf->ed_arsymsz; ELFUNLOCK(elf); /* LINTED */ return ((Elf_Arsym *)as); } is64 = (elf->ed_myflags & EDF_ARSYM64) != 0; /* * We're gonna need a write lock. */ ELFUNLOCK(elf) ELFWLOCK(elf) sz = elf->ed_arsymsz; if (_elf_vm(elf, (size_t)(as - (Byte *)elf->ed_ident), sz) != OK_YES) { ELFUNLOCK(elf); return (0); } if ((elf->ed_arsym = arsym(as, sz, &elf->ed_arsymsz, is64)) == 0) { ELFUNLOCK(elf); return (0); } elf->ed_myflags |= EDF_ASALLOC; if (ptr != 0) *ptr = elf->ed_arsymsz; rc = (Elf_Arsym *)elf->ed_arsym; ELFUNLOCK(elf); return (rc); } /* * Private function to obtain the value sizeof() would return * for a word from the symbol table from the given archive. Normally, * this is an unimportant implementation detail hidden within * elf_getarsym(). However, it is useful to elfdump for formatting the * output correctly, and for the file command. * * exit: * Returns 4 (32-bit) or 8 (64-bit) if a symbol table is present. * Returns 0 in all other cases. */ size_t _elf_getarsymwordsize(Elf *elf) { size_t size; if (elf == NULL) return (0); ELFRLOCK(elf); if ((elf->ed_kind == ELF_K_AR) && (elf->ed_arsym != 0)) size = (elf->ed_myflags & EDF_ARSYM64) ? 8 : 4; else size = 0; ELFUNLOCK(elf); return (size); } /* * 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) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include "libelf.h" #include "decl.h" off_t elf_getbase(Elf *elf) { off_t rc; if (elf == NULL) return (-1); ELFRLOCK(elf) rc = elf->ed_baseoff; ELFUNLOCK(elf) return (rc); } /* * Private function to obtain the offset of the archive header for * this archive member. The header directly precedes the base offset, * which is available via elf_getbase(), but we wish to isolate the * caller from implementation details that might change. * * Returns the offset on success, and -1 on failure. */ off_t _elf_getarhdrbase(Elf *elf) { off_t rc; if (elf == NULL) return (-1); ELFRLOCK(elf) if (elf->ed_parent == NULL) { _elf_seterr(EREQ_AR, 0); ELFUNLOCK(elf); return (-1); } rc = elf->ed_baseoff - sizeof (struct ar_hdr); ELFUNLOCK(elf) return (rc); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include #include #include #include "decl.h" #include "msg.h" /* * Convert data from file format to memory format. */ static const size_t align32[ELF_T_NUM] = { 1, /* ELF_T_BYTE */ sizeof (Elf32), /* ELF_T_ADDR */ sizeof (Elf32), /* ELF_T_DYN */ sizeof (Elf32), /* ELF_T_EHDR */ sizeof (Elf32_Half), /* ELF_T_HALF */ sizeof (Elf32), /* ELF_T_OFF */ sizeof (Elf32), /* ELF_T_PHDR */ sizeof (Elf32), /* ELF_T_RELA */ sizeof (Elf32), /* ELF_T_REL */ sizeof (Elf32), /* ELF_T_SHDR */ sizeof (Elf32), /* ELF_T_SWORD */ sizeof (Elf32), /* ELF_T_SYM */ sizeof (Elf32), /* ELF_T_WORD */ sizeof (Elf32), /* ELF_T_VERDEF */ sizeof (Elf32), /* ELF_T_VERNEED */ sizeof (Elf64_Sxword), /* ELF_T_SXWORD */ sizeof (Elf64), /* ELF_T_XWORD */ sizeof (Elf32_Half), /* ELF_T_SYMINFO */ sizeof (Elf32), /* ELF_T_NOTE */ sizeof (Elf32_Lword), /* ELF_T_MOVE */ sizeof (Elf32_Lword), /* ELF_T_MOVEP */ sizeof (Elf32_Word) /* ELF_T_CAP */ }; #define Nalign32 (sizeof (align32)/sizeof (align32[0])) static const size_t align64[ELF_T_NUM] = { 1, /* ELF_T_BYTE */ sizeof (Elf64), /* ELF_T_ADDR */ sizeof (Elf64), /* ELF_T_DYN */ sizeof (Elf64), /* ELF_T_EHDR */ sizeof (Elf64_Half), /* ELF_T_HALF */ sizeof (Elf64), /* ELF_T_OFF */ sizeof (Elf64), /* ELF_T_PHDR */ sizeof (Elf64), /* ELF_T_RELA */ sizeof (Elf64), /* ELF_T_REL */ sizeof (Elf64), /* ELF_T_SHDR */ sizeof (Elf64_Word), /* ELF_T_SWORD */ sizeof (Elf64), /* ELF_T_SYM */ sizeof (Elf64_Word), /* ELF_T_WORD */ sizeof (Elf64), /* ELF_T_VDEF */ sizeof (Elf64), /* ELF_T_VNEED */ sizeof (Elf64), /* ELF_T_SXWORD */ sizeof (Elf64), /* ELF_T_XWORD */ sizeof (Elf32_Half), /* ELF_T_SYMINFO */ sizeof (Elf32), /* ELF_T_NOTE */ sizeof (Elf64), /* ELF_T_MOVE */ sizeof (Elf64), /* ELF_T_MOVEP */ sizeof (Elf64_Word) /* ELF_T_CAP */ }; #define Nalign64 (sizeof (align64)/sizeof (align64[0])) /* * Could use an array indexed by ELFCLASS*, but I'd rather * avoid .data over something this infrequently used. The * next choice would be to add extra conditionals. */ #define NALIGN(elf) ((elf->ed_class == ELFCLASS32) ? Nalign32 : Nalign64) #define ALIGN(elf) ((elf->ed_class == ELFCLASS32) ? align32 : align64) Elf_Data * _elf_locked_getdata(Elf_Scn * scn, Elf_Data * data) { Dnode * d = (Dnode *)data; Elf * elf; Elf_Data src; unsigned work; assert(!elf_threaded || RW_LOCK_HELD(&(scn->s_elf->ed_rwlock))); assert(!elf_threaded || MUTEX_HELD(&(scn->s_mutex))); elf = scn->s_elf; if ((scn->s_myflags & SF_READY) == 0) { UPGRADELOCKS(elf, scn) /* * make sure someone else didn't come along and cook * this stuff. */ if ((scn->s_myflags & SF_READY) == 0) (void) _elf_cookscn(scn); DOWNGRADELOCKS(elf, scn) } if (d == 0) d = scn->s_hdnode; else d = d->db_next; if (scn->s_err != 0) { /*LINTED*/ _elf_seterr((Msg)scn->s_err, 0); return (0); } if (d == 0) { return (0); } if (d->db_scn != scn) { _elf_seterr(EREQ_DATA, 0); return (0); } if (d->db_myflags & DBF_READY) { return (&d->db_data); } elf = scn->s_elf; /* * Prepare return buffer. The data comes from the memory * image of the file. "Empty" regions get an empty buffer. * * Only sections of an ELF_C_READ file can be not READY here. * Furthermore, the input file must have been cooked or * frozen by now. Translate cooked files in place if possible. */ ELFACCESSDATA(work, _elf_work) d->db_data.d_version = work; if ((d->db_off == 0) || (d->db_fsz == 0)) { d->db_myflags |= DBF_READY; return (&d->db_data); } if (elf->ed_class == ELFCLASS32) { Elf32_Shdr *sh = scn->s_shdr; size_t sz = sh->sh_entsize; Elf_Type t = d->db_data.d_type; if ((t != ELF_T_BYTE) && (sz > 1) && (sz != elf32_fsize(t, 1, elf->ed_version))) { _elf_seterr(EFMT_ENTSZ, 0); return (0); } } else if (elf->ed_class == ELFCLASS64) { Elf64_Shdr *sh = scn->s_shdr; Elf64_Xword sz = sh->sh_entsize; Elf_Type t = d->db_data.d_type; if (t != ELF_T_BYTE && sz > 1 && sz != elf64_fsize(t, 1, elf->ed_version)) { _elf_seterr(EFMT_ENTSZ, 0); return (0); } } else { _elf_seterr(EREQ_CLASS, 0); return (0); } /* * validate the region */ if ((d->db_off < 0) || (d->db_off >= elf->ed_fsz) || (elf->ed_fsz - d->db_off < d->db_fsz)) { _elf_seterr(EFMT_DATA, 0); return (0); } /* * set up translation buffers and validate */ src.d_buf = (Elf_Void *)(elf->ed_ident + d->db_off); src.d_size = d->db_fsz; src.d_type = d->db_data.d_type; src.d_version = elf->ed_version; if (elf->ed_vm) { UPGRADELOCKS(elf, scn) if (_elf_vm(elf, (size_t)d->db_off, d->db_fsz) != OK_YES) { DOWNGRADELOCKS(elf, scn) return (0); } DOWNGRADELOCKS(elf, scn) } /* * decide where to put destination */ switch (elf->ed_status) { case ES_COOKED: if ((size_t)d->db_data.d_type >= NALIGN(elf)) { _elf_seterr(EBUG_COOKTYPE, 0); return (0); } /* * If the destination size (memory) is at least as * big as the source size (file), and has the necessary * alignment, reuse the space. * * Note that it is not sufficient to check the alignment * of the offset within the object. Rather, we must check * the alignment of the actual data buffer. The offset is * sufficient if the file is a plain object file, which * will always be mapped on a page boundary. In an archive * however, the only guarantee is that the object will start * on an even boundary within the archive file. The * Solaris ar(1) adds padding in most (but not all cases) * which minimizes this issue, but it is still important * for the remaining cases that do not get padded. It also * matters with archives produced by other versions of * ar(1), such as the GNU version, or one from another * ELF based operating system. */ if (d->db_data.d_size <= src.d_size) { d->db_data.d_buf = (Elf_Void *)(elf->ed_ident + d->db_off); if (((uintptr_t)d->db_data.d_buf % ALIGN(elf)[d->db_data.d_type]) == 0) { break; } else { /* Failure: Restore NULL buffer pointer */ d->db_data.d_buf = 0; } } /*FALLTHRU*/ case ES_FROZEN: if ((d->db_buf = malloc(d->db_data.d_size)) == 0) { _elf_seterr(EMEM_DATA, errno); return (0); } d->db_data.d_buf = d->db_buf; break; default: _elf_seterr(EBUG_COOKSTAT, 0); return (0); } if (elf->ed_class == ELFCLASS32) { if (elf32_xlatetom(&d->db_data, &src, elf->ed_encode) == 0) return (0); } else { /* ELFCLASS64 */ if (elf64_xlatetom(&d->db_data, &src, elf->ed_encode) == 0) return (0); } d->db_myflags |= DBF_READY; return (&d->db_data); } Elf_Data * elf_getdata(Elf_Scn * scn, Elf_Data * data) { Elf_Data * rc; Elf * elf; /* * trap null args, end of list, previous buffer. * SHT_NULL sections have no buffer list, so they * fall out here too. */ if (scn == 0) return (0); elf = scn->s_elf; READLOCKS(elf, scn); rc = _elf_locked_getdata(scn, data); READUNLOCKS(elf, scn); return (rc); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" #include "msg.h" static void* getehdr(Elf * elf, int class) { void * rc; if (elf == 0) return (0); ELFWLOCK(elf); if (elf->ed_class != class) { _elf_seterr(EREQ_CLASS, 0); ELFUNLOCK(elf); return (0); } if (elf->ed_ehdr == 0) (void) _elf_cook(elf); rc = elf->ed_ehdr; ELFUNLOCK(elf); return (rc); } Elf32_Ehdr * elf32_getehdr(Elf * elf) { return ((Elf32_Ehdr*) getehdr(elf, ELFCLASS32)); } Elf64_Ehdr * elf64_getehdr(Elf * elf) { return ((Elf64_Ehdr*) getehdr(elf, ELFCLASS64)); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" char * elf_getident(Elf *elf, size_t *ptr) { size_t sz = 0; char *id = 0; if (elf != 0) { ELFRLOCK(elf) if (elf->ed_identsz != 0) { if ((elf->ed_vm == 0) || (elf->ed_status != ES_COOKED)) { /* * We need to upgrade to a Writers * lock */ ELFUNLOCK(elf) ELFWLOCK(elf) if ((_elf_cook(elf) == OK_YES) && (_elf_vm(elf, (size_t)0, elf->ed_identsz) == OK_YES)) { id = elf->ed_ident; sz = elf->ed_identsz; } } else { id = elf->ed_ident; sz = elf->ed_identsz; } } ELFUNLOCK(elf) } if (ptr != 0) *ptr = sz; return (id); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" #include "msg.h" static void* getphdr(Elf * elf, int class) { void * rc; if (elf == 0) return (0); ELFWLOCK(elf); if (elf->ed_class != class) { _elf_seterr(EREQ_CLASS, 0); ELFUNLOCK(elf); return (0); } if (elf->ed_phdr == 0) (void) _elf_cook(elf); rc = elf->ed_phdr; ELFUNLOCK(elf); return (rc); } Elf32_Phdr * elf32_getphdr(Elf * elf) { return ((Elf32_Phdr*) getphdr(elf, ELFCLASS32)); } Elf64_Phdr * elf64_getphdr(Elf * elf) { return ((Elf64_Phdr*) getphdr(elf, ELFCLASS64)); } /* * 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. */ #include #include #include #include /* * Return number of entries in the program header array, taking * extended headers into account. * * elf_getphnum() was defined based on the definition of the earlier * elf_getshnum(). It returns 0 for failure, and 1 for success. * * elf_getphdrnum() supercedes elf_getphnum(), which is now considered * obsolete. It returns -1 for failure and 0 for success, matching * elf_getshdrnum(), and bringing us into alignment with the interface * agreed to in the 2002 gABI meeting. * * See the comment in getshnum.c for additional information. */ int elf_getphdrnum(Elf *elf, size_t *phnum) { GElf_Ehdr ehdr; Elf_Scn *scn; GElf_Shdr shdr0; if (gelf_getehdr(elf, &ehdr) == NULL) return (-1); if (ehdr.e_phnum != PN_XNUM) { *phnum = ehdr.e_phnum; return (0); } if ((scn = elf_getscn(elf, 0)) == NULL || gelf_getshdr(scn, &shdr0) == NULL) return (-1); if (shdr0.sh_info == 0) *phnum = ehdr.e_phnum; else *phnum = shdr0.sh_info; return (0); } int elf_getphnum(Elf *elf, size_t *phnum) { return (elf_getphdrnum(elf, phnum) == 0); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" #include "msg.h" Elf_Scn * elf_getscn(Elf * elf, size_t index) { Elf_Scn * s; Elf_Scn * prev_s; size_t j = index; size_t tabsz; if (elf == 0) return (0); ELFRLOCK(elf) tabsz = elf->ed_scntabsz; if (elf->ed_hdscn == 0) { ELFUNLOCK(elf) ELFWLOCK(elf) if ((elf->ed_hdscn == 0) && (_elf_cook(elf) != OK_YES)) { ELFUNLOCK(elf); return (0); } ELFUNLOCK(elf); ELFRLOCK(elf) } /* * If the section in question is part of a table allocated * from within _elf_prescn() then we can index straight * to it. */ if (index < tabsz) { s = &elf->ed_hdscn[index]; ELFUNLOCK(elf); return (s); } if (tabsz) s = &elf->ed_hdscn[tabsz - 1]; else s = elf->ed_hdscn; for (prev_s = 0; s != 0; prev_s = s, s = s->s_next) { if (prev_s) { SCNUNLOCK(prev_s) } SCNLOCK(s) if (j == 0) { if (s->s_index == index) { SCNUNLOCK(s) ELFUNLOCK(elf); return (s); } _elf_seterr(EBUG_SCNLIST, 0); SCNUNLOCK(s) ELFUNLOCK(elf) return (0); } --j; } if (prev_s) { SCNUNLOCK(prev_s) } _elf_seterr(EREQ_NDX, 0); ELFUNLOCK(elf); return (0); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" #include "msg.h" static void * getshdr(Elf_Scn * scn, int class) { void * rc; Elf * elf; if (scn == 0) return (0); elf = scn->s_elf; READLOCKS(elf, scn) if (elf->ed_class != class) { READUNLOCKS(elf, scn) _elf_seterr(EREQ_CLASS, 0); return (0); } rc = scn->s_shdr; READUNLOCKS(elf, scn) return (rc); } Elf32_Shdr * elf32_getshdr(Elf_Scn * scn) { return ((Elf32_Shdr*) getshdr(scn, ELFCLASS32)); } Elf64_Shdr * elf64_getshdr(Elf_Scn * scn) { return ((Elf64_Shdr*) getshdr(scn, ELFCLASS64)); } /* * 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. */ #include #include #include #include /* * Return number of entries in the section header array, taking * extended headers into account. * * elf_getshnum() and elf_getshstrndx() were defined during the 2002 gABI * meetings. They were supposed to return -1 for failure, and 0 for success. * Our manpage documented them as such, but we then implemented them to * return 0 for failure and 1 for success. This makes elf_getshnum() and * elf_getshstrnum() non-portable to systems that implement the 2002 gABI * definition. * * In 2005, the manpage was modified to match the code. * In 2009, the discrepency was identified. elf_getshdrnum() and * elf_getshdrstrndx() were created to provide a portable implementation. * The older two functions are considered to be obsolete, and are retained * for backward compatability. */ int elf_getshdrnum(Elf *elf, size_t *shnum) { GElf_Ehdr ehdr; Elf_Scn *scn; GElf_Shdr shdr0; if (gelf_getehdr(elf, &ehdr) == 0) return (-1); if (ehdr.e_shnum > 0) { *shnum = ehdr.e_shnum; return (0); } if ((ehdr.e_shnum == 0) && (ehdr.e_shoff == 0)) { *shnum = 0; return (0); } if ((scn = elf_getscn(elf, 0)) == 0) return (-1); if (gelf_getshdr(scn, &shdr0) == 0) return (-1); *shnum = shdr0.sh_size; return (0); } int elf_getshnum(Elf *elf, size_t *shnum) { return (elf_getshdrnum(elf, shnum) == 0); } /* * 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. */ #include #include #include #include /* * Return section header array string table index, taking * extended headers into account. * * elf_getshstrndx() returns 0 for failure, and 1 for success. * * elf_getshdrstrndx() supercedes elf_getshstrndx(), which is now considered * obsolete. It returns -1 for failure and 0 for success, bringing us into * alignment with the interface agreed to in the 2002 gABI meeting. * * See the comment in getshnum.c for additional information. */ int elf_getshdrstrndx(Elf *elf, size_t *shstrndx) { GElf_Ehdr ehdr; Elf_Scn *scn; GElf_Shdr shdr0; if (gelf_getehdr(elf, &ehdr) == 0) return (-1); if (ehdr.e_shstrndx != SHN_XINDEX) { *shstrndx = ehdr.e_shstrndx; return (0); } if ((scn = elf_getscn(elf, 0)) == 0) return (-1); if (gelf_getshdr(scn, &shdr0) == 0) return (-1); *shstrndx = shdr0.sh_link; return (0); } int elf_getshstrndx(Elf *elf, size_t *shstrndx) { return (elf_getshdrstrndx(elf, shstrndx) == 0); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * The elf_hash() routine as defined by the gABI */ unsigned long elf_hash(const char *ename) { unsigned int hval = 0; while (*ename) { unsigned int g; hval = (hval << 4) + *ename++; if ((g = (hval & 0xf0000000)) != 0) hval ^= g >> 24; hval &= ~g; } return ((unsigned long)hval); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #include #include #include "decl.h" #include "msg.h" /* * File input * These functions read input files. * On SVR4 and newer systems use mmap(2). On older systems (or on * file systems that don't support mmap, this code simulates mmap. * When reading a file, enough memory is allocated to hold the file's * image, and reads are delayed. When another part of the library * wants to use a part of the file, it "fetches" the needed regions. * * An elf descriptor has a bit array to manage this. Each bit * represents one "page" of the file. Pages are grouped into regions. * The page size is tunable. Its value should be at least one disk * block and small enough to avoid superfluous traffic. * * NBITS The number of bits in an unsigned. Each unsigned object * holds a "REGION." A byte must have at least 8 bits; * it may have more, though the extra bits at the top of * the unsigned will be unused. Thus, for 9-bit bytes and * 36-bit words, 4 bits at the top will stay empty. * * This mechanism gives significant performance gains for library * handling (among other things), because programs typically don't * need to look at entire libraries. The fastest I/O is no I/O. */ /* * This global is used to hold the value of the PAGESIZE macro. * * This is because the PAGESIZE macro actually calls the * sysconfig(_CONFIG_PAGESIZE) system call and we don't want * to repeatedly call this through out libelf. */ static unsigned long _elf_pagesize = 0; #define NBITS (8 * sizeof (unsigned)) #define REGSZ (NBITS * _elf_pagesize) #define PGNUM(off) ((off % REGSZ) / _elf_pagesize) #define REGNUM(off) (off / REGSZ) Okay _elf_vm(Elf * elf, size_t base, size_t sz) { register unsigned *hdreg, hdbit; unsigned *tlreg, tlbit; size_t tail; off_t off; Elf_Void *iop; /* * always validate region */ if ((base + sz) > elf->ed_fsz) { /* * range outside of file bounds. */ _elf_seterr(EFMT_VM, 0); return (OK_NO); } /* * If file is mmap()'d and/or the read size is 0 * their is nothing else for us to do. */ if (elf->ed_vm == 0 || sz == 0) return (OK_YES); /* * This uses arithmetic instead of masking because * sizeof (unsigned) might not be a power of 2. * * Tail gives one beyond the last offset that must be retrieved, * NOT the last in the region. */ if (elf->ed_parent && elf->ed_parent->ed_fd == -1) elf->ed_fd = -1; base += elf->ed_baseoff; tail = base + sz + _elf_pagesize - 1; off = base - base % _elf_pagesize; hdbit = 1 << PGNUM(base); tlbit = 1 << PGNUM(tail); hdreg = &elf->ed_vm[REGNUM(base)]; tlreg = &elf->ed_vm[REGNUM(tail)]; sz = 0; /* * Scan through the files 'page table' and make sure * that all of the pages in the specified range have been * loaded into memory. As the pages are loaded the appropriate * bit in the 'page table' is set. * * Note: This loop will only read in those pages which havn't * been previously loaded into memory, if the page is * already present it will not be re-loaded. */ while ((hdreg != tlreg) || (hdbit != tlbit)) { if (*hdreg & hdbit) { if (sz != 0) { /* * Read in a 'chunk' of the elf image. */ iop = (Elf_Void *)(elf->ed_image + off); /* * do not read past the end of the file */ if (elf->ed_imagesz - off < sz) sz = elf->ed_imagesz - off; if ((lseek(elf->ed_fd, off, SEEK_SET) != off) || (read(elf->ed_fd, iop, sz) != sz)) { _elf_seterr(EIO_VM, errno); return (OK_NO); } off += sz; sz = 0; } off += _elf_pagesize; } else { if (elf->ed_fd < 0) { _elf_seterr(EREQ_NOFD, 0); return (OK_NO); } sz += _elf_pagesize; *hdreg |= hdbit; } if (hdbit == ((unsigned)1 << (NBITS - 1))) { hdbit = 1; ++hdreg; } else hdbit <<= 1; } if (sz != 0) { iop = (Elf_Void *)(elf->ed_image + off); /* * do not read past the end of the file */ if ((elf->ed_imagesz - off) < sz) sz = elf->ed_imagesz - off; if ((lseek(elf->ed_fd, off, SEEK_SET) != off) || (read(elf->ed_fd, iop, sz) != sz)) { _elf_seterr(EIO_VM, errno); return (OK_NO); } } return (OK_YES); } Okay _elf_inmap(Elf * elf) { int fd = elf->ed_fd; register size_t sz; { register off_t off = lseek(fd, (off_t)0, SEEK_END); if (off == 0) return (OK_YES); if (off == -1) { _elf_seterr(EIO_FSZ, errno); return (OK_NO); } if ((sz = (size_t)off) != off) { _elf_seterr(EIO_FBIG, 0); return (OK_NO); } } /* * If the file is mapped, elf->ed_vm will stay null * and elf->ed_image will need to be unmapped someday. * If the file is read, elf->ed_vm and the file image * are allocated together; free() elf->ed_vm. * * If the file can be written, disallow mmap. * Otherwise, the input mapping and the output mapping * can collide. Moreover, elf_update will truncate * the file, possibly invalidating the input mapping. * Disallowing input mmap forces the library to malloc * and read the space, which will make output mmap safe. * Using mmap for output reduces the swap space needed * for the process, so that is given preference. */ { register char *p; if ((elf->ed_myflags & EDF_WRITE) == 0 && (p = mmap((char *)0, sz, PROT_READ, MAP_PRIVATE, fd, (off_t)0)) != (char *)-1) { elf->ed_image = elf->ed_ident = p; elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz; return (OK_YES); } } if (_elf_pagesize == 0) _elf_pagesize = PAGESIZE; /* * If mmap fails, try read. Some file systems don't mmap */ { register size_t vmsz = sizeof (unsigned) * (REGNUM(sz) + 1); if (vmsz % sizeof (Elf64) != 0) vmsz += sizeof (Elf64) - vmsz % sizeof (Elf64); if ((elf->ed_vm = (unsigned *)malloc(vmsz + sz)) == 0) { _elf_seterr(EMEM_VM, errno); return (OK_NO); } (void) memset(elf->ed_vm, 0, vmsz); elf->ed_vmsz = vmsz / sizeof (unsigned); elf->ed_image = elf->ed_ident = (char *)elf->ed_vm + vmsz; elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz; } return (_elf_vm(elf, (size_t)0, (size_t)1)); } void _elf_unmap(char *p, size_t sz) { if (p == 0 || sz == 0) return; (void) munmap(p, sz); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" Elf_Kind elf_kind(Elf * elf) { Elf_Kind rc; if (elf == 0) return (ELF_K_NONE); ELFRLOCK(elf); rc = elf->ed_kind; ELFUNLOCK(elf); return (rc); } # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # 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" @ _END_ # Message file for cmd/sgs/libelf (32bit specific - basically). # More C++ gibberish @ MSG_STR_LT "lt" @ MSG_STR_LS "ls" @ MSG_STR_DV "dv" @ MSG_STR_GT "gt" @ MSG_STR_RS "rs" @ MSG_STR_MD "md" @ MSG_STR_LE "le" @ MSG_STR_ML "ml" @ MSG_STR_PL "pl" @ MSG_STR_GE "ge" @ MSG_STR_AD "ad" @ MSG_STR_MI "mi" @ MSG_STR_NE "ne" @ MSG_STR_OR "or" @ MSG_STR_ER "er" @ MSG_STR_AA "aa" @ MSG_STR_OO "oo" @ MSG_STR_AS "as" @ MSG_STR_APL "apl" @ MSG_STR_AMI "ami" @ MSG_STR_AMU "amu" @ MSG_STR_ADV "adv" @ MSG_STR_AMD "amd" @ MSG_STR_AAD "aad" @ MSG_STR_AOR "aor" @ MSG_STR_AER "aer" @ MSG_STR_ALS "als" @ MSG_STR_ARS "ars" @ MSG_STR_PP "pp" @ MSG_STR_MM "mm" @ MSG_STR_VC "vc" @ MSG_STR_CL "cl" @ MSG_STR_RF "rf" @ MSG_STR_EQ "eq" @ MSG_STR_CO "co" @ MSG_STR_NT "nt" @ MSG_STR_NW "nw" @ MSG_STR_DL "dl" @ MSG_STR_OPNANGBRAK "<" @ MSG_STR_DBLOPNANGBRAK "<<" @ MSG_STR_SLASH "/" @ MSG_STR_CLOANGBRAK ">" @ MSG_STR_DBLCLOANGBRAK ">>" @ MSG_STR_PERCENT "%" @ MSG_STR_OPNANGBRAKEQU "<=" @ MSG_STR_PLUS "+" @ MSG_STR_CLOANGBRAKEQU ">=" @ MSG_STR_MINUS "-" @ MSG_STR_BANGEQU "!=" @ MSG_STR_PIPE "|" @ MSG_STR_CARAT "^" @ MSG_STR_DBLAMP "&&" @ MSG_STR_DBLPIPE "||" @ MSG_STR_EQU "=" @ MSG_STR_PLUSEQU "+=" @ MSG_STR_MINUSEQU "-=" @ MSG_STR_STARTEQU "*=" @ MSG_STR_SLASHEQU "/=" @ MSG_STR_PERCENTEQU "%=" @ MSG_STR_AMPEQU "&=" @ MSG_STR_PIPEEQU "|=" @ MSG_STR_CARATEQU "^=" @ MSG_STR_DBLOPENABKEQU "<<=" @ MSG_STR_DBLCLOSABKEQU ">>=" @ MSG_STR_DBLPLUS "++" @ MSG_STR_DBLMINUS "--" @ MSG_STR_OPENCLOBRAK "[]" @ MSG_STR_MINUSCLOANGBK "->" @ MSG_STR_DBLEQU "==" @ MSG_STR_BANG "!" @ MSG_STR_NEW " new" @ MSG_STR_DELETE " delete" @ MSG_STR_AMP "&" @ MSG_STR_OPENCLOSEPAR "()" @ MSG_STR_STAR "*" @ MSG_STR_TILDE "~" @ MSG_STR_EMPTY "" @ MSG_STR_COMMA "," @ MSG_STR_DBLCOL "::" @ MSG_STR_DBLCOLSTAR "::*" @ MSG_STR_SPACE " " @ MSG_STR_ELIPSE "..." @ MSG_STR_OPENPAR "(" @ MSG_STR_CLOSEPAR ")" @ MSG_STR_OPENBRAK "[" @ MSG_STR_CLOSEBRAK "]" @ MSG_STR_DBLUNDBAR "__" @ MSG_STR_TDBLUNDBAR "t__" @ MSG_STR_CONST_1 "const " @ MSG_STR_CONST_2 " const" @ MSG_STR_VOLATILE_1 "volatile " @ MSG_STR_VOLATILE_2 " volatile" @ MSG_STR_UNSIGNED "unsigned " @ MSG_STR_SIGNED "signed " @ MSG_STR_INT "int" @ MSG_STR_CHAR "char" @ MSG_STR_SHORT "short" @ MSG_STR_LONG "long" @ MSG_STR_FLOAT "float" @ MSG_STR_DOUBLE "double" @ MSG_STR_LONGDOUBLE "long double" @ MSG_STR_VOID "void" @ MSG_STR_OP "op" @ MSG_STR_OPERATOR_1 "operator" @ MSG_STR_OPERATOR_2 "operator " # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # 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 # #ident "%Z%%M% %I% %E% SMI" @ _START_ # Message file for cmd/sgs/libelf. @ MSG_ID_LIBELF # Null Error @ EINF_NULLERROR "Elf error 0" # BUG bug Internal error @ EBUG_COOKSTAT "Internal error: cook status" @ EBUG_COOKTYPE "Internal error: cook data type" @ EBUG_SCNLIST "Internal error: broken section list" @ EBUG_THRDKEY "Internal error: thr_keycreate() failed. \ Unable to allocate error buffer" @ EBUG_THRDSET "Internal error: thr_setspecific failed. \ Unable to create TSD for error message." # FMT fmt Format error @ EFMT_ARFMAG "Format error: archive fmag" @ EFMT_ARHDRSZ "Format error: archive header truncated" @ EFMT_ARMEMSZ "Format error: archive member truncated" @ EFMT_ARSYM "Format error: archive symtab truncated" @ EFMT_ARSYMSTR "Format error: archive symtab strings" @ EFMT_ARSYMSZ "Format error: archive symtab size" @ EFMT_DATA "Format error: data region truncated" @ EFMT_EHDRSZ "Format error: ehdr size" @ EFMT_ENTSZ "Format error: shdr entry size" @ EFMT_PHDRSZ "Format error: phdr entry size" @ EFMT_PHTAB "Format error: phdr table truncated" @ EFMT_SCNSZ "Format error: section sh_size too small for data" @ EFMT_SHDRSZ "Format error: shdr entry size" @ EFMT_SHTAB "Format error: shdr table truncated" @ EFMT_VER2 "Format error: ehdr EI_VERSION/e_version mismatch" @ EFMT_VM "Format error: reference outside file" @ EFMT_FBIG_CLASS32 "Format error: file size exceeds 4GB 32-bit limit" @ EFMT_FBIG_LARGEFILE "Format error: file size exceeds 2GB limit of 32-bit \ linker. 64-bit linker is recommended." @ EFMT_ARSTRNM "Format error: archive strtab name" @ EFMT_ARUNKNM "Format error: archive special name unknown" # IO io I/O error @ EIO_FBIG "I/O error: file too big for memory" @ EIO_FSZ "I/O error: get file size" @ EIO_READ "I/O error: raw read" @ EIO_SEEK "I/O error: seek" @ EIO_SYNC "I/O error: output msync" @ EIO_VM "I/O error: region read" @ EIO_WRITE "I/O error: output write" # MEM mem Memory error @ EMEM_ARMEM "Memory allocation error: archive member header" @ EMEM_ARSTR "Memory allocation error: archive long file name \ strings" @ EMEM_ARSYM "Memory allocation error: archive symtab" @ EMEM_DATA "Memory allocation error: section data" @ EMEM_DNODE "Memory allocation error: data node" @ EMEM_EHDR "Memory allocation error: ehdr" @ EMEM_ELF "Memory allocation error: elf descriptor" @ EMEM_OUT "Memory allocation error: output file space" @ EMEM_PHDR "Memory allocation error: phdr table" @ EMEM_SCN "Memory allocation error: scn descriptors" @ EMEM_SHDR "Memory allocation error: shdr table" @ EMEM_SNODE "Memory allocation error: section node" @ EMEM_VM "Memory allocation error: vm stats" @ EMEM_ERRMSG "Memory allocation error: during errmsg generation" # REQ req Request error @ EREQ_AR "Request error: not archive" @ EREQ_ARMEMFD "Request error: archive/member fildes mismatch" @ EREQ_ARRDWR "Request error: archive/member begin() for writing" @ EREQ_BEGIN "Request error: begin() ELF_C_..." @ EREQ_CLASS "Request error: class file/memory mismatch" @ EREQ_CNTLCMD "Request error: cntl() ELF_C_..." @ EREQ_CNTLWRT "Request error: cntl() ELF_C_FD... on output file" @ EREQ_DATA "Request error: data/scn mismatch" @ EREQ_ENCODE "Request error: unknown data encoding" @ EREQ_FLAG "Request error: flag() ELF_C_..." @ EREQ_NDX "Request error: no section at index" @ EREQ_NOFD "Request error: file descriptor disabled" @ EREQ_RAND "Request error: offset out of range" @ EREQ_RDWR "Request error: begin() ELF_C_... mismatch with parent" @ EREQ_SCNNULL "Request error: can't manipulate null section" @ EREQ_STROFF "Request error: string offset out of range" @ EREQ_STRSCN "Request error: no string table" @ EREQ_UPDATE "Request error: update() ELF_C_..." @ EREQ_UPDWRT "Request error: update() for write on read-only file" @ EREQ_VER "Request error: unknown version" @ EREQ_NOWRIMAGE "Request error: update(WRIMAGE) not performed on parent" @ EREQ_DSZ "Request error: destination too small" @ EREQ_TYPE "Request error: unknown ELF_T_..." # SEQ seq Sequence error @ ESEQ_EHDR "Sequence error: ehdr not created" @ ESEQ_VER "Sequence error: version not set" @ _END_ # The following strings represent reserved names. Reference to these strings # is via the MSG_ORIG() macro, and thus translations are required. @ MSG_SUNW_OST_SGS "SUNW_OST_SGS" # System error format @ MSG_FMT_ERR "%s: %s" # # 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) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.7 { global: elf_getphdrnum; elf_getshdrnum; elf_getshdrstrndx; } SUNW_1.6; SYMBOL_VERSION SUNW_1.6 { global: elf_getphnum; } SUNW_1.5; SYMBOL_VERSION SUNW_1.5 { global: gelf_getcap; gelf_update_cap; } SUNW_1.4; SYMBOL_VERSION SUNW_1.4 { global: elf_getshnum; elf_getshstrndx; gelf_getsymshndx; gelf_update_symshndx; } SUNW_1.3; SYMBOL_VERSION SUNW_1.3 { global: elf32_checksum; elf64_checksum; gelf_checksum; } SUNW_1.2; SYMBOL_VERSION SUNW_1.2 { global: elf64_fsize; elf64_getehdr; elf64_getphdr; elf64_getshdr; elf64_newehdr; elf64_newphdr; elf64_xlatetof; elf64_xlatetom; gelf_getclass; gelf_fsize; gelf_getehdr; gelf_update_ehdr; gelf_newehdr; gelf_getphdr; gelf_update_phdr; gelf_newphdr; gelf_getshdr; gelf_update_shdr; gelf_xlatetof; gelf_xlatetom; gelf_getsym; gelf_update_sym; gelf_getsyminfo; gelf_getmove; gelf_update_move; gelf_update_syminfo; gelf_getdyn; gelf_update_dyn; gelf_getrela; gelf_update_rela; gelf_getrel; gelf_update_rel; } SUNW_1.1; SYMBOL_VERSION SUNW_1.1 { global: SUNW_1.1; } SUNW_0.7; SYMBOL_VERSION SUNW_0.7 { global: elf_begin; elf_end; elf_memory; elf_next; elf_rand; elf_cntl; elf_errmsg; elf_errno; elf_fill; elf_flagdata; elf_flagehdr; elf_flagelf; elf_flagphdr; elf_flagscn; elf_flagshdr; elf_getarhdr; elf_getarsym; elf_getbase; elf_getdata; elf_newdata; elf_rawdata; elf_getident; elf_getscn; elf_ndxscn; elf_newscn; elf_nextscn; elf_hash; elf_kind; elf_rawfile; elf_strptr; elf_update; elf_version; nlist; elf32_fsize; elf32_getphdr; elf32_newphdr; elf32_getshdr; elf32_getehdr; elf32_newehdr; elf32_xlatetof; elf32_xlatetom; local: *; }; SYMBOL_VERSION SUNWprivate_1.1 { global: _elf_execfill; _elf_getarhdrbase; _elf_getarsymwordsize; _elf_getnextoff; _elf_getxoff; _elf_outsync; _elf_sys_encoding; _elf_swap_wrimage; _gelf_getdyndtflags_1; _gelf_getdynval; $if _ELF32 elf_demangle; $endif }; /* * 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 */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1995 by Sun Microsystems, Inc. * All rights reserved. */ /* * Member handling * Archive members have an ASCII header. A Member structure * holds internal information. Because the ASCII file header * may be clobbered, Member holds a private, safe copy. * The ar_name member of m_hdr points at m_name except for string * table names. Ar_rawname in m_hdr always points at m_raw. * * m_raw The original ar_name with null termination. * E.g., "name/ " * * m_name The processed name, with '/' terminator changed to '\0'. * Unused for string table names. E.g., "name\0 " * * To improve performance of member lookup we allocate lists which * contain MEMIDENTNO members: * * ed_memlist --> --------------------- * | m_next | * | m_end | * | m_free | * |---------------------| * | m_offset | m_member | * | m_offset | m_member | * | " | " | * --------------------- */ #define ARSZ(m) (sizeof ((struct ar_hdr *)0)->m) #define MEMIDENTNO 126 struct Member { Elf_Arhdr m_hdr; int m_err; long m_slide; char m_raw[ARSZ(ar_name)+1]; char m_name[ARSZ(ar_name)+1]; }; struct Memident { char * m_offset; struct Member * m_member; }; struct Memlist { struct Memlist * m_next; struct Memident * m_end; struct Memident * m_free; }; /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" size_t elf_ndxscn(Elf_Scn * scn) { size_t rc; Elf * elf; if (scn == 0) return (SHN_UNDEF); elf = scn->s_elf; READLOCKS(elf, scn) rc = scn->s_index; READUNLOCKS(elf, scn) return (rc); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" #include "msg.h" Elf_Data * elf_newdata(Elf_Scn * s) { Dnode * d; Elf_Data * rc; Elf * elf; unsigned work; if (s == 0) return (0); elf = s->s_elf; READLOCKS(elf, s) if (s->s_index == SHN_UNDEF) { _elf_seterr(EREQ_SCNNULL, 0); READUNLOCKS(elf, s) return (0); } if ((s->s_myflags & SF_READY) == 0) { UPGRADELOCKS(elf, s) /* * re-confirm that another 'thread' hasn't come along * and cooked this section while the locks were * obtained. */ if ((s->s_myflags & SF_READY) == 0) (void) _elf_cookscn(s); DOWNGRADELOCKS(elf, s) } /* * If this is the first new node, use the one allocated * in the scn itself. Update data buffer in both cases. */ ELFACCESSDATA(work, _elf_work) if (s->s_hdnode == 0) { s->s_dnode.db_uflags |= ELF_F_DIRTY; s->s_dnode.db_myflags |= DBF_READY; s->s_hdnode = &s->s_dnode; s->s_tlnode = &s->s_dnode; s->s_dnode.db_scn = s; s->s_dnode.db_data.d_version = work; rc = &s->s_dnode.db_data; READUNLOCKS(elf, s) return (rc); } if ((d = _elf_dnode()) == 0) { READUNLOCKS(elf, s) return (0); } d->db_data.d_version = work; d->db_scn = s; d->db_uflags |= ELF_F_DIRTY; d->db_myflags |= DBF_READY; s->s_tlnode->db_next = d; s->s_tlnode = d; rc = &d->db_data; READUNLOCKS(elf, s) return (rc); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include #include "decl.h" #include "msg.h" /* * This module is compiled twice, the second time having * -D_ELF64 defined. The following set of macros, along * with machelf.h, represent the differences between the * two compilations. Be careful *not* to add any class- * dependent code (anything that has elf32 or elf64 in the * name) to this code without hiding it behind a switch- * able macro like these. */ #if defined(_ELF64) #define ELFCLASS ELFCLASS64 #define _elf_ehdr_init _elf64_ehdr_init #define elf_newehdr elf64_newehdr #define getehdr elf64_getehdr #else /* else ELF32 */ #define ELFCLASS ELFCLASS32 #define _elf_ehdr_init _elf32_ehdr_init #define elf_newehdr elf32_newehdr #define getehdr elf32_getehdr #endif /* ELF64 */ Ehdr * elf_newehdr(Elf * elf) { Ehdr *eh; if (elf == 0) return (0); /* * If reading file, return its hdr */ ELFWLOCK(elf) if (elf->ed_myflags & EDF_READ) { ELFUNLOCK(elf) if ((eh = (Ehdr *)getehdr(elf)) != 0) { ELFWLOCK(elf) elf->ed_ehflags |= ELF_F_DIRTY; ELFUNLOCK(elf) } return (eh); } /* * Writing file */ if (elf->ed_class == ELFCLASSNONE) elf->ed_class = ELFCLASS; else if (elf->ed_class != ELFCLASS) { _elf_seterr(EREQ_CLASS, 0); ELFUNLOCK(elf) return (0); } ELFUNLOCK(elf); if ((eh = (Ehdr *)getehdr(elf)) != 0) { /* this cooks if necessary */ ELFWLOCK(elf) elf->ed_ehflags |= ELF_F_DIRTY; ELFUNLOCK(elf) return (eh); } ELFWLOCK(elf) if ((eh = (Ehdr *)malloc(sizeof (Ehdr))) == 0) { _elf_seterr(EMEM_EHDR, errno); ELFUNLOCK(elf) return (0); } *eh = _elf_ehdr_init; elf->ed_myflags |= EDF_EHALLOC; elf->ed_ehflags |= ELF_F_DIRTY; elf->ed_ehdr = eh; ELFUNLOCK(elf) return (eh); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include #include #include "decl.h" #include "msg.h" /* * This module is compiled twice, the second time having * -D_ELF64 defined. The following set of macros, along * with machelf.h, represent the differences between the * two compilations. Be careful *not* to add any class- * dependent code (anything that has elf32 or elf64 in the * name) to this code without hiding it behind a switch- * able macro like these. */ #if defined(_ELF64) #define ELFCLASS ELFCLASS64 #define elf_newphdr elf64_newphdr #define elf_getehdr elf64_getehdr #define _elf_msize _elf64_msize #define elf_fsize elf64_fsize #else /* else ELF32 */ #define ELFCLASS ELFCLASS32 #define elf_newphdr elf32_newphdr #define elf_getehdr elf32_getehdr #define _elf_msize _elf32_msize #define elf_fsize elf32_fsize #endif /* ELF64 */ Phdr * elf_newphdr(Elf * elf, size_t count) { Elf_Void * ph; size_t sz; Phdr * rc; unsigned work; if (elf == 0) return (0); ELFRLOCK(elf) if (elf->ed_class != ELFCLASS) { _elf_seterr(EREQ_CLASS, 0); ELFUNLOCK(elf) return (0); } ELFUNLOCK(elf) if (elf_getehdr(elf) == 0) { /* this cooks if necessary */ _elf_seterr(ESEQ_EHDR, 0); return (0); } /* * Free the existing header if appropriate. This could reuse * existing space if big enough, but that's unlikely, benefit * would be negligible, and code would be more complicated. */ ELFWLOCK(elf) if (elf->ed_myflags & EDF_PHALLOC) { elf->ed_myflags &= ~EDF_PHALLOC; rc = elf->ed_phdr; free(rc); } /* * Delete the header if count is zero. */ ELFACCESSDATA(work, _elf_work) if ((sz = count * _elf_msize(ELF_T_PHDR, work)) == 0) { elf->ed_phflags &= ~ELF_F_DIRTY; elf->ed_phdr = 0; ((Ehdr*)elf->ed_ehdr)->e_phnum = 0; ((Ehdr*)elf->ed_ehdr)->e_phentsize = 0; elf->ed_phdrsz = 0; ELFUNLOCK(elf) return (0); } if ((ph = malloc(sz)) == 0) { _elf_seterr(EMEM_PHDR, errno); elf->ed_phflags &= ~ELF_F_DIRTY; elf->ed_phdr = 0; ((Ehdr*)elf->ed_ehdr)->e_phnum = 0; ((Ehdr*)elf->ed_ehdr)->e_phentsize = 0; elf->ed_phdrsz = 0; ELFUNLOCK(elf) return (0); } elf->ed_myflags |= EDF_PHALLOC; (void) memset(ph, 0, sz); elf->ed_phflags |= ELF_F_DIRTY; /* LINTED */ ((Ehdr*)elf->ed_ehdr)->e_phnum = (Half)count; ((Ehdr*)elf->ed_ehdr)->e_phentsize /* LINTED */ = (Half)elf_fsize(ELF_T_PHDR, 1, work); elf->ed_phdrsz = sz; elf->ed_phdr = rc = ph; ELFUNLOCK(elf) return (rc); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" #include "msg.h" Elf_Scn * elf_newscn(Elf * elf) { Elf_Scn * tl; if (elf == 0) return (0); ELFWLOCK(elf) /* * if no sections yet, the file either isn't cooked * or it truly is empty. Then allocate shdr[0] */ if ((elf->ed_hdscn == 0) && (_elf_cook(elf) != OK_YES)) { ELFUNLOCK(elf) return (0); } if (elf->ed_ehdr == 0) { _elf_seterr(ESEQ_EHDR, 0); ELFUNLOCK(elf) return (0); } if (elf->ed_class == ELFCLASS32) { Snode32 *s; if (elf->ed_hdscn == 0) { if ((s = _elf32_snode()) == 0) { ELFUNLOCK(elf) return (0); } s->sb_scn.s_elf = elf; elf->ed_hdscn = elf->ed_tlscn = &s->sb_scn; s->sb_scn.s_uflags |= ELF_F_DIRTY; } if ((s = _elf32_snode()) == 0) { ELFUNLOCK(elf) return (0); } tl = elf->ed_tlscn; s->sb_scn.s_elf = elf; s->sb_scn.s_index = tl->s_index + 1; elf->ed_tlscn = tl->s_next = &s->sb_scn; ((Elf32_Ehdr *)elf->ed_ehdr)->e_shnum /* LINTED */ = (Elf32_Half)(tl->s_index + 2); s->sb_scn.s_uflags |= ELF_F_DIRTY; tl = &s->sb_scn; ELFUNLOCK(elf) return (tl); } else if (elf->ed_class == ELFCLASS64) { Snode64 *s; if (elf->ed_hdscn == 0) { if ((s = _elf64_snode()) == 0) { ELFUNLOCK(elf) return (0); } s->sb_scn.s_elf = elf; elf->ed_hdscn = elf->ed_tlscn = &s->sb_scn; s->sb_scn.s_uflags |= ELF_F_DIRTY; } if ((s = _elf64_snode()) == 0) { ELFUNLOCK(elf) return (0); } tl = elf->ed_tlscn; s->sb_scn.s_elf = elf; s->sb_scn.s_index = tl->s_index + 1; elf->ed_tlscn = tl->s_next = &s->sb_scn; ((Elf64_Ehdr *)elf->ed_ehdr)->e_shnum /* LINTED */ = (Elf64_Half)(tl->s_index + 2); s->sb_scn.s_uflags |= ELF_F_DIRTY; tl = &s->sb_scn; ELFUNLOCK(elf) return (tl); } else { _elf_seterr(EREQ_CLASS, 0); ELFUNLOCK(elf) return (0); } } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" Elf_Cmd elf_next(Elf * elf) { Elf *parent; if (elf == 0) return (ELF_C_NULL); ELFRLOCK(elf) if ((parent = elf->ed_parent) == 0) { ELFUNLOCK(elf); return (ELF_C_NULL); } ELFWLOCK(parent) if (elf->ed_siboff >= parent->ed_fsz) { ELFUNLOCK(parent) ELFUNLOCK(elf); return (ELF_C_NULL); } parent->ed_nextoff = elf->ed_siboff; ELFUNLOCK(parent) ELFUNLOCK(elf); return (ELF_C_READ); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" Elf_Scn * elf_nextscn(Elf * elf, Elf_Scn * scn) { Elf_Scn * ret_scn = 0; if (elf == 0) return (0); if (scn != 0) { READLOCKS(elf, scn) ret_scn = scn->s_next; READUNLOCKS(elf, scn) } else { ELFWLOCK(elf) if (elf->ed_hdscn == 0) { if (elf->ed_hdscn == 0) (void) _elf_cook(elf); } if ((scn = elf->ed_hdscn) != 0) ret_scn = scn->s_next; ELFUNLOCK(elf) } return (ret_scn); } /* * 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 (c) 1988 AT&T * All Rights Reserved */ #include #include #include #include #include #include #include "decl.h" #include "msg.h" /* * File output * These functions write output files. * On SVR4 and newer systems use mmap(2). On older systems (or on * file systems that don't support mmap), use write(2). */ char * _elf_outmap(int fd, size_t sz, unsigned int *pflag) { char *p; /* * Note: Some NFS implementations do not provide from enlarging a file * via ftruncate(), thus this may fail with ENOSUP. In this case the * fall through to the calloc() mechanism will occur. */ if ((!*pflag) && (ftruncate(fd, (off_t)sz) == 0) && (p = mmap((char *)0, sz, PROT_READ+PROT_WRITE, MAP_SHARED, fd, (off_t)0)) != (char *)-1) { *pflag = 1; return (p); } *pflag = 0; /* * If mmap fails, try calloc. Some file systems don't mmap. Note, we * use calloc rather than malloc, as ld(1) assumes that the backing * storage it is working with is zero filled. */ if ((p = (char *)calloc(1, sz)) == 0) _elf_seterr(EMEM_OUT, errno); return (p); } size_t _elf_outsync(int fd, char *p, size_t sz, unsigned int flag) { if (flag != 0) { int rv, err; err = ENOTSUP; /* msync should only return 0 or -1 */ rv = msync(p, sz, MS_ASYNC); if (rv == -1) err = errno; (void) munmap(p, sz); if (rv == 0) return (sz); _elf_seterr(EIO_SYNC, err); return (0); } if ((lseek(fd, 0L, SEEK_SET) == 0) && (write(fd, p, sz) == sz)) { (void) free(p); return (sz); } _elf_seterr(EIO_WRITE, errno); return (0); } /* * 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) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" #include "msg.h" size_t elf_rand(Elf * elf, size_t off) { if (elf == 0) return (0); ELFWLOCK(elf) if (elf->ed_kind != ELF_K_AR) { _elf_seterr(EREQ_AR, 0); ELFUNLOCK(elf) return (0); } if ((off == 0) || (elf->ed_fsz < off)) { _elf_seterr(EREQ_RAND, 0); ELFUNLOCK(elf) return (0); } elf->ed_nextoff = off; ELFUNLOCK(elf) return (off); } /* * Private function used to obtain the current value of the next * offset field for an archive header. Returns 0 for error, and * the offset otherwise. */ size_t _elf_getnextoff(Elf *elf) { size_t off; if (elf == NULL) return (0); ELFWLOCK(elf) if (elf->ed_kind != ELF_K_AR) { _elf_seterr(EREQ_AR, 0); ELFUNLOCK(elf) return (0); } off = elf->ed_nextoff; ELFUNLOCK(elf) return (off); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include "libelf.h" #include "decl.h" #include "msg.h" Elf_Data * elf_rawdata(Elf_Scn * scn, Elf_Data * data) { Dnode * d = (Dnode *)data; Dnode * raw; Elf_Data * rc; Elf * elf; if (scn == 0) return (0); elf = scn->s_elf; READLOCKS(elf, scn) if ((scn->s_myflags & SF_READY) == 0) { UPGRADELOCKS(elf, scn) if ((scn->s_myflags & SF_READY) == 0) (void) _elf_cookscn(scn); DOWNGRADELOCKS(elf, scn) } if (d == 0) d = scn->s_hdnode; else d = d->db_next; if (d == 0) { READUNLOCKS(elf, scn) return (0); } if (d->db_scn != scn) { _elf_seterr(EREQ_DATA, 0); READUNLOCKS(elf, scn) return (0); } /* * The data may come from a previously constructed Dbuf, * from the file's raw memory image, or the file system. * "Empty" regions get an empty buffer. */ if (d->db_raw != 0) { rc = &d->db_raw->db_data; READUNLOCKS(elf, scn) return (rc); } if ((raw = _elf_dnode()) == 0) { READUNLOCKS(elf, scn) return (0); } raw->db_myflags |= DBF_READY; if ((d->db_off == 0) || (d->db_fsz == 0)) { d->db_raw = raw; raw->db_data.d_size = d->db_shsz; rc = &raw->db_data; READUNLOCKS(elf, scn) return (rc); } /* * validate the region */ if ((d->db_off < 0) || (d->db_off >= elf->ed_fsz) || (elf->ed_fsz - d->db_off < d->db_fsz)) { _elf_seterr(EFMT_DATA, 0); free(raw); READUNLOCKS(elf, scn) return (0); } raw->db_data.d_size = d->db_fsz; if (elf->ed_raw != 0) { raw->db_data.d_buf = (Elf_Void *)(elf->ed_raw + d->db_off); d->db_raw = raw; rc = &raw->db_data; READUNLOCKS(elf, scn) return (rc); } raw->db_buf = (Elf_Void *)_elf_read(elf->ed_fd, elf->ed_baseoff + d->db_off, d->db_fsz); if (raw->db_buf == 0) { free(raw); READUNLOCKS(elf, scn) return (0); } raw->db_data.d_buf = raw->db_buf; d->db_raw = raw; rc = &raw->db_data; READUNLOCKS(elf, scn) return (rc); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" char * elf_rawfile(Elf *elf, size_t *ptr) { register size_t sz; char *p = 0; if (elf == 0) { if (ptr != 0) *ptr = 0; return (0); } ELFWLOCK(elf) if ((sz = elf->ed_fsz) == 0) { if (ptr != 0) *ptr = 0; ELFUNLOCK(elf) return (0); } if (elf->ed_raw != 0) p = elf->ed_raw; else if (elf->ed_status == ES_COOKED) { if ((p = _elf_read(elf->ed_fd, elf->ed_baseoff, sz)) != 0) { elf->ed_raw = p; elf->ed_myflags |= EDF_RAWALLOC; } else sz = 0; } else { p = elf->ed_raw = elf->ed_ident; elf->ed_status = ES_FROZEN; if (_elf_vm(elf, (size_t)0, elf->ed_fsz) != OK_YES) { p = 0; sz = 0; } } if (ptr != 0) *ptr = sz; ELFUNLOCK(elf) return (p); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include #include #include #include "libelf.h" #include "decl.h" #include "msg.h" /* * Raw file input/output * Read pieces of input files. */ char * _elf_read(int fd, off_t off, size_t fsz) { char *p; if (fsz == 0) return (0); if (fd == -1) { _elf_seterr(EREQ_NOFD, 0); return (0); } if (lseek(fd, off, 0) != off) { _elf_seterr(EIO_SEEK, errno); return (0); } if ((p = (char *)malloc(fsz)) == 0) { _elf_seterr(EMEM_DATA, errno); return (0); } if (read(fd, p, fsz) != fsz) { _elf_seterr(EIO_READ, errno); free(p); return (0); } return (p); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #include "libelf.h" #include "decl.h" #include "msg.h" char * elf_strptr(Elf * elf, size_t ndx, size_t off) { Elf_Scn *s; Elf_Data *d; char *rc; if (elf == 0) return (0); if ((s = elf_getscn(elf, ndx)) == 0) { _elf_seterr(EREQ_STRSCN, 0); return (0); } READLOCKS(elf, s) if (elf->ed_class == ELFCLASS32) { Elf32_Shdr* sh = (Elf32_Shdr*)s->s_shdr; if ((sh == 0) || (sh->sh_type != SHT_STRTAB)) { _elf_seterr(EREQ_STRSCN, 0); READUNLOCKS(elf, s) return (0); } } else if (elf->ed_class == ELFCLASS64) { Elf64_Shdr* sh = (Elf64_Shdr*)s->s_shdr; if ((sh == 0) || (sh->sh_type != SHT_STRTAB)) { _elf_seterr(EREQ_STRSCN, 0); READUNLOCKS(elf, s) return (0); } } else { _elf_seterr(EREQ_STRSCN, 0); READUNLOCKS(elf, s) return (0); } /* * If the layout bit is set, use the offsets and * sizes in the data buffers. Otherwise, take * data buffers in order. */ d = 0; if (elf->ed_uflags & ELF_F_LAYOUT) { while ((d = _elf_locked_getdata(s, d)) != 0) { if (d->d_buf == 0) continue; if ((off >= d->d_off) && (off < d->d_off + d->d_size)) { rc = (char *)d->d_buf + off - d->d_off; READUNLOCKS(elf, s) return (rc); } } } else { size_t sz = 0, j; while ((d = _elf_locked_getdata(s, d)) != 0) { if (((j = d->d_align) > 1) && (sz % j != 0)) { j -= sz % j; sz += j; if (off < j) break; off -= j; } if (d->d_buf != 0) { if (off < d->d_size) { rc = (char *)d->d_buf + off; READUNLOCKS(elf, s) return (rc); } } sz += d->d_size; if (off < d->d_size) break; off -= d->d_size; } } _elf_seterr(EREQ_STROFF, 0); READUNLOCKS(elf, s) return (0); } /* * 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 (c) 1988 AT&T * All Rights Reserved */ /* * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include "decl.h" #include "msg.h" /* * This module is compiled twice, the second time having * -D_ELF64 defined. The following set of macros, along * with machelf.h, represent the differences between the * two compilations. Be careful *not* to add any class- * dependent code (anything that has elf32 or elf64 in the * name) to this code without hiding it behind a switch- * able macro like these. */ #if defined(_ELF64) #define FSZ_LONG ELF64_FSZ_XWORD #define ELFCLASS ELFCLASS64 #define _elf_snode_init _elf64_snode_init #define _elfxx_cookscn _elf64_cookscn #define _elf_upd_lib _elf64_upd_lib #define elf_fsize elf64_fsize #define _elf_entsz _elf64_entsz #define _elf_msize _elf64_msize #define _elf_upd_usr _elf64_upd_usr #define wrt wrt64 #define elf_xlatetof elf64_xlatetof #define _elfxx_update _elf64_update #define _elfxx_swap_wrimage _elf64_swap_wrimage #else /* ELF32 */ #define FSZ_LONG ELF32_FSZ_WORD #define ELFCLASS ELFCLASS32 #define _elf_snode_init _elf32_snode_init #define _elfxx_cookscn _elf32_cookscn #define _elf_upd_lib _elf32_upd_lib #define elf_fsize elf32_fsize #define _elf_entsz _elf32_entsz #define _elf_msize _elf32_msize #define _elf_upd_usr _elf32_upd_usr #define wrt wrt32 #define elf_xlatetof elf32_xlatetof #define _elfxx_update _elf32_update #define _elfxx_swap_wrimage _elf32_swap_wrimage #endif /* ELF64 */ #if !(defined(_LP64) && defined(_ELF64)) #define TEST_SIZE /* * Handle the decision of whether the current linker can handle the * desired object size, and if not, which error to issue. * * Input is the desired size. On failure, an error has been issued * and 0 is returned. On success, 1 is returned. */ static int test_size(Lword hi) { #ifndef _LP64 /* 32-bit linker */ /* * A 32-bit libelf is limited to a 2GB output file. This limit * is due to the fact that off_t is a signed value, and that * libelf cannot support large file support: * - ABI reasons * - Memory use generally is 2x output file size anyway, * so lifting the file size limit will just send * you crashing into the 32-bit VM limit. * If the output is an ELFCLASS64 object, or an ELFCLASS32 object * under 4GB, switching to the 64-bit version of libelf will help. * However, an ELFCLASS32 object must not exceed 4GB. */ if (hi > INT_MAX) { /* Bigger than 2GB */ #ifndef _ELF64 /* ELFCLASS32 object is fundamentally too big? */ if (hi > UINT_MAX) { _elf_seterr(EFMT_FBIG_CLASS32, 0); return (0); } #endif /* _ELF64 */ /* Should switch to the 64-bit libelf? */ _elf_seterr(EFMT_FBIG_LARGEFILE, 0); return (0); } #endif /* !_LP64 */ #if defined(_LP64) && !defined(_ELF64) /* 64-bit linker, ELFCLASS32 */ /* * A 64-bit linker can produce any size output * file, but if the resulting file is ELFCLASS32, * it must not exceed 4GB. */ if (hi > UINT_MAX) { _elf_seterr(EFMT_FBIG_CLASS32, 0); return (0); } #endif return (1); } #endif /* TEST_SIZE */ /* * Output file update * These functions walk an Elf structure, update its information, * and optionally write the output file. Because the application * may control of the output file layout, two upd_... routines * exist. They're similar but too different to merge cleanly. * * The library defines a "dirty" bit to force parts of the file * to be written on update. These routines ignore the dirty bit * and do everything. A minimal update routine might be useful * someday. */ static size_t _elf_upd_lib(Elf * elf) { Lword hi; Lword hibit; Elf_Scn * s; register Lword sz; Ehdr * eh = elf->ed_ehdr; unsigned ver = eh->e_version; register char *p = (char *)eh->e_ident; size_t scncnt; /* * Ehdr and Phdr table go first */ p[EI_MAG0] = ELFMAG0; p[EI_MAG1] = ELFMAG1; p[EI_MAG2] = ELFMAG2; p[EI_MAG3] = ELFMAG3; p[EI_CLASS] = ELFCLASS; /* LINTED */ p[EI_VERSION] = (Byte)ver; hi = elf_fsize(ELF_T_EHDR, 1, ver); /* LINTED */ eh->e_ehsize = (Half)hi; if (eh->e_phnum != 0) { /* LINTED */ eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver); /* LINTED */ eh->e_phoff = (Off)hi; hi += eh->e_phentsize * eh->e_phnum; } else { eh->e_phoff = 0; eh->e_phentsize = 0; } /* * Obtain the first section header. Typically, this section has NULL * contents, however in the case of Extended ELF Sections this section * is used to hold an alternative e_shnum, e_shstrndx and e_phnum. * On initial allocation (see _elf_snode) the elements of this section * would have been zeroed. The e_shnum is initialized later, after the * section header count has been determined. The e_shstrndx and * e_phnum may have already been initialized by the caller (for example, * gelf_update_shdr() in mcs(1)). */ if ((s = elf->ed_hdscn) == 0) { eh->e_shnum = 0; scncnt = 0; } else { s = s->s_next; scncnt = 1; } /* * Loop through sections. Compute section size before changing hi. * Allow null buffers for NOBITS. */ hibit = 0; for (; s != 0; s = s->s_next) { register Dnode *d; register Lword fsz, j; Shdr *sh = s->s_shdr; scncnt++; if (sh->sh_type == SHT_NULL) { *sh = _elf_snode_init.sb_shdr; continue; } if ((s->s_myflags & SF_READY) == 0) (void) _elfxx_cookscn(s); sh->sh_addralign = 1; if ((sz = (Lword)_elf_entsz(elf, sh->sh_type, ver)) != 0) /* LINTED */ sh->sh_entsize = (Half)sz; sz = 0; for (d = s->s_hdnode; d != 0; d = d->db_next) { if ((fsz = elf_fsize(d->db_data.d_type, 1, ver)) == 0) return (0); j = _elf_msize(d->db_data.d_type, ver); fsz *= (d->db_data.d_size / j); d->db_osz = (size_t)fsz; if ((j = d->db_data.d_align) > 1) { if (j > sh->sh_addralign) sh->sh_addralign = (Xword)j; if (sz % j != 0) sz += j - sz % j; } d->db_data.d_off = (off_t)sz; d->db_xoff = sz; sz += fsz; } sh->sh_size = (Xword) sz; /* * We want to take into account the offsets for NOBITS * sections and let the "sh_offsets" point to where * the section would 'conceptually' fit within * the file (as required by the ABI). * * But - we must also make sure that the NOBITS does * not take up any actual space in the file. We preserve * the actual offset into the file in the 'hibit' variable. * When we come to the first non-NOBITS section after a * encountering a NOBITS section the hi counter is restored * to its proper place in the file. */ if (sh->sh_type == SHT_NOBITS) { if (hibit == 0) hibit = hi; } else { if (hibit) { hi = hibit; hibit = 0; } } j = sh->sh_addralign; if ((fsz = hi % j) != 0) hi += j - fsz; /* LINTED */ sh->sh_offset = (Off)hi; hi += sz; } /* * if last section was a 'NOBITS' section then we need to * restore the 'hi' counter to point to the end of the last * non 'NOBITS' section. */ if (hibit) { hi = hibit; hibit = 0; } /* * Shdr table last */ if (scncnt != 0) { if (hi % FSZ_LONG != 0) hi += FSZ_LONG - hi % FSZ_LONG; /* LINTED */ eh->e_shoff = (Off)hi; /* * If we are using 'extended sections' then the * e_shnum is stored in the sh_size field of the * first section header. * * NOTE: we set e_shnum to '0' because it's specified * this way in the gABI, and in the hopes that * this will cause less problems to unaware * tools then if we'd set it to SHN_XINDEX (0xffff). */ if (scncnt < SHN_LORESERVE) eh->e_shnum = scncnt; else { Shdr *sh; sh = (Shdr *)elf->ed_hdscn->s_shdr; sh->sh_size = scncnt; eh->e_shnum = 0; } /* LINTED */ eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver); hi += eh->e_shentsize * scncnt; } else { eh->e_shoff = 0; eh->e_shentsize = 0; } #ifdef TEST_SIZE if (test_size(hi) == 0) return (0); #endif return ((size_t)hi); } static size_t _elf_upd_usr(Elf * elf) { Lword hi; Elf_Scn * s; register Lword sz; Ehdr * eh = elf->ed_ehdr; unsigned ver = eh->e_version; register char *p = (char *)eh->e_ident; size_t scncnt; /* * Ehdr and Phdr table go first */ p[EI_MAG0] = ELFMAG0; p[EI_MAG1] = ELFMAG1; p[EI_MAG2] = ELFMAG2; p[EI_MAG3] = ELFMAG3; p[EI_CLASS] = ELFCLASS; /* LINTED */ p[EI_VERSION] = (Byte)ver; hi = elf_fsize(ELF_T_EHDR, 1, ver); /* LINTED */ eh->e_ehsize = (Half)hi; /* * If phnum is zero, phoff "should" be zero too, * but the application is responsible for it. * Allow a non-zero value here and update the * hi water mark accordingly. */ if (eh->e_phnum != 0) /* LINTED */ eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver); else eh->e_phentsize = 0; if ((sz = eh->e_phoff + eh->e_phentsize * eh->e_phnum) > hi) hi = sz; /* * Loop through sections, skipping index zero. * Compute section size before changing hi. * Allow null buffers for NOBITS. */ if ((s = elf->ed_hdscn) == 0) { eh->e_shnum = 0; scncnt = 0; } else { scncnt = 1; s = s->s_next; } for (; s != 0; s = s->s_next) { register Dnode *d; register Lword fsz, j; Shdr *sh = s->s_shdr; if ((s->s_myflags & SF_READY) == 0) (void) _elfxx_cookscn(s); ++scncnt; sz = 0; for (d = s->s_hdnode; d != 0; d = d->db_next) { if ((fsz = elf_fsize(d->db_data.d_type, 1, ver)) == 0) return (0); j = _elf_msize(d->db_data.d_type, ver); fsz *= (d->db_data.d_size / j); d->db_osz = (size_t)fsz; if ((sh->sh_type != SHT_NOBITS) && ((j = (d->db_data.d_off + d->db_osz)) > sz)) sz = j; } if (sh->sh_size < sz) { _elf_seterr(EFMT_SCNSZ, 0); return (0); } if ((sh->sh_type != SHT_NOBITS) && (hi < sh->sh_offset + sh->sh_size)) hi = sh->sh_offset + sh->sh_size; } /* * Shdr table last. Comment above for phnum/phoff applies here. */ if (scncnt != 0) { /* LINTED */ eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver); if (scncnt < SHN_LORESERVE) { eh->e_shnum = scncnt; } else { Shdr *sh; sh = (Shdr *)elf->ed_hdscn->s_shdr; sh->sh_size = scncnt; eh->e_shnum = 0; } } else { eh->e_shentsize = 0; } if ((sz = eh->e_shoff + eh->e_shentsize * scncnt) > hi) hi = sz; #ifdef TEST_SIZE if (test_size(hi) == 0) return (0); #endif return ((size_t)hi); } static size_t wrt(Elf * elf, Xword outsz, unsigned fill, int update_cmd) { Elf_Data dst, src; unsigned flag; Xword hi, sz; char *image; Elf_Scn *s; Ehdr *eh = elf->ed_ehdr; unsigned ver = eh->e_version; unsigned encode; int byte; _elf_execfill_func_t *execfill_func; /* * If this is an ELF_C_WRIMAGE write, then we encode into the * byte order of the system we are running on rather than that of * of the object. For ld.so.1, this is the same order, but * for 'ld', it might not be in the case where we are cross * linking an object for a different target. In this later case, * the linker-host byte order is necessary so that the linker can * manipulate the resulting image. It is expected that the linker * will call elf_swap_wrimage() if necessary to convert the image * to the target byte order. */ encode = (update_cmd == ELF_C_WRIMAGE) ? _elf_sys_encoding() : eh->e_ident[EI_DATA]; /* * Two issues can cause trouble for the output file. * First, begin() with ELF_C_RDWR opens a file for both * read and write. On the write update(), the library * has to read everything it needs before truncating * the file. Second, using mmap for both read and write * is too tricky. Consequently, the library disables mmap * on the read side. Using mmap for the output saves swap * space, because that mapping is SHARED, not PRIVATE. * * If the file is write-only, there can be nothing of * interest to bother with. * * The following reads the entire file, which might be * more than necessary. Better safe than sorry. */ if ((elf->ed_myflags & EDF_READ) && (_elf_vm(elf, (size_t)0, elf->ed_fsz) != OK_YES)) return (0); flag = elf->ed_myflags & EDF_WRALLOC; if ((image = _elf_outmap(elf->ed_fd, outsz, &flag)) == 0) return (0); if (flag == 0) elf->ed_myflags |= EDF_IMALLOC; /* * If an error occurs below, a "dirty" bit may be cleared * improperly. To save a second pass through the file, * this code sets the dirty bit on the elf descriptor * when an error happens, assuming that will "cover" any * accidents. */ /* * Hi is needed only when 'fill' is non-zero. * Fill is non-zero only when the library * calculates file/section/data buffer offsets. * The lib guarantees they increase monotonically. * That guarantees proper filling below. */ /* * Ehdr first */ src.d_buf = (Elf_Void *)eh; src.d_type = ELF_T_EHDR; src.d_size = sizeof (Ehdr); src.d_version = EV_CURRENT; dst.d_buf = (Elf_Void *)image; dst.d_size = eh->e_ehsize; dst.d_version = ver; if (elf_xlatetof(&dst, &src, encode) == 0) return (0); elf->ed_ehflags &= ~ELF_F_DIRTY; hi = eh->e_ehsize; /* * Phdr table if one exists */ if (eh->e_phnum != 0) { unsigned work; /* * Unlike other library data, phdr table is * in the user version. Change src buffer * version here, fix it after translation. */ src.d_buf = (Elf_Void *)elf->ed_phdr; src.d_type = ELF_T_PHDR; src.d_size = elf->ed_phdrsz; ELFACCESSDATA(work, _elf_work) src.d_version = work; dst.d_buf = (Elf_Void *)(image + eh->e_phoff); dst.d_size = eh->e_phnum * eh->e_phentsize; hi = (Xword)(eh->e_phoff + dst.d_size); if (elf_xlatetof(&dst, &src, encode) == 0) { elf->ed_uflags |= ELF_F_DIRTY; return (0); } elf->ed_phflags &= ~ELF_F_DIRTY; src.d_version = EV_CURRENT; } /* * Loop through sections */ ELFACCESSDATA(byte, _elf_byte); ELFACCESSDATA(execfill_func, _elf_execfill_func); for (s = elf->ed_hdscn; s != 0; s = s->s_next) { register Dnode *d, *prevd; Xword off = 0; Shdr *sh = s->s_shdr; char *start = image + sh->sh_offset; char *here; _elf_execfill_func_t *execfill; /* Only use the execfill function on SHF_EXECINSTR sections */ execfill = (sh->sh_flags & SHF_EXECINSTR) ? execfill_func : NULL; /* * Just "clean" DIRTY flag for "empty" sections. Even if * NOBITS needs padding, the next thing in the * file will provide it. (And if this NOBITS is * the last thing in the file, no padding needed.) */ if ((sh->sh_type == SHT_NOBITS) || (sh->sh_type == SHT_NULL)) { d = s->s_hdnode, prevd = 0; for (; d != 0; prevd = d, d = d->db_next) d->db_uflags &= ~ELF_F_DIRTY; continue; } /* * Clear out the memory between the end of the last * section and the begining of this section. */ if (fill && (sh->sh_offset > hi)) { sz = sh->sh_offset - hi; (void) memset(start - sz, byte, sz); } for (d = s->s_hdnode, prevd = 0; d != 0; prevd = d, d = d->db_next) { d->db_uflags &= ~ELF_F_DIRTY; here = start + d->db_data.d_off; /* * Clear out the memory between the end of the * last update and the start of this data buffer. * * These buffers represent input sections that have * been concatenated into an output section, so if * the output section is executable (SHF_EXECINSTR) * and a fill function has been registered, use the * function. Otherwise, use the fill byte. */ if (fill && (d->db_data.d_off > off)) { sz = (Xword)(d->db_data.d_off - off); if (execfill != NULL) (* execfill)(start, here - start - sz, sz); else (void) memset(here - sz, byte, sz); } if ((d->db_myflags & DBF_READY) == 0) { SCNLOCK(s); if (_elf_locked_getdata(s, &prevd->db_data) != &d->db_data) { elf->ed_uflags |= ELF_F_DIRTY; SCNUNLOCK(s); return (0); } SCNUNLOCK(s); } dst.d_buf = (Elf_Void *)here; dst.d_size = d->db_osz; /* * Copy the translated bits out to the destination * image. */ if (elf_xlatetof(&dst, &d->db_data, encode) == 0) { elf->ed_uflags |= ELF_F_DIRTY; return (0); } off = (Xword)(d->db_data.d_off + dst.d_size); } hi = sh->sh_offset + sh->sh_size; } /* * Shdr table last */ if (fill && (eh->e_shoff > hi)) { sz = eh->e_shoff - hi; (void) memset(image + hi, byte, sz); } src.d_type = ELF_T_SHDR; src.d_size = sizeof (Shdr); dst.d_buf = (Elf_Void *)(image + eh->e_shoff); dst.d_size = eh->e_shentsize; for (s = elf->ed_hdscn; s != 0; s = s->s_next) { assert((uintptr_t)dst.d_buf < ((uintptr_t)image + outsz)); s->s_shflags &= ~ELF_F_DIRTY; s->s_uflags &= ~ELF_F_DIRTY; src.d_buf = s->s_shdr; if (elf_xlatetof(&dst, &src, encode) == 0) { elf->ed_uflags |= ELF_F_DIRTY; return (0); } dst.d_buf = (char *)dst.d_buf + eh->e_shentsize; } /* * ELF_C_WRIMAGE signifyes that we build the memory image, but * that we do not actually write it to disk. This is used * by ld(1) to build up a full image of an elf file and then * to process the file before it's actually written out to * disk. This saves ld(1) the overhead of having to write * the image out to disk twice. */ if (update_cmd == ELF_C_WRIMAGE) { elf->ed_uflags &= ~ELF_F_DIRTY; elf->ed_wrimage = image; elf->ed_wrimagesz = outsz; return (outsz); } if (_elf_outsync(elf->ed_fd, image, outsz, ((elf->ed_myflags & EDF_IMALLOC) ? 0 : 1)) != 0) { elf->ed_uflags &= ~ELF_F_DIRTY; elf->ed_myflags &= ~EDF_IMALLOC; return (outsz); } elf->ed_uflags |= ELF_F_DIRTY; return (0); } /* * The following is a private interface between the linkers (ld & ld.so.1) * and libelf: * * elf_update(elf, ELF_C_WRIMAGE) * This will cause full image representing the elf file * described by the elf pointer to be built in memory. If the * elf pointer has a valid file descriptor associated with it * we will attempt to build the memory image from mmap()'ed * storage. If the elf descriptor does not have a valid * file descriptor (opened with elf_begin(0, ELF_C_IMAGE, 0)) * then the image will be allocated from dynamic memory (malloc()). * * elf_update() will return the size of the memory image built * when sucessful. * * When a subsequent call to elf_update() with ELF_C_WRITE as * the command is performed it will sync the image created * by ELF_C_WRIMAGE to disk (if fd available) and * free the memory allocated. */ off_t _elfxx_update(Elf * elf, Elf_Cmd cmd) { size_t sz; unsigned u; Ehdr *eh = elf->ed_ehdr; ELFWLOCK(elf) switch (cmd) { default: _elf_seterr(EREQ_UPDATE, 0); ELFUNLOCK(elf) return (-1); case ELF_C_WRIMAGE: if ((elf->ed_myflags & EDF_WRITE) == 0) { _elf_seterr(EREQ_UPDWRT, 0); ELFUNLOCK(elf) return (-1); } break; case ELF_C_WRITE: if ((elf->ed_myflags & EDF_WRITE) == 0) { _elf_seterr(EREQ_UPDWRT, 0); ELFUNLOCK(elf) return (-1); } if (elf->ed_wrimage) { if (elf->ed_myflags & EDF_WRALLOC) { free(elf->ed_wrimage); /* * The size is still returned even * though nothing is actually written * out. This is just to be consistant * with the rest of the interface. */ sz = elf->ed_wrimagesz; elf->ed_wrimage = 0; elf->ed_wrimagesz = 0; ELFUNLOCK(elf); return ((off_t)sz); } sz = _elf_outsync(elf->ed_fd, elf->ed_wrimage, elf->ed_wrimagesz, (elf->ed_myflags & EDF_IMALLOC ? 0 : 1)); elf->ed_myflags &= ~EDF_IMALLOC; elf->ed_wrimage = 0; elf->ed_wrimagesz = 0; ELFUNLOCK(elf); return ((off_t)sz); } /* FALLTHROUGH */ case ELF_C_NULL: break; } if (eh == 0) { _elf_seterr(ESEQ_EHDR, 0); ELFUNLOCK(elf) return (-1); } if ((u = eh->e_version) > EV_CURRENT) { _elf_seterr(EREQ_VER, 0); ELFUNLOCK(elf) return (-1); } if (u == EV_NONE) eh->e_version = EV_CURRENT; if ((u = eh->e_ident[EI_DATA]) == ELFDATANONE) { unsigned encode; ELFACCESSDATA(encode, _elf_encode) if (encode == ELFDATANONE) { _elf_seterr(EREQ_ENCODE, 0); ELFUNLOCK(elf) return (-1); } /* LINTED */ eh->e_ident[EI_DATA] = (Byte)encode; } u = 1; if (elf->ed_uflags & ELF_F_LAYOUT) { sz = _elf_upd_usr(elf); u = 0; } else sz = _elf_upd_lib(elf); if ((sz != 0) && ((cmd == ELF_C_WRITE) || (cmd == ELF_C_WRIMAGE))) sz = wrt(elf, (Xword)sz, u, cmd); if (sz == 0) { ELFUNLOCK(elf) return (-1); } ELFUNLOCK(elf) return ((off_t)sz); } /* * When wrt() processes an ELF_C_WRIMAGE request, the resulting image * gets the byte order (encoding) of the platform running the linker * rather than that of the target host. This allows the linker to modify * the image, prior to flushing it to the output file. This routine * is used to re-translate such an image into the byte order of the * target host. */ int _elfxx_swap_wrimage(Elf *elf) { Elf_Data dst, src; Elf_Scn *s; Ehdr *eh; Half e_phnum; unsigned ver; unsigned encode; /* * Ehdr first */ ELFWLOCK(elf); eh = elf->ed_ehdr; e_phnum = eh->e_phnum; ver = eh->e_version; encode = eh->e_ident[EI_DATA]; src.d_buf = dst.d_buf = (Elf_Void *)eh; src.d_type = dst.d_type = ELF_T_EHDR; src.d_size = dst.d_size = sizeof (Ehdr); src.d_version = dst.d_version = ver; if (elf_xlatetof(&dst, &src, encode) == 0) { ELFUNLOCK(elf); return (1); } /* * Phdr table if one exists */ if (e_phnum != 0) { unsigned work; /* * Unlike other library data, phdr table is * in the user version. */ src.d_buf = dst.d_buf = (Elf_Void *)elf->ed_phdr; src.d_type = dst.d_type = ELF_T_PHDR; src.d_size = dst.d_size = elf->ed_phdrsz; ELFACCESSDATA(work, _elf_work) src.d_version = dst.d_version = work; if (elf_xlatetof(&dst, &src, encode) == 0) { ELFUNLOCK(elf); return (1); } } /* * Loop through sections */ for (s = elf->ed_hdscn; s != 0; s = s->s_next) { register Dnode *d, *prevd; Shdr *sh = s->s_shdr; if ((sh->sh_type == SHT_NOBITS) || (sh->sh_type == SHT_NULL)) continue; for (d = s->s_hdnode, prevd = 0; d != 0; prevd = d, d = d->db_next) { if ((d->db_myflags & DBF_READY) == 0) { SCNLOCK(s); if (_elf_locked_getdata(s, &prevd->db_data) != &d->db_data) { SCNUNLOCK(s); ELFUNLOCK(elf); return (1); } SCNUNLOCK(s); } dst = d->db_data; if (elf_xlatetof(&dst, &d->db_data, encode) == 0) { ELFUNLOCK(elf); return (1); } } } /* * Shdr table */ src.d_type = dst.d_type = ELF_T_SHDR; src.d_version = dst.d_version = ver; for (s = elf->ed_hdscn; s != 0; s = s->s_next) { src.d_buf = dst.d_buf = s->s_shdr; src.d_size = dst.d_size = sizeof (Shdr); if (elf_xlatetof(&dst, &src, encode) == 0) { ELFUNLOCK(elf); return (1); } } ELFUNLOCK(elf); return (0); } #ifndef _ELF64 /* class-independent, only needs to be compiled once */ off_t elf_update(Elf *elf, Elf_Cmd cmd) { if (elf == 0) return (-1); if (elf->ed_class == ELFCLASS32) return (_elf32_update(elf, cmd)); else if (elf->ed_class == ELFCLASS64) { return (_elf64_update(elf, cmd)); } _elf_seterr(EREQ_CLASS, 0); return (-1); } int _elf_swap_wrimage(Elf *elf) { if (elf == 0) return (0); if (elf->ed_class == ELFCLASS32) return (_elf32_swap_wrimage(elf)); if (elf->ed_class == ELFCLASS64) return (_elf64_swap_wrimage(elf)); _elf_seterr(EREQ_CLASS, 0); return (0); } /* * 4106312, 4106398, This is an ad-hoc means for the 32-bit * Elf64 version of libld.so.3 to get around the limitation * of a 32-bit d_off field. This is only intended to be * used by libld to relocate symbols in large NOBITS sections. */ Elf64_Off _elf_getxoff(Elf_Data * d) { return (((Dnode *)d)->db_xoff); } #endif /* !_ELF64 */ /* * 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 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include /* * fmsize: Array used to determine what size the the structures * are (for memory image & file image). * * x32: Translation routines - to file & to memory. * * What must be done when adding a new type for conversion: * * The first question is whether you need a new ELF_T_* type * to be created. If you've introduced a new structure - then * it will need to be described - this is done by: * * o adding a new type ELF_T_* to usr/src/head/libelf.h * o Create a new macro to define the bytes contained in the structure. Take a * look at the 'Syminfo_1' macro defined below. The declarations describe * the structure based off of the field size of each element of the structure. * o Add a entry to the fmsize table for the new ELF_T_* type. * o Create a _11_tof macro. Take a look at 'syminfo_11_tof'. * o Create a _11_tom macro. Take a look at 'syminfo_11_tom'. * o The _11_tof & _11_tom results in conversion routines * _2L11_tof, _2L11_tom, _2M11_tof, * _2M11_tom being created in xlate.c. These routines * need to be added to the 'x32[]' array. * o Add entries to getdata.c::align32[] and getdata.c::align64[]. These * tables define what the alignment requirements for a data type are. * * In order to tie a section header type (SHT_*) to a data * structure you need to update elf32_mtype() so that it can * make the association. If you are introducing a new section built * on a basic datatype (SHT_INIT_ARRAY) then this is all the updating * that needs to be done. * * * ELF translation routines * These routines make a subtle implicit assumption. * The file representations of all structures are "packed," * meaning no implicit padding bytes occur. This might not * be the case for the memory representations. Consequently, * the memory representations ALWAYS contain at least as many * bytes as the file representations. Otherwise, the memory * structures would lose information, meaning they're not * implemented properly. * * The words above apply to structures with the same members. * If a future version changes the number of members, the * relative structure sizes for different version must be * tested with the compiler. */ #define HI32 0x80000000UL #define LO31 0x7fffffffUL /* * These macros create indexes for accessing the bytes of * words and halfwords for ELFCLASS32 data representations * (currently ELFDATA2LSB and ELFDATA2MSB). In all cases, * * w = (((((X_3 << 8) + X_2) << 8) + X_1) << 8) + X_0 * h = (X_1 << 8) + X_0 * * These assume the file representations for Addr, Off, * Sword, and Word use 4 bytes, but the memory def's for * the types may differ. * * Naming convention: * ..._L ELFDATA2LSB * ..._M ELFDATA2MSB * * enuma_*(n) define enum names for addr n * enumb_*(n) define enum names for byte n * enumh_*(n) define enum names for half n * enumo_*(n) define enum names for off n * enumw_*(n) define enum names for word n * enuml_*(n) define enum names for Lword n * tofa(d,s,n) xlate addr n from mem s to file d * tofb(d,s,n) xlate byte n from mem s to file d * tofh(d,s,n) xlate half n from mem s to file d * tofo(d,s,n) xlate off n from mem s to file d * tofw(d,s,n) xlate word n from mem s to file d * tofl(d,s,n) xlate Lword n from mem s to file d * toma(s,n) xlate addr n from file s to expression value * tomb(s,n) xlate byte n from file s to expression value * tomh(s,n) xlate half n from file s to expression value * tomo(s,n) xlate off n from file s to expression value * tomw(s,n) xlate word n from file s to expression value * toml(s,n) xlate Lword n from file s to expression value * * tof*() macros must move a multi-byte value into a temporary * because ``in place'' conversions are allowed. If a temp is not * used for multi-byte objects, storing an initial destination byte * may clobber a source byte not yet examined. * * tom*() macros compute an expression value from the source * without touching the destination; so they're safe. */ define(enuma_L, `$1_L0, $1_L1, $1_L2, $1_L3')dnl define(enuma_M, `$1_M3, $1_M2, $1_M1, $1_M0')dnl define(enumb_L, `$1_L')dnl define(enumb_M, `$1_M')dnl define(enumh_L, `$1_L0, $1_L1')dnl define(enumh_M, `$1_M1, $1_M0')dnl define(enumo_L, `$1_L0, $1_L1, $1_L2, $1_L3')dnl define(enumo_M, `$1_M3, $1_M2, $1_M1, $1_M0')dnl define(enumw_L, `$1_L0, $1_L1, $1_L2, $1_L3')dnl define(enumw_M, `$1_M3, $1_M2, $1_M1, $1_M0')dnl define(enuml_L, `$1_L0, $1_L1, $1_L2, $1_L3, $1_L4, $1_L5, $1_L6, $1_L7')dnl define(enuml_M, `$1_M7, $1_M6, $1_M5, $1_M4, $1_M3, $1_M2, $1_M1, $1_M0')dnl define(tofa, `{ register Elf32_Addr _t_ = $2; ($1)[$3`'0] = (unsigned char)_t_, ($1)[$3`'1] = (unsigned char)(_t_>>8), ($1)[$3`'2] = (unsigned char)(_t_>>16), ($1)[$3`'3] = (unsigned char)(_t_>>24); }')dnl define(tofb, `($1)[$3] = (unsigned char)($2)')dnl define(tofh, `{ register Elf32_Half _t_ = $2; ($1)[$3`'0] = (unsigned char)_t_, ($1)[$3`'1] = (unsigned char)(_t_>>8); }')dnl define(tofo, `{ register Elf32_Off _t_ = $2; ($1)[$3`'0] = (unsigned char)_t_, ($1)[$3`'1] = (unsigned char)(_t_>>8), ($1)[$3`'2] = (unsigned char)(_t_>>16), ($1)[$3`'3] = (unsigned char)(_t_>>24); }')dnl define(tofw, `{ register Elf32_Word _t_ = $2; ($1)[$3`'0] = (unsigned char)_t_, ($1)[$3`'1] = (unsigned char)(_t_>>8), ($1)[$3`'2] = (unsigned char)(_t_>>16), ($1)[$3`'3] = (unsigned char)(_t_>>24); }')dnl define(tofl, `{ Elf32_Lword _t_ = $2; ($1)[$3`'0] = (Byte)_t_, ($1)[$3`'1] = (Byte)(_t_>>8), ($1)[$3`'2] = (Byte)(_t_>>16), ($1)[$3`'3] = (Byte)(_t_>>24), ($1)[$3`'4] = (Byte)(_t_>>32), ($1)[$3`'5] = (Byte)(_t_>>40), ($1)[$3`'6] = (Byte)(_t_>>48), ($1)[$3`'7] = (Byte)(_t_>>56); }')dnl define(toma, `(((((((Elf32_Addr)($1)[$2`'3]<<8) +($1)[$2`'2])<<8) +($1)[$2`'1])<<8) +($1)[$2`'0])')dnl define(tomb, `((unsigned char)($1)[$2])')dnl define(tomh, `(((Elf32_Half)($1)[$2`'1]<<8)+($1)[$2`'0])')dnl define(tomo, `(((((((Elf32_Off)($1)[$2`'3]<<8) +($1)[$2`'2])<<8) +($1)[$2`'1])<<8) +($1)[$2`'0])')dnl define(tomw, `(((((((Elf32_Word)($1)[$2`'3]<<8) +($1)[$2`'2])<<8) +($1)[$2`'1])<<8) +($1)[$2`'0])')dnl define(toml, `(((((((((((((((Elf32_Lword)($1)[$2`'7]<<8) +($1)[$2`'6])<<8) +($1)[$2`'5])<<8) +($1)[$2`'4])<<8) +($1)[$2`'3])<<8) +($1)[$2`'2])<<8) +($1)[$2`'1])<<8) +($1)[$2`'0])')dnl /* * ELF data object indexes * The enums are broken apart to get around deficiencies * in some compilers. */ define(Addr, ` enum { enuma_$1(A)`'ifelse(`$2', `', `', `, A_sizeof') };') Addr(L) Addr(M,1) define(Half, ` enum { enumh_$1(H)`'ifelse(`$2', `', `', `, H_sizeof') };') Half(L) Half(M,1) define(Lword, ` enum { enuml_$1(L)`'ifelse(`$2', `', `', `, L_sizeof') };') Lword(L) Lword(M,1) define(Move_1, ` enum { enuml_$1(M1_value), enumw_$1(M1_info), enumw_$1(M1_poffset), enumh_$1(M1_repeat), enumh_$1(M1_stride)`'ifelse(`$2', `', `', `, M1_sizeof') };') Move_1(L) Move_1(M,1) define(MoveP_1, ` enum { enuml_$1(MP1_value), enumw_$1(MP1_info), enumw_$1(MP1_poffset), enumh_$1(MP1_repeat), enumh_$1(MP1_stride), enumw_$1(MP1_padding)`'ifelse(`$2', `', `', `, MP1_sizeof') };') MoveP_1(L) MoveP_1(M,1) define(Off, ` enum { enumo_$1(O)`'ifelse(`$2', `', `', `, O_sizeof') };') Off(L) Off(M,1) define(Word, ` enum { enumw_$1(W)`'ifelse(`$2', `', `', `, W_sizeof') };') Word(L) Word(M,1) define(Dyn_1, ` enum { enumw_$1(D1_tag), enumw_$1(D1_val)`'ifelse(`$2', `', `', `, D1_sizeof') };') Dyn_1(L) Dyn_1(M,1) #define E1_Nident 16 define(Ehdr_1, ` enum { ifelse(`$2', `', `E1_ident, ')E1_ident_$1_Z = E1_Nident - 1, enumh_$1(E1_type), enumh_$1(E1_machine), enumw_$1(E1_version), enuma_$1(E1_entry), enumo_$1(E1_phoff), enumo_$1(E1_shoff), enumw_$1(E1_flags), enumh_$1(E1_ehsize), enumh_$1(E1_phentsize), enumh_$1(E1_phnum), enumh_$1(E1_shentsize), enumh_$1(E1_shnum), enumh_$1(E1_shstrndx)`'ifelse(`$2', `', `', `, E1_sizeof') };') Ehdr_1(L) Ehdr_1(M,1) define(Nhdr_1, ` enum { enumw_$1(N1_namesz), enumw_$1(N1_descsz), enumw_$1(N1_type)`'ifelse(`$2', `', `', `, N1_sizeof') };') Nhdr_1(L) Nhdr_1(M,1) define(Phdr_1, ` enum { enumw_$1(P1_type), enumo_$1(P1_offset), enuma_$1(P1_vaddr), enuma_$1(P1_paddr), enumw_$1(P1_filesz), enumw_$1(P1_memsz), enumw_$1(P1_flags), enumw_$1(P1_align)`'ifelse(`$2', `', `', `, P1_sizeof') };') Phdr_1(L) Phdr_1(M,1) define(Rel_1, ` enum { enuma_$1(R1_offset), enumw_$1(R1_info)`'ifelse(`$2', `', `', `, R1_sizeof') };') Rel_1(L) Rel_1(M,1) define(Rela_1, ` enum { enuma_$1(RA1_offset), enumw_$1(RA1_info), enumw_$1(RA1_addend)`'ifelse(`$2', `', `', `, RA1_sizeof') };') Rela_1(L) Rela_1(M,1) define(Shdr_1, ` enum { enumw_$1(SH1_name), enumw_$1(SH1_type), enumw_$1(SH1_flags), enuma_$1(SH1_addr), enumo_$1(SH1_offset), enumw_$1(SH1_size), enumw_$1(SH1_link), enumw_$1(SH1_info), enumw_$1(SH1_addralign), enumw_$1(SH1_entsize)`'ifelse(`$2', `', `', `, SH1_sizeof') };') Shdr_1(L) Shdr_1(M,1) define(Sym_1, ` enum { enumw_$1(ST1_name), enuma_$1(ST1_value), enumw_$1(ST1_size), enumb_$1(ST1_info), enumb_$1(ST1_other), enumh_$1(ST1_shndx)`'ifelse(`$2', `', `', `, ST1_sizeof') };') Sym_1(L) Sym_1(M,1) define(Syminfo_1, ` enum { enumh_$1(SI1_boundto), enumh_$1(SI1_flags)`'ifelse(`$2', `', `', `, SI1_sizeof') };') Syminfo_1(L) Syminfo_1(M,1) define(Cap_1, ` enum { enumw_$1(C1_tag), enumw_$1(C1_val)`'ifelse(`$2', `', `', `, C1_sizeof') };') Cap_1(L) Cap_1(M,1) define(Verdef_1, ` enum { enumh_$1(VD1_version), enumh_$1(VD1_flags), enumh_$1(VD1_ndx), enumh_$1(VD1_cnt), enumw_$1(VD1_hash), enumw_$1(VD1_aux), enumw_$1(VD1_next)`'ifelse(`$2', `', `', `, VD1_sizeof') };') Verdef_1(L) Verdef_1(M,1) define(Verdaux_1, ` enum { enuma_$1(VDA1_name), enumw_$1(VDA1_next)`'ifelse(`$2', `', `', `, VDA1_sizeof') };') Verdaux_1(L) Verdaux_1(M,1) define(Verneed_1, ` enum { enumh_$1(VN1_version), enumh_$1(VN1_cnt), enuma_$1(VN1_file), enumw_$1(VN1_aux), enumw_$1(VN1_next)`'ifelse(`$2', `', `', `, VN1_sizeof') };') Verneed_1(L) Verneed_1(M,1) define(Vernaux_1, ` enum { enumw_$1(VNA1_hash), enumh_$1(VNA1_flags), enumh_$1(VNA1_other), enuma_$1(VNA1_name), enumw_$1(VNA1_next)`'ifelse(`$2', `', `', `, VNA1_sizeof') };') Vernaux_1(L) Vernaux_1(M,1) /* * Translation function declarations. * * __tof * __tom * where * 2L ELFDATA2LSB * 2M ELFDATA2MSB */ static void addr_2L_tof(), addr_2L_tom(), addr_2M_tof(), addr_2M_tom(), byte_to(), dyn_2L11_tof(), dyn_2L11_tom(), dyn_2M11_tof(), dyn_2M11_tom(), ehdr_2L11_tof(), ehdr_2L11_tom(), ehdr_2M11_tof(), ehdr_2M11_tom(), half_2L_tof(), half_2L_tom(), half_2M_tof(), half_2M_tom(), move_2L11_tof(), move_2L11_tom(), move_2M11_tof(), move_2M11_tom(), movep_2L11_tof(), movep_2L11_tom(), movep_2M11_tof(), movep_2M11_tom(), off_2L_tof(), off_2L_tom(), off_2M_tof(), off_2M_tom(), note_2L11_tof(), note_2L11_tom(), note_2M11_tof(), note_2M11_tom(), phdr_2L11_tof(), phdr_2L11_tom(), phdr_2M11_tof(), phdr_2M11_tom(), rel_2L11_tof(), rel_2L11_tom(), rel_2M11_tof(), rel_2M11_tom(), rela_2L11_tof(), rela_2L11_tom(), rela_2M11_tof(), rela_2M11_tom(), shdr_2L11_tof(), shdr_2L11_tom(), shdr_2M11_tof(), shdr_2M11_tom(), sword_2L_tof(), sword_2L_tom(), sword_2M_tof(), sword_2M_tom(), sym_2L11_tof(), sym_2L11_tom(), sym_2M11_tof(), sym_2M11_tom(), syminfo_2L11_tof(), syminfo_2L11_tom(), syminfo_2M11_tof(), syminfo_2M11_tom(), word_2L_tof(), word_2L_tom(), word_2M_tof(), word_2M_tom(), verdef_2L11_tof(), verdef_2L11_tom(), verdef_2M11_tof(), verdef_2M11_tom(), verneed_2L11_tof(), verneed_2L11_tom(), verneed_2M11_tof(), verneed_2M11_tom(), cap_2L11_tof(), cap_2L11_tom(), cap_2M11_tof(), cap_2M11_tom(); /* x32 [dst_version - 1] [src_version - 1] [encode - 1] [type] */ static struct { void (*x_tof)(), (*x_tom)(); } x32 [EV_CURRENT] [EV_CURRENT] [ELFDATANUM - 1] [ELF_T_NUM] = { { { { /* [1-1][1-1][2LSB-1][.] */ /* BYTE */ { byte_to, byte_to }, /* ADDR */ { addr_2L_tof, addr_2L_tom }, /* DYN */ { dyn_2L11_tof, dyn_2L11_tom }, /* EHDR */ { ehdr_2L11_tof, ehdr_2L11_tom }, /* HALF */ { half_2L_tof, half_2L_tom }, /* OFF */ { off_2L_tof, off_2L_tom }, /* PHDR */ { phdr_2L11_tof, phdr_2L11_tom }, /* RELA */ { rela_2L11_tof, rela_2L11_tom }, /* REL */ { rel_2L11_tof, rel_2L11_tom }, /* SHDR */ { shdr_2L11_tof, shdr_2L11_tom }, /* SWORD */ { sword_2L_tof, sword_2L_tom }, /* SYM */ { sym_2L11_tof, sym_2L11_tom }, /* WORD */ { word_2L_tof, word_2L_tom }, /* VERDEF */ { verdef_2L11_tof, verdef_2L11_tom}, /* VERNEED */ { verneed_2L11_tof, verneed_2L11_tom}, /* SXWORD */ { 0, 0 }, /* illegal 32-bit op */ /* XWORD */ { 0, 0 }, /* illegal 32-bit op */ /* SYMINFO */ { syminfo_2L11_tof, syminfo_2L11_tom }, /* NOTE */ { note_2L11_tof, note_2L11_tom }, /* MOVE */ { move_2L11_tof, move_2L11_tom }, /* MOVEP */ { movep_2L11_tof, movep_2L11_tom }, /* CAP */ { cap_2L11_tof, cap_2L11_tom }, }, { /* [1-1][1-1][2MSB-1][.] */ /* BYTE */ { byte_to, byte_to }, /* ADDR */ { addr_2M_tof, addr_2M_tom }, /* DYN */ { dyn_2M11_tof, dyn_2M11_tom }, /* EHDR */ { ehdr_2M11_tof, ehdr_2M11_tom }, /* HALF */ { half_2M_tof, half_2M_tom }, /* OFF */ { off_2M_tof, off_2M_tom }, /* PHDR */ { phdr_2M11_tof, phdr_2M11_tom }, /* RELA */ { rela_2M11_tof, rela_2M11_tom }, /* REL */ { rel_2M11_tof, rel_2M11_tom }, /* SHDR */ { shdr_2M11_tof, shdr_2M11_tom }, /* SWORD */ { sword_2M_tof, sword_2M_tom }, /* SYM */ { sym_2M11_tof, sym_2M11_tom }, /* WORD */ { word_2M_tof, word_2M_tom }, /* VERDEF */ { verdef_2M11_tof, verdef_2M11_tom}, /* VERNEED */ { verneed_2M11_tof, verneed_2M11_tom}, /* SXWORD */ { 0, 0 }, /* illegal 32-bit op */ /* XWORD */ { 0, 0 }, /* illegal 32-bit op */ /* SYMINFO */ { syminfo_2M11_tof, syminfo_2M11_tom }, /* NOTE */ { note_2M11_tof, note_2M11_tom }, /* MOVE */ { move_2M11_tof, move_2M11_tom }, /* MOVEP */ { movep_2M11_tof, movep_2M11_tom }, /* CAP */ { cap_2M11_tof, cap_2M11_tom }, }, }, }, }; /* * size [version - 1] [type] */ static const struct { size_t s_filesz, s_memsz; } fmsize [EV_CURRENT] [ELF_T_NUM] = { { /* [1-1][.] */ /* BYTE */ { 1, 1 }, /* ADDR */ { A_sizeof, sizeof (Elf32_Addr) }, /* DYN */ { D1_sizeof, sizeof (Elf32_Dyn) }, /* EHDR */ { E1_sizeof, sizeof (Elf32_Ehdr) }, /* HALF */ { H_sizeof, sizeof (Elf32_Half) }, /* OFF */ { O_sizeof, sizeof (Elf32_Off) }, /* PHDR */ { P1_sizeof, sizeof (Elf32_Phdr) }, /* RELA */ { RA1_sizeof, sizeof (Elf32_Rela) }, /* REL */ { R1_sizeof, sizeof (Elf32_Rel) }, /* SHDR */ { SH1_sizeof, sizeof (Elf32_Shdr) }, /* SWORD */ { W_sizeof, sizeof (Elf32_Sword) }, /* SYM */ { ST1_sizeof, sizeof (Elf32_Sym) }, /* WORD */ { W_sizeof, sizeof (Elf32_Word) }, /* VERDEF */ { 1, 1}, /* because bot VERDEF & VERNEED have varying */ /* VERNEED */ { 1, 1}, /* sized structures we set their sizes */ /* to 1 byte */ /* SXWORD */ { 0, 0 }, /* illegal 32-bit op */ /* XWORD */ { 0, 0 }, /* illegal 32-bit op */ /* SYMINFO */ { SI1_sizeof, sizeof (Elf32_Syminfo) }, /* NOTE */ { 1, 1}, /* NOTE has varying sized data we can't */ /* use the usual table magic. */ /* MOVE */ { M1_sizeof, sizeof (Elf32_Move) }, /* MOVEP */ { MP1_sizeof, sizeof (Elf32_Move) }, /* CAP */ { C1_sizeof, sizeof (Elf32_Cap) }, }, }; /* * memory type [version - 1] [section type] */ static const Elf_Type mtype[EV_CURRENT][SHT_NUM] = { { /* [1-1][.] */ /* NULL */ ELF_T_BYTE, /* PROGBITS */ ELF_T_BYTE, /* SYMTAB */ ELF_T_SYM, /* STRTAB */ ELF_T_BYTE, /* RELA */ ELF_T_RELA, /* HASH */ ELF_T_WORD, /* DYNAMIC */ ELF_T_DYN, /* NOTE */ ELF_T_NOTE, /* NOBITS */ ELF_T_BYTE, /* REL */ ELF_T_REL, /* SHLIB */ ELF_T_BYTE, /* DYNSYM */ ELF_T_SYM, /* UNKNOWN12 */ ELF_T_BYTE, /* UNKNOWN13 */ ELF_T_BYTE, /* INIT_ARRAY */ ELF_T_ADDR, /* FINI_ARRAY */ ELF_T_ADDR, /* PREINIT_ARRAY */ ELF_T_ADDR, /* GROUP */ ELF_T_WORD, /* SYMTAB_SHNDX */ ELF_T_WORD }, }; size_t elf32_fsize(Elf_Type type, size_t count, unsigned ver) { if (--ver >= EV_CURRENT) { _elf_seterr(EREQ_VER, 0); return (0); } if ((unsigned)type >= ELF_T_NUM) { _elf_seterr(EREQ_TYPE, 0); return (0); } return (fmsize[ver][type].s_filesz * count); } size_t _elf32_msize(Elf_Type type, unsigned ver) { return (fmsize[ver - 1][type].s_memsz); } Elf_Type _elf32_mtype(Elf * elf, Elf32_Word shtype, unsigned ver) { Elf32_Ehdr * ehdr = (Elf32_Ehdr *)elf->ed_ehdr; if (shtype < SHT_NUM) return (mtype[ver - 1][shtype]); switch (shtype) { case SHT_SUNW_symsort: case SHT_SUNW_tlssort: return (ELF_T_WORD); case SHT_SUNW_LDYNSYM: return (ELF_T_SYM); case SHT_SUNW_dof: return (ELF_T_BYTE); case SHT_SUNW_cap: return (ELF_T_CAP); case SHT_SUNW_capchain: return (ELF_T_WORD); case SHT_SUNW_capinfo: return (ELF_T_WORD); case SHT_SUNW_SIGNATURE: return (ELF_T_BYTE); case SHT_SUNW_ANNOTATE: return (ELF_T_BYTE); case SHT_SUNW_DEBUGSTR: return (ELF_T_BYTE); case SHT_SUNW_DEBUG: return (ELF_T_BYTE); case SHT_SUNW_move: /* * 32bit sparc binaries have a padded * MOVE structure. So - return the * appropriate type. */ if ((ehdr->e_machine == EM_SPARC) || (ehdr->e_machine == EM_SPARC32PLUS)) { return (ELF_T_MOVEP); } return (ELF_T_MOVE); case SHT_SUNW_COMDAT: return (ELF_T_BYTE); case SHT_SUNW_syminfo: return (ELF_T_SYMINFO); case SHT_SUNW_verdef: return (ELF_T_VDEF); case SHT_SUNW_verneed: return (ELF_T_VNEED); case SHT_SUNW_versym: return (ELF_T_HALF); }; /* * Check for the sparc specific section types * below. */ if (((ehdr->e_machine == EM_SPARC) || (ehdr->e_machine == EM_SPARC32PLUS) || (ehdr->e_machine == EM_SPARCV9)) && (shtype == SHT_SPARC_GOTDATA)) return (ELF_T_BYTE); /* * Check for the amd64 specific section types * below. */ if ((ehdr->e_machine == EM_AMD64) && (shtype == SHT_AMD64_UNWIND)) return (ELF_T_BYTE); /* * And the default is ELF_T_BYTE - but we should * certainly have caught any sections we know about * above. This is for unknown sections to libelf. */ return (ELF_T_BYTE); } size_t _elf32_entsz(Elf *elf, Elf32_Word shtype, unsigned ver) { Elf_Type ttype; ttype = _elf32_mtype(elf, shtype, ver); return ((ttype == ELF_T_BYTE) ? 0 : fmsize[ver - 1][ttype].s_filesz); } /* * Determine the data encoding used by the current system. */ uint_t _elf_sys_encoding(void) { union { Elf32_Word w; unsigned char c[W_sizeof]; } u; u.w = 0x10203; /*CONSTANTCONDITION*/ if (~(Elf32_Word)0 == -(Elf32_Sword)1 && tomw(u.c, W_L) == 0x10203) return (ELFDATA2LSB); /*CONSTANTCONDITION*/ if (~(Elf32_Word)0 == -(Elf32_Sword)1 && tomw(u.c, W_M) == 0x10203) return (ELFDATA2MSB); /* Not expected to occur */ return (ELFDATANONE); } /* * XX64 This routine is also used to 'version' interactions with Elf64 * applications, but there's no way to figure out if the caller is * asking Elf32 or Elf64 questions, even though it has Elf32 * dependencies. Ick. */ unsigned elf_version(unsigned ver) { register unsigned j; if (ver == EV_NONE) return EV_CURRENT; if (ver > EV_CURRENT) { _elf_seterr(EREQ_VER, 0); return EV_NONE; } (void) mutex_lock(&_elf_globals_mutex); if (_elf_work != EV_NONE) { j = _elf_work; _elf_work = ver; (void) mutex_unlock(&_elf_globals_mutex); return j; } _elf_work = ver; _elf_encode = _elf_sys_encoding(); (void) mutex_unlock(&_elf_globals_mutex); return ver; } static Elf_Data * xlate(Elf_Data *dst, const Elf_Data *src, unsigned encode, int tof) /* tof !0 -> xlatetof */ { size_t cnt, dsz, ssz; unsigned type; unsigned dver, sver; void (*f)(); unsigned _encode; if (dst == 0 || src == 0) return (0); if (--encode >= (ELFDATANUM - 1)) { _elf_seterr(EREQ_ENCODE, 0); return (0); } if ((dver = dst->d_version - 1) >= EV_CURRENT || (sver = src->d_version - 1) >= EV_CURRENT) { _elf_seterr(EREQ_VER, 0); return (0); } if ((type = src->d_type) >= ELF_T_NUM) { _elf_seterr(EREQ_TYPE, 0); return (0); } if (tof) { dsz = fmsize[dver][type].s_filesz; ssz = fmsize[sver][type].s_memsz; f = x32[dver][sver][encode][type].x_tof; } else { dsz = fmsize[dver][type].s_memsz; ssz = fmsize[sver][type].s_filesz; f = x32[dver][sver][encode][type].x_tom; } cnt = src->d_size / ssz; if (dst->d_size < dsz * cnt) { _elf_seterr(EREQ_DSZ, 0); return (0); } ELFACCESSDATA(_encode, _elf_encode) if ((_encode == (encode + 1)) && (dsz == ssz)) { /* * ld(1) frequently produces empty sections (eg. .dynsym, * .dynstr, .symtab, .strtab, etc) so that the initial * output image can be created of the correct size. Later * these sections are filled in with the associated data. * So that we don't have to pre-allocate buffers for * these segments, allow for the src destination to be 0. */ if (src->d_buf && src->d_buf != dst->d_buf) (void) memcpy(dst->d_buf, src->d_buf, src->d_size); dst->d_type = src->d_type; dst->d_size = src->d_size; return (dst); } if (cnt) (*f)(dst->d_buf, src->d_buf, cnt); dst->d_size = dsz * cnt; dst->d_type = src->d_type; return (dst); } Elf_Data * elf32_xlatetof(Elf_Data *dst, const Elf_Data *src, unsigned encode) { return (xlate(dst, src, encode, 1)); } Elf_Data * elf32_xlatetom(Elf_Data *dst, const Elf_Data *src, unsigned encode) { return (xlate(dst, src, encode, 0)); } /* * xlate to file format * * ..._tof(name, data) -- macros * * Recall that the file format must be no larger than the * memory format (equal versions). Use "forward" copy. * All these routines require non-null, non-zero arguments. */ define(addr_tof, ` static void $1(unsigned char *dst, Elf32_Addr *src, size_t cnt) { Elf32_Addr *end = src + cnt; do { tofa(dst, *src, A_$2); dst += A_sizeof; } while (++src < end); }') addr_tof(addr_2L_tof,L) addr_tof(addr_2M_tof,M) static void byte_to(unsigned char *dst, unsigned char *src, size_t cnt) { if (dst != src) (void) memcpy(dst, src, cnt); } define(dyn_11_tof, ` static void $1(unsigned char *dst, Elf32_Dyn *src, size_t cnt) { Elf32_Dyn *end = src + cnt; do { tofw(dst, src->d_tag, D1_tag_$2); tofo(dst, src->d_un.d_val, D1_val_$2); dst += D1_sizeof; } while (++src < end); }') dyn_11_tof(dyn_2L11_tof,L) dyn_11_tof(dyn_2M11_tof,M) define(ehdr_11_tof, ` static void $1(unsigned char *dst, Elf32_Ehdr *src, size_t cnt) { Elf32_Ehdr *end = src + cnt; do { if (&dst[E1_ident] != src->e_ident) (void) memcpy(&dst[E1_ident], src->e_ident, E1_Nident); tofh(dst, src->e_type, E1_type_$2); tofh(dst, src->e_machine, E1_machine_$2); tofw(dst, src->e_version, E1_version_$2); tofa(dst, src->e_entry, E1_entry_$2); tofo(dst, src->e_phoff, E1_phoff_$2); tofo(dst, src->e_shoff, E1_shoff_$2); tofw(dst, src->e_flags, E1_flags_$2); tofh(dst, src->e_ehsize, E1_ehsize_$2); tofh(dst, src->e_phentsize, E1_phentsize_$2); tofh(dst, src->e_phnum, E1_phnum_$2); tofh(dst, src->e_shentsize, E1_shentsize_$2); tofh(dst, src->e_shnum, E1_shnum_$2); tofh(dst, src->e_shstrndx, E1_shstrndx_$2); dst += E1_sizeof; } while (++src < end); }') ehdr_11_tof(ehdr_2L11_tof,L) ehdr_11_tof(ehdr_2M11_tof,M) define(half_tof, ` static void $1(unsigned char *dst, Elf32_Half *src, size_t cnt) { Elf32_Half *end = src + cnt; do { tofh(dst, *src, H_$2); dst += H_sizeof; } while (++src < end); }') half_tof(half_2L_tof,L) half_tof(half_2M_tof,M) define(move_11_tof, ` static void $1(unsigned char *dst, Elf32_Move *src, size_t cnt) { Elf32_Move *end = src + cnt; do { tofl(dst, src->m_value, M1_value_$2); tofw(dst, src->m_info, M1_info_$2); tofw(dst, src->m_poffset, M1_poffset_$2); tofh(dst, src->m_repeat, M1_repeat_$2); tofh(dst, src->m_stride, M1_stride_$2); dst += M1_sizeof; } while (++src < end); }') move_11_tof(move_2L11_tof,L) move_11_tof(move_2M11_tof,M) define(movep_11_tof, ` static void $1(unsigned char *dst, Elf32_Move *src, size_t cnt) { Elf32_Move *end = src + cnt; do { tofl(dst, src->m_value, MP1_value_$2); tofw(dst, src->m_info, MP1_info_$2); tofw(dst, src->m_poffset, MP1_poffset_$2); tofh(dst, src->m_repeat, MP1_repeat_$2); tofh(dst, src->m_stride, MP1_stride_$2); dst += MP1_sizeof; } while (++src < end); }') movep_11_tof(movep_2L11_tof,L) movep_11_tof(movep_2M11_tof,M) define(off_tof, ` static void $1(unsigned char *dst, Elf32_Off *src, size_t cnt) { Elf32_Off *end = src + cnt; do { tofo(dst, *src, O_$2); dst += O_sizeof; } while (++src < end); }') off_tof(off_2L_tof,L) off_tof(off_2M_tof,M) define(note_11_tof, ` static void $1(unsigned char *dst, Elf32_Nhdr *src, size_t cnt) { /* LINTED */ Elf32_Nhdr *end = (Elf32_Nhdr *)((char *)src + cnt); /* * Copy the note data to the source, translating the * length fields. Clip against the size of the actual buffer * to guard against corrupt note data. */ do { Elf32_Word descsz, namesz; /* * cache size of desc & name fields - while rounding * up their size. */ namesz = S_ROUND(src->n_namesz, sizeof (Elf32_Word)); descsz = src->n_descsz; /* * Copy contents of Elf32_Nhdr */ if ((offsetof(Elf32_Nhdr, n_namesz) + sizeof(Elf32_Word) + (char *) src) >= (char *) end) break; tofw(dst, src->n_namesz, N1_namesz_$2); if ((offsetof(Elf32_Nhdr, n_descsz) + sizeof(Elf32_Word) + (char *) src) >= (char *) end) break; tofw(dst, src->n_descsz, N1_descsz_$2); if ((offsetof(Elf32_Nhdr, n_type) + sizeof(Elf32_Word) + (char *) src) >= (char *) end) break; tofw(dst, src->n_type, N1_type_$2); /* * Copy contents of Name field */ dst += N1_sizeof; src++; if ((namesz + (char *) src) > (char *) end) { namesz = (char *) end - (char *) src; if (namesz == 0) break; } (void)memcpy(dst, src, namesz); /* * Copy contents of desc field */ dst += namesz; src = (Elf32_Nhdr *)((uintptr_t)src + namesz); if ((descsz + (char *) src) > (char *) end) { descsz = (char *) end - (char *) src; if (descsz == 0) break; } (void)memcpy(dst, src, descsz); descsz = S_ROUND(descsz, sizeof (Elf32_Word)); dst += descsz; src = (Elf32_Nhdr *)((uintptr_t)src + descsz); } while (src < end); }') note_11_tof(note_2L11_tof,L) note_11_tof(note_2M11_tof,M) define(phdr_11_tof, ` static void $1(unsigned char *dst, Elf32_Phdr *src, size_t cnt) { Elf32_Phdr *end = src + cnt; do { tofw(dst, src->p_type, P1_type_$2); tofo(dst, src->p_offset, P1_offset_$2); tofa(dst, src->p_vaddr, P1_vaddr_$2); tofa(dst, src->p_paddr, P1_paddr_$2); tofw(dst, src->p_filesz, P1_filesz_$2); tofw(dst, src->p_memsz, P1_memsz_$2); tofw(dst, src->p_flags, P1_flags_$2); tofw(dst, src->p_align, P1_align_$2); dst += P1_sizeof; } while (++src < end); }') phdr_11_tof(phdr_2L11_tof,L) phdr_11_tof(phdr_2M11_tof,M) define(rel_11_tof, ` static void $1(unsigned char *dst, Elf32_Rel *src, size_t cnt) { Elf32_Rel *end = src + cnt; do { tofa(dst, src->r_offset, R1_offset_$2); tofw(dst, src->r_info, R1_info_$2); dst += R1_sizeof; } while (++src < end); }') rel_11_tof(rel_2L11_tof,L) rel_11_tof(rel_2M11_tof,M) define(rela_11_tof, ` static void $1(unsigned char *dst, Elf32_Rela *src, size_t cnt) { Elf32_Rela *end = src + cnt; do { tofa(dst, src->r_offset, RA1_offset_$2); tofw(dst, src->r_info, RA1_info_$2); /*CONSTANTCONDITION*/ if (~(Elf32_Word)0 == -(Elf32_Sword)1) { /* 2s comp */ tofw(dst, src->r_addend, RA1_addend_$2); } else { Elf32_Word w; if (src->r_addend < 0) { w = - src->r_addend; w = ~w + 1; } else w = src->r_addend; tofw(dst, w, RA1_addend_$2); } dst += RA1_sizeof; } while (++src < end); }') rela_11_tof(rela_2L11_tof,L) rela_11_tof(rela_2M11_tof,M) define(shdr_11_tof, ` static void $1(unsigned char *dst, Elf32_Shdr *src, size_t cnt) { Elf32_Shdr *end = src + cnt; do { tofw(dst, src->sh_name, SH1_name_$2); tofw(dst, src->sh_type, SH1_type_$2); tofw(dst, src->sh_flags, SH1_flags_$2); tofa(dst, src->sh_addr, SH1_addr_$2); tofo(dst, src->sh_offset, SH1_offset_$2); tofw(dst, src->sh_size, SH1_size_$2); tofw(dst, src->sh_link, SH1_link_$2); tofw(dst, src->sh_info, SH1_info_$2); tofw(dst, src->sh_addralign, SH1_addralign_$2); tofw(dst, src->sh_entsize, SH1_entsize_$2); dst += SH1_sizeof; } while (++src < end); }') shdr_11_tof(shdr_2L11_tof,L) shdr_11_tof(shdr_2M11_tof,M) define(sword_tof, ` static void $1(unsigned char *dst, Elf32_Sword *src, size_t cnt) { Elf32_Sword *end = src + cnt; do { /*CONSTANTCONDITION*/ if (~(Elf32_Word)0 == -(Elf32_Sword)1) { /* 2s comp */ tofw(dst, *src, W_$2); } else { Elf32_Word w; if (*src < 0) { w = - *src; w = ~w + 1; } else w = *src; tofw(dst, w, W_$2); } dst += W_sizeof; } while (++src < end); }') sword_tof(sword_2L_tof,L) sword_tof(sword_2M_tof,M) define(cap_11_tof, ` static void $1(unsigned char *dst, Elf32_Cap *src, size_t cnt) { Elf32_Cap *end = src + cnt; do { tofw(dst, src->c_tag, C1_tag_$2); tofw(dst, src->c_un.c_val, C1_val_$2); dst += C1_sizeof; } while (++src < end); }') cap_11_tof(cap_2L11_tof,L) cap_11_tof(cap_2M11_tof,M) define(syminfo_11_tof, ` static void $1(unsigned char *dst, Elf32_Syminfo *src, size_t cnt) { Elf32_Syminfo *end = src + cnt; do { tofh(dst, src->si_boundto, SI1_boundto_$2); tofh(dst, src->si_flags, SI1_flags_$2); dst += SI1_sizeof; } while (++src < end); }') syminfo_11_tof(syminfo_2L11_tof,L) syminfo_11_tof(syminfo_2M11_tof,M) define(sym_11_tof, ` static void $1(unsigned char *dst, Elf32_Sym *src, size_t cnt) { Elf32_Sym *end = src + cnt; do { tofw(dst, src->st_name, ST1_name_$2); tofa(dst, src->st_value, ST1_value_$2); tofw(dst, src->st_size, ST1_size_$2); tofb(dst, src->st_info, ST1_info_$2); tofb(dst, src->st_other, ST1_other_$2); tofh(dst, src->st_shndx, ST1_shndx_$2); dst += ST1_sizeof; } while (++src < end); }') sym_11_tof(sym_2L11_tof,L) sym_11_tof(sym_2M11_tof,M) define(word_tof, ` static void $1(unsigned char *dst, Elf32_Word *src, size_t cnt) { Elf32_Word *end = src + cnt; do { tofw(dst, *src, W_$2); dst += W_sizeof; } while (++src < end); }') word_tof(word_2L_tof,L) word_tof(word_2M_tof,M) define(verdef_11_tof, ` static void $1(unsigned char *dst, Elf32_Verdef *src, size_t cnt) { /* LINTED */ Elf32_Verdef *end = (Elf32_Verdef *)((char *)src + cnt); do { Elf32_Verdef *next_verdef; Elf32_Verdaux *vaux; Elf32_Half i; unsigned char *vaux_dst; unsigned char *dst_next; /* LINTED */ next_verdef = (Elf32_Verdef *)(src->vd_next ? (char *)src + src->vd_next : (char *)end); dst_next = dst + src->vd_next; /* LINTED */ vaux = (Elf32_Verdaux *)((char *)src + src->vd_aux); vaux_dst = dst + src->vd_aux; /* * Convert auxilary structures */ for (i = 0; i < src->vd_cnt; i++) { Elf32_Verdaux *vaux_next; unsigned char *vaux_dst_next; /* * because our source and destination can be * the same place we need to figure out the next * location now. */ /* LINTED */ vaux_next = (Elf32_Verdaux *)((char *)vaux + vaux->vda_next); vaux_dst_next = vaux_dst + vaux->vda_next; tofa(vaux_dst, vaux->vda_name, VDA1_name_$2); tofw(vaux_dst, vaux->vda_next, VDA1_next_$2); vaux_dst = vaux_dst_next; vaux = vaux_next; } /* * Convert Elf32_Verdef structure. */ tofh(dst, src->vd_version, VD1_version_$2); tofh(dst, src->vd_flags, VD1_flags_$2); tofh(dst, src->vd_ndx, VD1_ndx_$2); tofh(dst, src->vd_cnt, VD1_cnt_$2); tofw(dst, src->vd_hash, VD1_hash_$2); tofw(dst, src->vd_aux, VD1_aux_$2); tofw(dst, src->vd_next, VD1_next_$2); src = next_verdef; dst = dst_next; } while (src < end); }') verdef_11_tof(verdef_2L11_tof, L) verdef_11_tof(verdef_2M11_tof, M) define(verneed_11_tof, ` static void $1(unsigned char *dst, Elf32_Verneed *src, size_t cnt) { /* LINTED */ Elf32_Verneed *end = (Elf32_Verneed *)((char *)src + cnt); do { Elf32_Verneed *next_verneed; Elf32_Vernaux *vaux; Elf32_Half i; unsigned char *vaux_dst; unsigned char *dst_next; /* LINTED */ next_verneed = (Elf32_Verneed *)(src->vn_next ? (char *)src + src->vn_next : (char *)end); dst_next = dst + src->vn_next; /* LINTED */ vaux = (Elf32_Vernaux *)((char *)src + src->vn_aux); vaux_dst = dst + src->vn_aux; /* * Convert auxilary structures first */ for (i = 0; i < src->vn_cnt; i++) { Elf32_Vernaux * vaux_next; unsigned char * vaux_dst_next; /* * because our source and destination can be * the same place we need to figure out the * next location now. */ /* LINTED */ vaux_next = (Elf32_Vernaux *)((char *)vaux + vaux->vna_next); vaux_dst_next = vaux_dst + vaux->vna_next; tofw(vaux_dst, vaux->vna_hash, VNA1_hash_$2); tofh(vaux_dst, vaux->vna_flags, VNA1_flags_$2); tofh(vaux_dst, vaux->vna_other, VNA1_other_$2); tofa(vaux_dst, vaux->vna_name, VNA1_name_$2); tofw(vaux_dst, vaux->vna_next, VNA1_next_$2); vaux_dst = vaux_dst_next; vaux = vaux_next; } /* * Convert Elf32_Verneed structure. */ tofh(dst, src->vn_version, VN1_version_$2); tofh(dst, src->vn_cnt, VN1_cnt_$2); tofa(dst, src->vn_file, VN1_file_$2); tofw(dst, src->vn_aux, VN1_aux_$2); tofw(dst, src->vn_next, VN1_next_$2); src = next_verneed; dst = dst_next; } while (src < end); }') verneed_11_tof(verneed_2L11_tof, L) verneed_11_tof(verneed_2M11_tof, M) /* xlate to memory format * * ..._tom(name, data) -- macros * * Recall that the memory format may be larger than the * file format (equal versions). Use "backward" copy. * All these routines require non-null, non-zero arguments. */ define(addr_tom, ` static void $1(Elf32_Addr *dst, unsigned char *src, size_t cnt) { Elf32_Addr *end = dst; dst += cnt; src += cnt * A_sizeof; while (dst-- > end) { src -= A_sizeof; *dst = toma(src, A_$2); } }') addr_tom(addr_2L_tom,L) addr_tom(addr_2M_tom,M) define(dyn_11_tom, ` static void $1(Elf32_Dyn *dst, unsigned char *src, size_t cnt) { Elf32_Dyn *end = dst + cnt; do { dst->d_tag = tomw(src, D1_tag_$2); dst->d_un.d_val = tomw(src, D1_val_$2); src += D1_sizeof; } while (++dst < end); }') dyn_11_tom(dyn_2L11_tom,L) dyn_11_tom(dyn_2M11_tom,M) define(ehdr_11_tom, ` static void $1(Elf32_Ehdr *dst, unsigned char *src, size_t cnt) { Elf32_Ehdr *end = dst; dst += cnt; src += cnt * E1_sizeof; while (dst-- > end) { src -= E1_sizeof; dst->e_shstrndx = tomh(src, E1_shstrndx_$2); dst->e_shnum = tomh(src, E1_shnum_$2); dst->e_shentsize = tomh(src, E1_shentsize_$2); dst->e_phnum = tomh(src, E1_phnum_$2); dst->e_phentsize = tomh(src, E1_phentsize_$2); dst->e_ehsize = tomh(src, E1_ehsize_$2); dst->e_flags = tomw(src, E1_flags_$2); dst->e_shoff = tomo(src, E1_shoff_$2); dst->e_phoff = tomo(src, E1_phoff_$2); dst->e_entry = toma(src, E1_entry_$2); dst->e_version = tomw(src, E1_version_$2); dst->e_machine = tomh(src, E1_machine_$2); dst->e_type = tomh(src, E1_type_$2); if (dst->e_ident != &src[E1_ident]) (void) memcpy(dst->e_ident, &src[E1_ident], E1_Nident); } }') ehdr_11_tom(ehdr_2L11_tom,L) ehdr_11_tom(ehdr_2M11_tom,M) define(half_tom, ` static void $1(Elf32_Half *dst, unsigned char *src, size_t cnt) { Elf32_Half *end = dst; dst += cnt; src += cnt * H_sizeof; while (dst-- > end) { src -= H_sizeof; *dst = tomh(src, H_$2); } }') half_tom(half_2L_tom,L) half_tom(half_2M_tom,M) define(move_11_tom, ` static void $1(Elf32_Move *dst, unsigned char *src, size_t cnt) { Elf32_Move *end = dst + cnt; do { dst->m_value = toml(src, M1_value_$2); dst->m_info = tomw(src, M1_info_$2); dst->m_poffset = tomw(src, M1_poffset_$2); dst->m_repeat = tomh(src, M1_repeat_$2); dst->m_stride = tomh(src, M1_stride_$2); src += M1_sizeof; } while (++dst < end); }') move_11_tom(move_2L11_tom,L) move_11_tom(move_2M11_tom,M) define(movep_11_tom, ` static void $1(Elf32_Move *dst, unsigned char *src, size_t cnt) { Elf32_Move *end = dst + cnt; do { dst->m_value = toml(src, MP1_value_$2); dst->m_info = tomw(src, MP1_info_$2); dst->m_poffset = tomw(src, MP1_poffset_$2); dst->m_repeat = tomh(src, MP1_repeat_$2); dst->m_stride = tomh(src, MP1_stride_$2); src += MP1_sizeof; } while (++dst < end); }') movep_11_tom(movep_2L11_tom,L) movep_11_tom(movep_2M11_tom,M) define(note_11_tom, ` static void $1(Elf32_Nhdr *dst, unsigned char *src, size_t cnt) { /* LINTED */ Elf32_Nhdr *end = (Elf32_Nhdr *)((char *)dst + cnt); /* * Copy the note data to the destination, translating the * length fields. Clip against the size of the actual buffer * to guard against corrupt note data. */ while (dst < end) { Elf32_Nhdr *nhdr; unsigned char *namestr; void *desc; Elf32_Word field_sz; if ((offsetof(Elf32_Nhdr, n_namesz) + sizeof(Elf32_Word) + (char *) dst) >= (char *) end) break; dst->n_namesz = tomw(src, N1_namesz_$2); if ((offsetof(Elf32_Nhdr, n_descsz) + sizeof(Elf32_Word) + (char *) dst) >= (char *) end) break; dst->n_descsz = tomw(src, N1_descsz_$2); if ((offsetof(Elf32_Nhdr, n_type) + sizeof(Elf32_Word) + (char *) dst) >= (char *) end) break; dst->n_type = tomw(src, N1_type_$2); nhdr = dst; /* LINTED */ dst = (Elf32_Nhdr *)((char *)dst + sizeof (Elf32_Nhdr)); namestr = src + N1_sizeof; field_sz = S_ROUND(nhdr->n_namesz, sizeof (Elf32_Word)); if ((field_sz + (char *) dst) > (char *) end) { field_sz = (char *) end - (char *) dst; if (field_sz == 0) break; } (void)memcpy((void *)dst, namestr, field_sz); desc = namestr + field_sz; /* LINTED */ dst = (Elf32_Nhdr *)((char *)dst + field_sz); field_sz = nhdr->n_descsz; if ((field_sz + (char *) dst) > (char *) end) { field_sz = (char *) end - (char *) dst; if (field_sz == 0) break; } (void)memcpy(dst, desc, field_sz); field_sz = S_ROUND(field_sz, sizeof (Elf32_Word)); /* LINTED */ dst = (Elf32_Nhdr *)((char *)dst + field_sz); src = (unsigned char *)desc + field_sz; } }') note_11_tom(note_2L11_tom,L) note_11_tom(note_2M11_tom,M) define(off_tom, ` static void $1(Elf32_Off *dst, unsigned char *src, size_t cnt) { Elf32_Off *end = dst; dst += cnt; src += cnt * O_sizeof; while (dst-- > end) { src -= O_sizeof; *dst = tomo(src, O_$2); } }') off_tom(off_2L_tom,L) off_tom(off_2M_tom,M) define(phdr_11_tom, ` static void $1(Elf32_Phdr *dst, unsigned char *src, size_t cnt) { Elf32_Phdr *end = dst; dst += cnt; src += cnt * P1_sizeof; while (dst-- > end) { src -= P1_sizeof; dst->p_align = tomw(src, P1_align_$2); dst->p_flags = tomw(src, P1_flags_$2); dst->p_memsz = tomw(src, P1_memsz_$2); dst->p_filesz = tomw(src, P1_filesz_$2); dst->p_paddr = toma(src, P1_paddr_$2); dst->p_vaddr = toma(src, P1_vaddr_$2); dst->p_offset = tomo(src, P1_offset_$2); dst->p_type = tomw(src, P1_type_$2); } }') phdr_11_tom(phdr_2L11_tom,L) phdr_11_tom(phdr_2M11_tom,M) define(rel_11_tom, ` static void $1(Elf32_Rel *dst, unsigned char *src, size_t cnt) { Elf32_Rel *end = dst; dst += cnt; src += cnt * R1_sizeof; while (dst-- > end) { src -= R1_sizeof; dst->r_info = tomw(src, R1_info_$2); dst->r_offset = toma(src, R1_offset_$2); } }') rel_11_tom(rel_2L11_tom,L) rel_11_tom(rel_2M11_tom,M) define(rela_11_tom, ` static void $1(Elf32_Rela *dst, unsigned char *src, size_t cnt) { Elf32_Rela *end = dst; dst += cnt; src += cnt * RA1_sizeof; while (dst-- > end) { src -= RA1_sizeof; /*CONSTANTCONDITION*/ if (~(Elf32_Word)0 == -(Elf32_Sword)1 && /* 2s comp */ ~(~(Elf32_Word)0 >> 1) == HI32) { dst->r_addend = tomw(src, RA1_addend_$2); } else { union { Elf32_Word w; Elf32_Sword sw; } u; if ((u.w = tomw(src, RA1_addend_$2)) & HI32) { u.w |= ~(Elf32_Word)LO31; u.w = ~u.w + 1; u.sw = -u.w; } dst->r_addend = u.sw; } dst->r_info = tomw(src, RA1_info_$2); dst->r_offset = toma(src, RA1_offset_$2); } }') rela_11_tom(rela_2L11_tom,L) rela_11_tom(rela_2M11_tom,M) define(shdr_11_tom, ` static void $1(Elf32_Shdr *dst, unsigned char *src, size_t cnt) { Elf32_Shdr *end = dst; dst += cnt; src += cnt * SH1_sizeof; while (dst-- > end) { src -= SH1_sizeof; dst->sh_entsize = tomw(src, SH1_entsize_$2); dst->sh_addralign = tomw(src, SH1_addralign_$2); dst->sh_info = tomw(src, SH1_info_$2); dst->sh_link = tomw(src, SH1_link_$2); dst->sh_size = tomw(src, SH1_size_$2); dst->sh_offset = tomo(src, SH1_offset_$2); dst->sh_addr = toma(src, SH1_addr_$2); dst->sh_flags = tomw(src, SH1_flags_$2); dst->sh_type = tomw(src, SH1_type_$2); dst->sh_name = tomw(src, SH1_name_$2); } }') shdr_11_tom(shdr_2L11_tom,L) shdr_11_tom(shdr_2M11_tom,M) define(sword_tom, ` static void $1(Elf32_Sword *dst, unsigned char *src, size_t cnt) { Elf32_Sword *end = dst; dst += cnt; src += cnt * W_sizeof; while (dst-- > end) { src -= W_sizeof; /*CONSTANTCONDITION*/ if (~(Elf32_Word)0 == -(Elf32_Sword)1 && /* 2s comp */ ~(~(Elf32_Word)0 >> 1) == HI32) { *dst = tomw(src, W_$2); } else { union { Elf32_Word w; Elf32_Sword sw; } u; if ((u.w = tomw(src, W_$2)) & HI32) { u.w |= ~(Elf32_Word)LO31; u.w = ~u.w + 1; u.sw = -u.w; } *dst = u.sw; } } }') sword_tom(sword_2L_tom,L) sword_tom(sword_2M_tom,M) define(cap_11_tom, ` static void $1(Elf32_Cap *dst, unsigned char *src, size_t cnt) { Elf32_Cap *end = dst + cnt; do { dst->c_tag = tomw(src, C1_tag_$2); dst->c_un.c_val = tomw(src, C1_val_$2); src += C1_sizeof; } while (++dst < end); }') cap_11_tom(cap_2L11_tom,L) cap_11_tom(cap_2M11_tom,M) define(syminfo_11_tom, ` static void $1(Elf32_Syminfo *dst, unsigned char *src, size_t cnt) { Elf32_Syminfo *end = dst; dst += cnt; src += cnt * SI1_sizeof; while (dst-- > end) { src -= SI1_sizeof; dst->si_boundto = tomh(src, SI1_boundto_$2); dst->si_flags = tomh(src, SI1_flags_$2); } }') syminfo_11_tom(syminfo_2L11_tom,L) syminfo_11_tom(syminfo_2M11_tom,M) define(sym_11_tom, ` static void $1(Elf32_Sym *dst, unsigned char *src, size_t cnt) { Elf32_Sym *end = dst; dst += cnt; src += cnt * ST1_sizeof; while (dst-- > end) { src -= ST1_sizeof; dst->st_shndx = tomh(src, ST1_shndx_$2); dst->st_other = tomb(src, ST1_other_$2); dst->st_info = tomb(src, ST1_info_$2); dst->st_size = tomw(src, ST1_size_$2); dst->st_value = toma(src, ST1_value_$2); dst->st_name = tomw(src, ST1_name_$2); } }') sym_11_tom(sym_2L11_tom,L) sym_11_tom(sym_2M11_tom,M) define(word_tom, ` static void $1(Elf32_Word *dst, unsigned char *src, size_t cnt) { Elf32_Word *end = dst; dst += cnt; src += cnt * W_sizeof; while (dst-- > end) { src -= W_sizeof; *dst = tomw(src, W_$2); } }') word_tom(word_2L_tom,L) word_tom(word_2M_tom,M) define(verdef_11_tom, ` static void $1(Elf32_Verdef *dst, unsigned char *src, size_t cnt) { /* LINTED */ Elf32_Verdef *end = (Elf32_Verdef *)((char *)dst + cnt); while (dst < end) { Elf32_Verdaux *vaux; unsigned char *src_vaux; Elf32_Half i; dst->vd_version = tomh(src, VD1_version_$2); dst->vd_flags = tomh(src, VD1_flags_$2); dst->vd_ndx = tomh(src, VD1_ndx_$2); dst->vd_cnt = tomh(src, VD1_cnt_$2); dst->vd_hash = tomw(src, VD1_hash_$2); dst->vd_aux = tomw(src, VD1_aux_$2); dst->vd_next = tomw(src, VD1_next_$2); src_vaux = src + dst->vd_aux; /* LINTED */ vaux = (Elf32_Verdaux*)((char *)dst + dst->vd_aux); for (i = 0; i < dst->vd_cnt; i++) { vaux->vda_name = toma(src_vaux, VDA1_name_$2); vaux->vda_next = toma(src_vaux, VDA1_next_$2); src_vaux += vaux->vda_next; /* LINTED */ vaux = (Elf32_Verdaux *)((char *)vaux + vaux->vda_next); } src += dst->vd_next; /* LINTED */ dst = (Elf32_Verdef *)(dst->vd_next ? (char *)dst + dst->vd_next : (char *)end); } }') verdef_11_tom(verdef_2L11_tom,L) verdef_11_tom(verdef_2M11_tom,M) define(verneed_11_tom, ` static void $1(Elf32_Verneed *dst, unsigned char *src, size_t cnt) { /* LINTED */ Elf32_Verneed *end = (Elf32_Verneed *)((char *)dst + cnt); while (dst < end) { Elf32_Vernaux * vaux; unsigned char * src_vaux; Elf32_Half i; dst->vn_version = tomh(src, VN1_version_$2); dst->vn_cnt = tomh(src, VN1_cnt_$2); dst->vn_file = toma(src, VN1_file_$2); dst->vn_aux = tomw(src, VN1_aux_$2); dst->vn_next = tomw(src, VN1_next_$2); src_vaux = src + dst->vn_aux; /* LINTED */ vaux = (Elf32_Vernaux *)((char *)dst + dst->vn_aux); for (i = 0; i < dst->vn_cnt; i++) { vaux->vna_hash = tomw(src_vaux, VNA1_hash_$2); vaux->vna_flags = tomh(src_vaux, VNA1_flags_$2); vaux->vna_other = tomh(src_vaux, VNA1_other_$2); vaux->vna_name = toma(src_vaux, VNA1_name_$2); vaux->vna_next = tomw(src_vaux, VNA1_next_$2); src_vaux += vaux->vna_next; /* LINTED */ vaux = (Elf32_Vernaux *)((char *)vaux + vaux->vna_next); } src += dst->vn_next; /* LINTED */ dst = (Elf32_Verneed *)(dst->vn_next ? (char *)dst + dst->vn_next : (char *)end); } }') verneed_11_tom(verneed_2L11_tom,L) verneed_11_tom(verneed_2M11_tom,M) /* * 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 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include /* * fmsize: Array used to determine what size the the structures * are (for memory image & file image). * * x64: Translation routines - to file & to memory. * * What must be done when adding a new type for conversion: * * The first question is whether you need a new ELF_T_* type * to be created. If you've introduced a new structure - then * it will need to be described - this is done by: * * o adding a new type ELF_T_* to usr/src/head/libelf.h * o Create a new macro to define the bytes contained in the structure. Take a * look at the 'Syminfo_1' macro defined below. The declarations describe * the structure based off of the field size of each element of the structure. * o Add a entry to the fmsize table for the new ELF_T_* type. * o Create a _11_tof macro. Take a look at 'syminfo_11_tof'. * o Create a _11_tom macro. Take a look at 'syminfo_11_tom'. * o The _11_tof & _11_tom results in conversion routines * _2L11_tof, _2L11_tom, _2M11_tof, * _2M11_tom being created in xlate.c. These routines * need to be added to the 'x64[]' array. * o Add entries to getdata.c::align32[] and getdata.c::align64[]. These * tables define what the alignment requirements for a data type are. * * In order to tie a section header type (SHT_*) to a data * structure you need to update elf64_mtype() so that it can * make the association. If you are introducing a new section built * on a basic datatype (SHT_INIT_ARRAY) then this is all the updating * that needs to be done. * * * ELF translation routines * * These routines make a subtle implicit assumption. * The file representations of all structures are "packed," * meaning no implicit padding bytes occur. This might not * be the case for the memory representations. Consequently, * the memory representations ALWAYS contain at least as many * bytes as the file representations. Otherwise, the memory * structures would lose information, meaning they're not * implemented properly. * * The words above apply to structures with the same members. * If a future version changes the number of members, the * relative structure sizes for different version must be * tested with the compiler. */ #define HI32 0x80000000UL #define LO31 0x7fffffffUL #define HI64 0x8000000000000000ULL #define LO63 0x7fffffffffffffffULL /* * These macros create indexes for accessing the bytes of * words and halfwords for ELFCLASS64 data representations * (currently ELFDATA2LSB and ELFDATA2MSB). In all cases, * * x = ((((((((((((X_7 << 8) + X_6) << 8) + X_5) << 8) + X_4) << 8 * + X_3) << 8) + X_2) << 8) + X_1) << 8) + X_0 * w = (((((X_3 << 8) + X_2) << 8) + X_1) << 8) + X_0 * h = (X_1 << 8) + X_0 * * These assume the file representations for Addr, Off, * Sword, and Word use 4 bytes, but the memory def's for * the types may differ. * * Naming convention: * ..._L ELFDATA2LSB * ..._M ELFDATA2MSB * * enuma_*(n) define enum names for addr n * enumb_*(n) define enum names for byte n * enumh_*(n) define enum names for half n * enumo_*(n) define enum names for off n * enumw_*(n) define enum names for word n * enumx_*(n) define enum names for xword n * enuml_*(n) define enum names for Lword n * tofa(d,s,n) xlate addr n from mem s to file d * tofb(d,s,n) xlate byte n from mem s to file d * tofh(d,s,n) xlate half n from mem s to file d * tofo(d,s,n) xlate off n from mem s to file d * tofw(d,s,n) xlate word n from mem s to file d * tofx(d,s,n) xlate xword n from mem s to file d * tofl(d,s,n) xlate Lword n from mem s to file d * toma(s,n) xlate addr n from file s to expression value * tomb(s,n) xlate byte n from file s to expression value * tomh(s,n) xlate half n from file s to expression value * tomo(s,n) xlate off n from file s to expression value * tomw(s,n) xlate word n from file s to expression value * tomx(s,n) xlate xword n from file s to expression value * toml(s,n) xlate Lword n from file s to expression value * * tof*() macros must move a multi-byte value into a temporary * because ``in place'' conversions are allowed. If a temp is not * used for multi-byte objects, storing an initial destination byte * may clobber a source byte not yet examined. * * tom*() macros compute an expression value from the source * without touching the destination; so they're safe. */ define(enuma_L, `$1_L0, $1_L1, $1_L2, $1_L3, $1_L4, $1_L5, $1_L6, $1_L7')dnl define(enuma_M, `$1_M7, $1_M6, $1_M5, $1_M4, $1_M3, $1_M2, $1_M1, $1_M0')dnl define(enumb_L, `$1_L')dnl define(enumb_M, `$1_M')dnl define(enumh_L, `$1_L0, $1_L1')dnl define(enumh_M, `$1_M1, $1_M0')dnl define(enumo_L, `$1_L0, $1_L1, $1_L2, $1_L3, $1_L4, $1_L5, $1_L6, $1_L7')dnl define(enumo_M, `$1_M7, $1_M6, $1_M5, $1_M4, $1_M3, $1_M2, $1_M1, $1_M0')dnl define(enumw_L, `$1_L0, $1_L1, $1_L2, $1_L3')dnl define(enumw_M, `$1_M3, $1_M2, $1_M1, $1_M0')dnl define(enumx_L, `$1_L0, $1_L1, $1_L2, $1_L3, $1_L4, $1_L5, $1_L6, $1_L7')dnl define(enumx_M, `$1_M7, $1_M6, $1_M5, $1_M4, $1_M3, $1_M2, $1_M1, $1_M0')dnl define(enuml_L, `$1_L0, $1_L1, $1_L2, $1_L3, $1_L4, $1_L5, $1_L6, $1_L7')dnl define(enuml_M, `$1_M7, $1_M6, $1_M5, $1_M4, $1_M3, $1_M2, $1_M1, $1_M0')dnl define(tofa, `{ Elf64_Addr _t_ = $2; ($1)[$3`'0] = (Byte)_t_, ($1)[$3`'1] = (Byte)(_t_>>8), ($1)[$3`'2] = (Byte)(_t_>>16), ($1)[$3`'3] = (Byte)(_t_>>24), ($1)[$3`'4] = (Byte)(_t_>>32), ($1)[$3`'5] = (Byte)(_t_>>40), ($1)[$3`'6] = (Byte)(_t_>>48), ($1)[$3`'7] = (Byte)(_t_>>56); }')dnl define(tofb, `($1)[$3] = (Byte)($2)')dnl define(tofh, `{ Elf64_Half _t_ = $2; ($1)[$3`'0] = (Byte)_t_, ($1)[$3`'1] = (Byte)(_t_>>8); }')dnl define(tofo, `{ Elf64_Off _t_ = $2; ($1)[$3`'0] = (Byte)_t_, ($1)[$3`'1] = (Byte)(_t_>>8), ($1)[$3`'2] = (Byte)(_t_>>16), ($1)[$3`'3] = (Byte)(_t_>>24), ($1)[$3`'4] = (Byte)(_t_>>32), ($1)[$3`'5] = (Byte)(_t_>>40), ($1)[$3`'6] = (Byte)(_t_>>48), ($1)[$3`'7] = (Byte)(_t_>>56); }')dnl define(tofw, `{ Elf64_Word _t_ = $2; ($1)[$3`'0] = (Byte)_t_, ($1)[$3`'1] = (Byte)(_t_>>8), ($1)[$3`'2] = (Byte)(_t_>>16), ($1)[$3`'3] = (Byte)(_t_>>24); }')dnl define(tofx, `{ Elf64_Xword _t_ = $2; ($1)[$3`'0] = (Byte)_t_, ($1)[$3`'1] = (Byte)(_t_>>8), ($1)[$3`'2] = (Byte)(_t_>>16), ($1)[$3`'3] = (Byte)(_t_>>24), ($1)[$3`'4] = (Byte)(_t_>>32), ($1)[$3`'5] = (Byte)(_t_>>40), ($1)[$3`'6] = (Byte)(_t_>>48), ($1)[$3`'7] = (Byte)(_t_>>56); }')dnl define(tofl, `{ Elf64_Lword _t_ = $2; ($1)[$3`'0] = (Byte)_t_, ($1)[$3`'1] = (Byte)(_t_>>8), ($1)[$3`'2] = (Byte)(_t_>>16), ($1)[$3`'3] = (Byte)(_t_>>24), ($1)[$3`'4] = (Byte)(_t_>>32), ($1)[$3`'5] = (Byte)(_t_>>40), ($1)[$3`'6] = (Byte)(_t_>>48), ($1)[$3`'7] = (Byte)(_t_>>56); }')dnl define(toma, `(((((((((((((((Elf64_Addr)($1)[$2`'7]<<8) +($1)[$2`'6])<<8) +($1)[$2`'5])<<8) +($1)[$2`'4])<<8) +($1)[$2`'3])<<8) +($1)[$2`'2])<<8) +($1)[$2`'1])<<8) +($1)[$2`'0])')dnl define(tomb, `((Byte)($1)[$2])')dnl define(tomh, `(((Elf64_Half)($1)[$2`'1]<<8)+($1)[$2`'0])')dnl define(tomo, `(((((((((((((((Elf64_Off)($1)[$2`'7]<<8) +($1)[$2`'6])<<8) +($1)[$2`'5])<<8) +($1)[$2`'4])<<8) +($1)[$2`'3])<<8) +($1)[$2`'2])<<8) +($1)[$2`'1])<<8) +($1)[$2`'0])')dnl define(tomw, `(((((((Elf64_Word)($1)[$2`'3]<<8) +($1)[$2`'2])<<8) +($1)[$2`'1])<<8) +($1)[$2`'0])')dnl define(tomx, `(((((((((((((((Elf64_Xword)($1)[$2`'7]<<8) +($1)[$2`'6])<<8) +($1)[$2`'5])<<8) +($1)[$2`'4])<<8) +($1)[$2`'3])<<8) +($1)[$2`'2])<<8) +($1)[$2`'1])<<8) +($1)[$2`'0])')dnl define(toml, `(((((((((((((((Elf64_Lword)($1)[$2`'7]<<8) +($1)[$2`'6])<<8) +($1)[$2`'5])<<8) +($1)[$2`'4])<<8) +($1)[$2`'3])<<8) +($1)[$2`'2])<<8) +($1)[$2`'1])<<8) +($1)[$2`'0])')dnl /* * ELF data object indexes * The enums are broken apart to get around deficiencies * in some compilers. */ define(Addr, ` enum { enuma_$1(A)`'ifelse(`$2', `', `', `, A_sizeof') };') Addr(L) Addr(M,1) define(Half, ` enum { enumh_$1(H)`'ifelse(`$2', `', `', `, H_sizeof') };') Half(L) Half(M,1) define(Lword, ` enum { enuml_$1(L)`'ifelse(`$2', `', `', `, L_sizeof') };') Lword(L) Lword(M,1) define(Move_1, ` enum { enuml_$1(M1_value), enumx_$1(M1_info), enumx_$1(M1_poffset), enumh_$1(M1_repeat), enumh_$1(M1_stride)`'ifelse(`$2', `', `', `, M1_sizeof') };') Move_1(L) Move_1(M,1) define(MoveP_1, ` enum { enuml_$1(MP1_value), enumx_$1(MP1_info), enumx_$1(MP1_poffset), enumh_$1(MP1_repeat), enumh_$1(MP1_stride), enumw_$1(MP1_padding)`'ifelse(`$2', `', `', `, MP1_sizeof') };') MoveP_1(L) MoveP_1(M,1) define(Off, ` enum { enumo_$1(O)`'ifelse(`$2', `', `', `, O_sizeof') };') Off(L) Off(M,1) define(Word, ` enum { enumw_$1(W)`'ifelse(`$2', `', `', `, W_sizeof') };') Word(L) Word(M,1) define(Xword, ` enum { enumx_$1(X)`'ifelse(`$2',`', `', `, X_sizeof') };') Xword(L) Xword(M,1) define(Dyn_1, ` enum { enumx_$1(D1_tag), enumx_$1(D1_val)`'ifelse(`$2', `', `', `, D1_sizeof') };') Dyn_1(L) Dyn_1(M,1) #define E1_Nident 16 define(Ehdr_1, ` enum { ifelse(`$2', `', `E1_ident, ')E1_ident_$1_Z = E1_Nident - 1, enumh_$1(E1_type), enumh_$1(E1_machine), enumw_$1(E1_version), enuma_$1(E1_entry), enumo_$1(E1_phoff), enumo_$1(E1_shoff), enumw_$1(E1_flags), enumh_$1(E1_ehsize), enumh_$1(E1_phentsize), enumh_$1(E1_phnum), enumh_$1(E1_shentsize), enumh_$1(E1_shnum), enumh_$1(E1_shstrndx)`'ifelse(`$2', `', `', `, E1_sizeof') };') Ehdr_1(L) Ehdr_1(M,1) define(Nhdr_1, ` enum { enumw_$1(N1_namesz), enumw_$1(N1_descsz), enumw_$1(N1_type)`'ifelse(`$2', `', `', `, N1_sizeof') };') Nhdr_1(L) Nhdr_1(M,1) define(Phdr_1, ` enum { enumw_$1(P1_type), enumw_$1(P1_flags), enumo_$1(P1_offset), enuma_$1(P1_vaddr), enuma_$1(P1_paddr), enumx_$1(P1_filesz), enumx_$1(P1_memsz), enumx_$1(P1_align)`'ifelse(`$2', `', `', `, P1_sizeof') };') Phdr_1(L) Phdr_1(M,1) define(Rel_1, ` enum { enuma_$1(R1_offset), enumx_$1(R1_info)`'ifelse(`$2', `', `', `, R1_sizeof') };') Rel_1(L) Rel_1(M,1) define(Rela_1, ` enum { enuma_$1(RA1_offset), enumx_$1(RA1_info), enumx_$1(RA1_addend)`'ifelse(`$2', `', `', `, RA1_sizeof') };') Rela_1(L) Rela_1(M,1) define(Shdr_1, ` enum { enumw_$1(SH1_name), enumw_$1(SH1_type), enumx_$1(SH1_flags), enuma_$1(SH1_addr), enumo_$1(SH1_offset), enumx_$1(SH1_size), enumw_$1(SH1_link), enumw_$1(SH1_info), enumx_$1(SH1_addralign), enumx_$1(SH1_entsize)`'ifelse(`$2', `', `', `, SH1_sizeof') };') Shdr_1(L) Shdr_1(M,1) define(Sym_1, ` enum { enumw_$1(ST1_name), enumb_$1(ST1_info), enumb_$1(ST1_other), enumh_$1(ST1_shndx), enuma_$1(ST1_value), enumx_$1(ST1_size)`'ifelse(`$2', `', `', `, ST1_sizeof') };') Sym_1(L) Sym_1(M,1) define(Syminfo_1, ` enum { enumh_$1(SI1_boundto), enumh_$1(SI1_flags)`'ifelse(`$2', `', `', `, SI1_sizeof') };') Syminfo_1(L) Syminfo_1(M,1) define(Cap_1, ` enum { enumx_$1(C1_tag), enumx_$1(C1_val)`'ifelse(`$2', `', `', `, C1_sizeof') };') Cap_1(L) Cap_1(M,1) define(Verdef_1, ` enum { enumh_$1(VD1_version), enumh_$1(VD1_flags), enumh_$1(VD1_ndx), enumh_$1(VD1_cnt), enumw_$1(VD1_hash), enumw_$1(VD1_aux), enumw_$1(VD1_next)`'ifelse(`$2', `', `', `, VD1_sizeof') };') Verdef_1(L) Verdef_1(M,1) define(Verdaux_1, ` enum { enumw_$1(VDA1_name), enumw_$1(VDA1_next)`'ifelse(`$2', `', `', `, VDA1_sizeof') };') Verdaux_1(L) Verdaux_1(M,1) define(Verneed_1, ` enum { enumh_$1(VN1_version), enumh_$1(VN1_cnt), enumw_$1(VN1_file), enumw_$1(VN1_aux), enumw_$1(VN1_next)`'ifelse(`$2', `', `', `, VN1_sizeof') };') Verneed_1(L) Verneed_1(M,1) define(Vernaux_1, ` enum { enumw_$1(VNA1_hash), enumh_$1(VNA1_flags), enumh_$1(VNA1_other), enumw_$1(VNA1_name), enumw_$1(VNA1_next)`'ifelse(`$2', `', `', `, VNA1_sizeof') };') Vernaux_1(L) Vernaux_1(M,1) /* * Translation function declarations. * * __tof * __tom * where * 2L ELFDATA2LSB * 2M ELFDATA2MSB */ static void addr_2L_tof(), addr_2L_tom(), addr_2M_tof(), addr_2M_tom(), byte_to(), dyn_2L11_tof(), dyn_2L11_tom(), dyn_2M11_tof(), dyn_2M11_tom(), ehdr_2L11_tof(), ehdr_2L11_tom(), ehdr_2M11_tof(), ehdr_2M11_tom(), half_2L_tof(), half_2L_tom(), half_2M_tof(), half_2M_tom(), move_2L11_tof(), move_2L11_tom(), move_2M11_tof(), move_2M11_tom(), movep_2L11_tof(), movep_2L11_tom(), movep_2M11_tof(), movep_2M11_tom(), off_2L_tof(), off_2L_tom(), off_2M_tof(), off_2M_tom(), note_2L11_tof(), note_2L11_tom(), note_2M11_tof(), note_2M11_tom(), phdr_2L11_tof(), phdr_2L11_tom(), phdr_2M11_tof(), phdr_2M11_tom(), rel_2L11_tof(), rel_2L11_tom(), rel_2M11_tof(), rel_2M11_tom(), rela_2L11_tof(), rela_2L11_tom(), rela_2M11_tof(), rela_2M11_tom(), shdr_2L11_tof(), shdr_2L11_tom(), shdr_2M11_tof(), shdr_2M11_tom(), sword_2L_tof(), sword_2L_tom(), sword_2M_tof(), sword_2M_tom(), sym_2L11_tof(), sym_2L11_tom(), sym_2M11_tof(), sym_2M11_tom(), syminfo_2L11_tof(), syminfo_2L11_tom(), syminfo_2M11_tof(), syminfo_2M11_tom(), word_2L_tof(), word_2L_tom(), word_2M_tof(), word_2M_tom(), verdef_2L11_tof(), verdef_2L11_tom(), verdef_2M11_tof(), verdef_2M11_tom(), verneed_2L11_tof(), verneed_2L11_tom(), verneed_2M11_tof(), verneed_2M11_tom(), sxword_2L_tof(), sxword_2L_tom(), sxword_2M_tof(), sxword_2M_tom(), xword_2L_tof(), xword_2L_tom(), xword_2M_tof(), xword_2M_tom(), cap_2L11_tof(), cap_2L11_tom(), cap_2M11_tof(), cap_2M11_tom(); /* * x64 [dst_version - 1] [src_version - 1] [encode - 1] [type] */ static struct { void (*x_tof)(), (*x_tom)(); } x64 [EV_CURRENT] [EV_CURRENT] [ELFDATANUM - 1] [ELF_T_NUM] = { { { { /* [1-1][1-1][2LSB-1][.] */ /* BYTE */ { byte_to, byte_to }, /* ADDR */ { addr_2L_tof, addr_2L_tom }, /* DYN */ { dyn_2L11_tof, dyn_2L11_tom }, /* EHDR */ { ehdr_2L11_tof, ehdr_2L11_tom }, /* HALF */ { half_2L_tof, half_2L_tom }, /* OFF */ { off_2L_tof, off_2L_tom }, /* PHDR */ { phdr_2L11_tof, phdr_2L11_tom }, /* RELA */ { rela_2L11_tof, rela_2L11_tom }, /* REL */ { rel_2L11_tof, rel_2L11_tom }, /* SHDR */ { shdr_2L11_tof, shdr_2L11_tom }, /* SWORD */ { sword_2L_tof, sword_2L_tom }, /* SYM */ { sym_2L11_tof, sym_2L11_tom }, /* WORD */ { word_2L_tof, word_2L_tom }, /* VERDEF */ { verdef_2L11_tof, verdef_2L11_tom}, /* VERNEED */ { verneed_2L11_tof, verneed_2L11_tom}, /* SXWORD */ { sxword_2L_tof, sxword_2L_tom }, /* XWORD */ { xword_2L_tof, xword_2L_tom }, /* SYMINFO */ { syminfo_2L11_tof, syminfo_2L11_tom }, /* NOTE */ { note_2L11_tof, note_2L11_tom }, /* MOVE */ { move_2L11_tof, move_2L11_tom }, /* MOVEP */ { movep_2L11_tof, movep_2L11_tom }, /* CAP */ { cap_2L11_tof, cap_2L11_tom }, }, { /* [1-1][1-1][2MSB-1][.] */ /* BYTE */ { byte_to, byte_to }, /* ADDR */ { addr_2M_tof, addr_2M_tom }, /* DYN */ { dyn_2M11_tof, dyn_2M11_tom }, /* EHDR */ { ehdr_2M11_tof, ehdr_2M11_tom }, /* HALF */ { half_2M_tof, half_2M_tom }, /* OFF */ { off_2M_tof, off_2M_tom }, /* PHDR */ { phdr_2M11_tof, phdr_2M11_tom }, /* RELA */ { rela_2M11_tof, rela_2M11_tom }, /* REL */ { rel_2M11_tof, rel_2M11_tom }, /* SHDR */ { shdr_2M11_tof, shdr_2M11_tom }, /* SWORD */ { sword_2M_tof, sword_2M_tom }, /* SYM */ { sym_2M11_tof, sym_2M11_tom }, /* WORD */ { word_2M_tof, word_2M_tom }, /* VERDEF */ { verdef_2M11_tof, verdef_2M11_tom}, /* VERNEED */ { verneed_2M11_tof, verneed_2M11_tom}, /* SXWORD */ { sxword_2M_tof, sxword_2M_tom }, /* XWORD */ { xword_2M_tof, xword_2M_tom }, /* SYMINFO */ { syminfo_2M11_tof, syminfo_2M11_tom }, /* NOTE */ { note_2M11_tof, note_2M11_tom }, /* MOVE */ { move_2M11_tof, move_2M11_tom }, /* MOVEP */ { movep_2M11_tof, movep_2M11_tom }, /* CAP */ { cap_2M11_tof, cap_2M11_tom }, }, }, }, }; /* * size [version - 1] [type] */ static const struct { size_t s_filesz, s_memsz; } fmsize [EV_CURRENT] [ELF_T_NUM] = { { /* [1-1][.] */ /* BYTE */ { 1, 1 }, /* ADDR */ { A_sizeof, sizeof (Elf64_Addr) }, /* DYN */ { D1_sizeof, sizeof (Elf64_Dyn) }, /* EHDR */ { E1_sizeof, sizeof (Elf64_Ehdr) }, /* HALF */ { H_sizeof, sizeof (Elf64_Half) }, /* OFF */ { O_sizeof, sizeof (Elf64_Off) }, /* PHDR */ { P1_sizeof, sizeof (Elf64_Phdr) }, /* RELA */ { RA1_sizeof, sizeof (Elf64_Rela) }, /* REL */ { R1_sizeof, sizeof (Elf64_Rel) }, /* SHDR */ { SH1_sizeof, sizeof (Elf64_Shdr) }, /* SWORD */ { W_sizeof, sizeof (Elf64_Sword) }, /* SYM */ { ST1_sizeof, sizeof (Elf64_Sym) }, /* WORD */ { W_sizeof, sizeof (Elf64_Word) }, /* VERDEF */ { 1, 1 }, /* both VERDEF & VERNEED have varying size */ /* VERNEED */ { 1, 1 }, /* structures so we set their sizes to 1 */ /* SXWORD */ { X_sizeof, sizeof (Elf64_Sxword) }, /* XWORD */ { X_sizeof, sizeof (Elf64_Xword) }, /* SYMINFO */ { SI1_sizeof, sizeof (Elf64_Syminfo) }, /* NOTE */ { 1, 1}, /* NOTE has varying sized data we can't */ /* use the usual table magic. */ /* MOVE */ { M1_sizeof, sizeof (Elf64_Move) }, /* MOVEP */ { MP1_sizeof, sizeof (Elf64_Move) }, /* CAP */ { C1_sizeof, sizeof (Elf64_Cap) }, }, }; /* * memory type [version - 1] [section type] */ static const Elf_Type mtype[EV_CURRENT][SHT_NUM] = { { /* [1-1][.] */ /* NULL */ ELF_T_BYTE, /* PROGBITS */ ELF_T_BYTE, /* SYMTAB */ ELF_T_SYM, /* STRTAB */ ELF_T_BYTE, /* RELA */ ELF_T_RELA, /* HASH */ ELF_T_WORD, /* DYNAMIC */ ELF_T_DYN, /* NOTE */ ELF_T_NOTE, /* NOBITS */ ELF_T_BYTE, /* REL */ ELF_T_REL, /* SHLIB */ ELF_T_BYTE, /* DYNSYM */ ELF_T_SYM, /* UNKNOWN12 */ ELF_T_BYTE, /* UNKNOWN13 */ ELF_T_BYTE, /* INIT_ARRAY */ ELF_T_ADDR, /* FINI_ARRAY */ ELF_T_ADDR, /* PREINIT_ARRAY */ ELF_T_ADDR, /* GROUP */ ELF_T_WORD, /* SYMTAB_SHNDX */ ELF_T_WORD }, }; size_t elf64_fsize(Elf_Type type, size_t count, unsigned ver) { if (--ver >= EV_CURRENT) { _elf_seterr(EREQ_VER, 0); return (0); } if ((unsigned)type >= ELF_T_NUM) { _elf_seterr(EREQ_TYPE, 0); return (0); } return (fmsize[ver][type].s_filesz * count); } size_t _elf64_msize(Elf_Type type, unsigned ver) { return (fmsize[ver - 1][type].s_memsz); } Elf_Type /* ARGSUSED */ _elf64_mtype(Elf * elf, Elf64_Word shtype, unsigned ver) { Elf64_Ehdr * ehdr = (Elf64_Ehdr *)elf->ed_ehdr; if (shtype < SHT_NUM) return (mtype[ver - 1][shtype]); switch (shtype) { case SHT_SUNW_symsort: case SHT_SUNW_tlssort: return (ELF_T_WORD); case SHT_SUNW_LDYNSYM: return (ELF_T_SYM); case SHT_SUNW_dof: return (ELF_T_BYTE); case SHT_SUNW_cap: return (ELF_T_CAP); case SHT_SUNW_capchain: return (ELF_T_WORD); case SHT_SUNW_capinfo: return (ELF_T_XWORD); case SHT_SUNW_SIGNATURE: return (ELF_T_BYTE); case SHT_SUNW_ANNOTATE: return (ELF_T_BYTE); case SHT_SUNW_DEBUGSTR: return (ELF_T_BYTE); case SHT_SUNW_DEBUG: return (ELF_T_BYTE); case SHT_SUNW_move: /* * Right now - the only 64bit binaries I know * about with a move is SPARC - and SPARC * binaries pad the size of the move. */ return (ELF_T_MOVEP); case SHT_SUNW_COMDAT: return (ELF_T_BYTE); case SHT_SUNW_syminfo: return (ELF_T_SYMINFO); case SHT_SUNW_verdef: return (ELF_T_VDEF); case SHT_SUNW_verneed: return (ELF_T_VNEED); case SHT_SUNW_versym: return (ELF_T_HALF); }; /* * Check for the sparc specific section types * below. */ if (((ehdr->e_machine == EM_SPARC) || (ehdr->e_machine == EM_SPARC32PLUS) || (ehdr->e_machine == EM_SPARCV9)) && (shtype == SHT_SPARC_GOTDATA)) return (ELF_T_BYTE); /* * Check for the amd64 specific section types * below. */ if ((ehdr->e_machine == EM_AMD64) && (shtype == SHT_AMD64_UNWIND)) return (ELF_T_BYTE); /* * And the default is ELF_T_BYTE - but we should * certainly have caught any sections we know about * above. This is for unknown sections to libelf. */ return (ELF_T_BYTE); } size_t _elf64_entsz(Elf *elf, Elf64_Word shtype, unsigned ver) { Elf_Type ttype; ttype = _elf64_mtype(elf, shtype, ver); return ((ttype == ELF_T_BYTE) ? 0 : fmsize[ver - 1][ttype].s_filesz); } static Elf_Data * xlate(Elf_Data *dst, const Elf_Data *src, unsigned encode, int tof) /* !0 -> xlatetof */ { size_t cnt, dsz, ssz; unsigned type; unsigned dver, sver; void (*f)(); unsigned _encode; if (dst == 0 || src == 0) return (0); if (--encode >= (ELFDATANUM - 1)) { _elf_seterr(EREQ_ENCODE, 0); return (0); } if ((dver = dst->d_version - 1) >= EV_CURRENT || (sver = src->d_version - 1) >= EV_CURRENT) { _elf_seterr(EREQ_VER, 0); return (0); } if ((type = src->d_type) >= ELF_T_NUM) { _elf_seterr(EREQ_TYPE, 0); return (0); } if (tof) { dsz = fmsize[dver][type].s_filesz; ssz = fmsize[sver][type].s_memsz; f = x64[dver][sver][encode][type].x_tof; } else { dsz = fmsize[dver][type].s_memsz; ssz = fmsize[sver][type].s_filesz; f = x64[dver][sver][encode][type].x_tom; } cnt = src->d_size / ssz; if (dst->d_size < dsz * cnt) { _elf_seterr(EREQ_DSZ, 0); return (0); } ELFACCESSDATA(_encode, _elf_encode) if ((_encode == (encode + 1)) && (dsz == ssz)) { /* * ld(1) frequently produces empty sections (eg. .dynsym, * .dynstr, .symtab, .strtab, etc) so that the initial * output image can be created of the correct size. Later * these sections are filled in with the associated data. * So that we don't have to pre-allocate buffers for * these segments, allow for the src destination to be 0. */ if (src->d_buf && src->d_buf != dst->d_buf) (void) memcpy(dst->d_buf, src->d_buf, src->d_size); dst->d_type = src->d_type; dst->d_size = src->d_size; return (dst); } if (cnt) (*f)(dst->d_buf, src->d_buf, cnt); dst->d_size = dsz * cnt; dst->d_type = src->d_type; return (dst); } Elf_Data * elf64_xlatetof(Elf_Data *dst, const Elf_Data *src, unsigned encode) { return (xlate(dst, src, encode, 1)); } Elf_Data * elf64_xlatetom(Elf_Data *dst, const Elf_Data *src, unsigned encode) { return (xlate(dst, src, encode, 0)); } /* * xlate to file format * * ..._tof(name, data) -- macros * * Recall that the file format must be no larger than the * memory format (equal versions). Use "forward" copy. * All these routines require non-null, non-zero arguments. */ define(addr_tof, ` static void $1(Byte *dst, Elf64_Addr *src, size_t cnt) { Elf64_Addr *end = src + cnt; do { tofa(dst, *src, A_$2); dst += A_sizeof; } while (++src < end); }') addr_tof(addr_2L_tof,L) addr_tof(addr_2M_tof,M) static void byte_to(Byte *dst, Byte *src, size_t cnt) { if (dst != src) (void) memcpy(dst, src, cnt); } define(dyn_11_tof, ` static void $1(Byte *dst, Elf64_Dyn *src, size_t cnt) { Elf64_Dyn *end = src + cnt; do { tofx(dst, src->d_tag, D1_tag_$2); tofx(dst, src->d_un.d_val, D1_val_$2); dst += D1_sizeof; } while (++src < end); }') dyn_11_tof(dyn_2L11_tof,L) dyn_11_tof(dyn_2M11_tof,M) define(ehdr_11_tof, ` static void $1(Byte *dst, Elf64_Ehdr *src, size_t cnt) { Elf64_Ehdr *end = src + cnt; do { if (&dst[E1_ident] != src->e_ident) (void) memcpy(&dst[E1_ident], src->e_ident, E1_Nident); tofh(dst, src->e_type, E1_type_$2); tofh(dst, src->e_machine, E1_machine_$2); tofw(dst, src->e_version, E1_version_$2); tofa(dst, src->e_entry, E1_entry_$2); tofo(dst, src->e_phoff, E1_phoff_$2); tofo(dst, src->e_shoff, E1_shoff_$2); tofw(dst, src->e_flags, E1_flags_$2); tofh(dst, src->e_ehsize, E1_ehsize_$2); tofh(dst, src->e_phentsize, E1_phentsize_$2); tofh(dst, src->e_phnum, E1_phnum_$2); tofh(dst, src->e_shentsize, E1_shentsize_$2); tofh(dst, src->e_shnum, E1_shnum_$2); tofh(dst, src->e_shstrndx, E1_shstrndx_$2); dst += E1_sizeof; } while (++src < end); }') ehdr_11_tof(ehdr_2L11_tof,L) ehdr_11_tof(ehdr_2M11_tof,M) define(half_tof, ` static void $1(Byte *dst, Elf64_Half *src, size_t cnt) { Elf64_Half *end = src + cnt; do { tofh(dst, *src, H_$2); dst += H_sizeof; } while (++src < end); }') half_tof(half_2L_tof,L) half_tof(half_2M_tof,M) define(move_11_tof, ` static void $1(unsigned char *dst, Elf64_Move *src, size_t cnt) { Elf64_Move *end = src + cnt; do { tofl(dst, src->m_value, M1_value_$2); tofw(dst, src->m_info, M1_info_$2); tofw(dst, src->m_poffset, M1_poffset_$2); tofh(dst, src->m_repeat, M1_repeat_$2); tofh(dst, src->m_stride, M1_stride_$2); dst += M1_sizeof; } while (++src < end); }') move_11_tof(move_2L11_tof,L) move_11_tof(move_2M11_tof,M) define(movep_11_tof, ` static void $1(unsigned char *dst, Elf64_Move *src, size_t cnt) { Elf64_Move *end = src + cnt; do { tofl(dst, src->m_value, MP1_value_$2); tofw(dst, src->m_info, MP1_info_$2); tofw(dst, src->m_poffset, MP1_poffset_$2); tofh(dst, src->m_repeat, MP1_repeat_$2); tofh(dst, src->m_stride, MP1_stride_$2); dst += MP1_sizeof; } while (++src < end); }') movep_11_tof(movep_2L11_tof,L) movep_11_tof(movep_2M11_tof,M) define(off_tof, ` static void $1(Byte *dst, Elf64_Off *src, size_t cnt) { Elf64_Off *end = src + cnt; do { tofo(dst, *src, O_$2); dst += O_sizeof; } while (++src < end); }') off_tof(off_2L_tof,L) off_tof(off_2M_tof,M) define(note_11_tof, ` static void $1(unsigned char *dst, Elf64_Nhdr *src, size_t cnt) { /* LINTED */ Elf64_Nhdr *end = (Elf64_Nhdr *)((char *)src + cnt); /* * Copy the note data to the source, translating the * length fields. Clip against the size of the actual buffer * to guard against corrupt note data. */ do { Elf64_Word descsz, namesz; /* * cache size of desc & name fields - while rounding * up their size. */ namesz = S_ROUND(src->n_namesz, sizeof (Elf64_Word)); descsz = src->n_descsz; /* * Copy contents of Elf64_Nhdr */ if ((offsetof(Elf64_Nhdr, n_namesz) + sizeof(Elf64_Word) + (char *) src) >= (char *) end) break; tofw(dst, src->n_namesz, N1_namesz_$2); if ((offsetof(Elf64_Nhdr, n_descsz) + sizeof(Elf64_Word) + (char *) src) >= (char *) end) break; tofw(dst, src->n_descsz, N1_descsz_$2); if ((offsetof(Elf64_Nhdr, n_type) + sizeof(Elf64_Word) + (char *) src) >= (char *) end) break; tofw(dst, src->n_type, N1_type_$2); /* * Copy contents of Name field */ dst += N1_sizeof; src++; if ((namesz + (char *) src) > (char *) end) { namesz = (char *) end - (char *) src; if (namesz == 0) break; } (void)memcpy(dst, src, namesz); /* * Copy contents of desc field */ dst += namesz; src = (Elf64_Nhdr *)((uintptr_t)src + namesz); if ((descsz + (char *) src) > (char *) end) { descsz = (char *) end - (char *) src; if (descsz == 0) break; } (void)memcpy(dst, src, descsz); descsz = S_ROUND(descsz, sizeof (Elf64_Word)); dst += descsz; src = (Elf64_Nhdr *)((uintptr_t)src + descsz); } while (src < end); }') note_11_tof(note_2L11_tof,L) note_11_tof(note_2M11_tof,M) define(phdr_11_tof, ` static void $1(Byte *dst, Elf64_Phdr *src, size_t cnt) { Elf64_Phdr *end = src + cnt; do { tofw(dst, src->p_type, P1_type_$2); tofw(dst, src->p_flags, P1_flags_$2); tofo(dst, src->p_offset, P1_offset_$2); tofa(dst, src->p_vaddr, P1_vaddr_$2); tofa(dst, src->p_paddr, P1_paddr_$2); tofx(dst, src->p_filesz, P1_filesz_$2); tofx(dst, src->p_memsz, P1_memsz_$2); tofx(dst, src->p_align, P1_align_$2); dst += P1_sizeof; } while (++src < end); }') phdr_11_tof(phdr_2L11_tof,L) phdr_11_tof(phdr_2M11_tof,M) define(rel_11_tof, ` static void $1(Byte *dst, Elf64_Rel *src, size_t cnt) { Elf64_Rel *end = src + cnt; do { tofa(dst, src->r_offset, R1_offset_$2); tofx(dst, src->r_info, R1_info_$2); dst += R1_sizeof; } while (++src < end); }') rel_11_tof(rel_2L11_tof,L) rel_11_tof(rel_2M11_tof,M) define(rela_11_tof, ` static void $1(Byte *dst, Elf64_Rela *src, size_t cnt) { Elf64_Rela *end = src + cnt; do { tofa(dst, src->r_offset, RA1_offset_$2); tofx(dst, src->r_info, RA1_info_$2); /*CONSTANTCONDITION*/ if (~(Elf64_Xword)0 == -(Elf64_Sxword)1) { /* 2s comp */ tofx(dst, src->r_addend, RA1_addend_$2); } else { Elf64_Xword w; if (src->r_addend < 0) { w = - src->r_addend; w = ~w + 1; } else w = src->r_addend; tofx(dst, w, RA1_addend_$2); } dst += RA1_sizeof; } while (++src < end); }') rela_11_tof(rela_2L11_tof,L) rela_11_tof(rela_2M11_tof,M) define(shdr_11_tof, ` static void $1(Byte *dst, Elf64_Shdr *src, size_t cnt) { Elf64_Shdr *end = src + cnt; do { tofw(dst, src->sh_name, SH1_name_$2); tofw(dst, src->sh_type, SH1_type_$2); tofx(dst, src->sh_flags, SH1_flags_$2); tofa(dst, src->sh_addr, SH1_addr_$2); tofo(dst, src->sh_offset, SH1_offset_$2); tofx(dst, src->sh_size, SH1_size_$2); tofw(dst, src->sh_link, SH1_link_$2); tofw(dst, src->sh_info, SH1_info_$2); tofx(dst, src->sh_addralign, SH1_addralign_$2); tofx(dst, src->sh_entsize, SH1_entsize_$2); dst += SH1_sizeof; } while (++src < end); }') shdr_11_tof(shdr_2L11_tof,L) shdr_11_tof(shdr_2M11_tof,M) define(sword_tof, ` static void $1(Byte *dst, Elf64_Sword *src, size_t cnt) { Elf64_Sword *end = src + cnt; do { /*CONSTANTCONDITION*/ if (~(Elf64_Word)0 == -(Elf64_Sword)1) { /* 2s comp */ tofw(dst, *src, W_$2); } else { Elf64_Word w; if (*src < 0) { w = - *src; w = ~w + 1; } else w = *src; tofw(dst, w, W_$2); } dst += W_sizeof; } while (++src < end); }') sword_tof(sword_2L_tof,L) sword_tof(sword_2M_tof,M) define(cap_11_tof, ` static void $1(unsigned char *dst, Elf64_Cap *src, size_t cnt) { Elf64_Cap *end = src + cnt; do { tofx(dst, src->c_tag, C1_tag_$2); tofx(dst, src->c_un.c_val, C1_val_$2); dst += C1_sizeof; } while (++src < end); }') cap_11_tof(cap_2L11_tof,L) cap_11_tof(cap_2M11_tof,M) define(syminfo_11_tof, ` static void $1(unsigned char *dst, Elf64_Syminfo *src, size_t cnt) { Elf64_Syminfo *end = src + cnt; do { tofh(dst, src->si_boundto, SI1_boundto_$2); tofh(dst, src->si_flags, SI1_flags_$2); dst += SI1_sizeof; } while (++src < end); }') syminfo_11_tof(syminfo_2L11_tof,L) syminfo_11_tof(syminfo_2M11_tof,M) define(sym_11_tof, ` static void $1(Byte *dst, Elf64_Sym *src, size_t cnt) { Elf64_Sym *end = src + cnt; do { tofw(dst, src->st_name, ST1_name_$2); tofb(dst, src->st_info, ST1_info_$2); tofb(dst, src->st_other, ST1_other_$2); tofh(dst, src->st_shndx, ST1_shndx_$2); tofa(dst, src->st_value, ST1_value_$2); tofx(dst, src->st_size, ST1_size_$2); dst += ST1_sizeof; } while (++src < end); }') sym_11_tof(sym_2L11_tof,L) sym_11_tof(sym_2M11_tof,M) define(word_tof, ` static void $1(Byte *dst, Elf64_Word *src, size_t cnt) { Elf64_Word *end = src + cnt; do { tofw(dst, *src, W_$2); dst += W_sizeof; } while (++src < end); }') word_tof(word_2L_tof,L) word_tof(word_2M_tof,M) define(verdef_11_tof, ` static void $1(Byte *dst, Elf64_Verdef *src, size_t cnt) { /* LINTED */ Elf64_Verdef *end = (Elf64_Verdef *)((Byte *)src + cnt); do { Elf64_Verdef *next_verdef; Elf64_Verdaux *vaux; Elf64_Half i; Byte *vaux_dst; Byte *dst_next; /* LINTED */ next_verdef = (Elf64_Verdef *)(src->vd_next ? (Byte *)src + src->vd_next : (Byte *)end); dst_next = dst + src->vd_next; /* LINTED */ vaux = (Elf64_Verdaux *)((Byte *)src + src->vd_aux); vaux_dst = dst + src->vd_aux; /* * Convert auxilary structures */ for (i = 0; i < src->vd_cnt; i++) { Elf64_Verdaux *vaux_next; Byte *vaux_dst_next; /* * because our source and destination can be * the same place we need to figure out the next * location now. */ /* LINTED */ vaux_next = (Elf64_Verdaux *)((Byte *)vaux + vaux->vda_next); vaux_dst_next = vaux_dst + vaux->vda_next; tofw(vaux_dst, vaux->vda_name, VDA1_name_$2); tofw(vaux_dst, vaux->vda_next, VDA1_next_$2); vaux_dst = vaux_dst_next; vaux = vaux_next; } /* * Convert Elf64_Verdef structure. */ tofh(dst, src->vd_version, VD1_version_$2); tofh(dst, src->vd_flags, VD1_flags_$2); tofh(dst, src->vd_ndx, VD1_ndx_$2); tofh(dst, src->vd_cnt, VD1_cnt_$2); tofw(dst, src->vd_hash, VD1_hash_$2); tofw(dst, src->vd_aux, VD1_aux_$2); tofw(dst, src->vd_next, VD1_next_$2); src = next_verdef; dst = dst_next; } while (src < end); }') verdef_11_tof(verdef_2L11_tof, L) verdef_11_tof(verdef_2M11_tof, M) define(verneed_11_tof, ` static void $1(Byte *dst, Elf64_Verneed *src, size_t cnt) { /* LINTED */ Elf64_Verneed *end = (Elf64_Verneed *)((char *)src + cnt); do { Elf64_Verneed * next_verneed; Elf64_Vernaux * vaux; Elf64_Half i; Byte * vaux_dst; Byte * dst_next; /* LINTED */ next_verneed = (Elf64_Verneed *)(src->vn_next ? (Byte *)src + src->vn_next : (Byte *)end); dst_next = dst + src->vn_next; /* LINTED */ vaux = (Elf64_Vernaux *)((Byte *)src + src->vn_aux); vaux_dst = dst + src->vn_aux; /* * Convert auxilary structures first */ for (i = 0; i < src->vn_cnt; i++) { Elf64_Vernaux *vaux_next; Byte *vaux_dst_next; /* * because our source and destination can be * the same place we need to figure out the * next location now. */ /* LINTED */ vaux_next = (Elf64_Vernaux *)((Byte *)vaux + vaux->vna_next); vaux_dst_next = vaux_dst + vaux->vna_next; tofw(vaux_dst, vaux->vna_hash, VNA1_hash_$2); tofh(vaux_dst, vaux->vna_flags, VNA1_flags_$2); tofh(vaux_dst, vaux->vna_other, VNA1_other_$2); tofw(vaux_dst, vaux->vna_name, VNA1_name_$2); tofw(vaux_dst, vaux->vna_next, VNA1_next_$2); vaux_dst = vaux_dst_next; vaux = vaux_next; } /* * Convert Elf64_Verneed structure. */ tofh(dst, src->vn_version, VN1_version_$2); tofh(dst, src->vn_cnt, VN1_cnt_$2); tofw(dst, src->vn_file, VN1_file_$2); tofw(dst, src->vn_aux, VN1_aux_$2); tofw(dst, src->vn_next, VN1_next_$2); src = next_verneed; dst = dst_next; } while (src < end); }') verneed_11_tof(verneed_2L11_tof, L) verneed_11_tof(verneed_2M11_tof, M) define(sxword_tof, ` static void $1(Byte *dst, Elf64_Sxword *src, size_t cnt) { Elf64_Sxword *end = src + cnt; do { /*CONSTANTCONDITION*/ if (~(Elf64_Xword)0 == -(Elf64_Sxword)1) { /* 2s comp */ tofx(dst, *src, X_$2); } else { /* unknown */ Elf64_Xword w; if (*src < 0) { w = - *src; w = ~w + 1; } else w = *src; tofx(dst, w, X_$2); } dst += X_sizeof; } while (++src < end); }') sxword_tof(sxword_2L_tof,L) sxword_tof(sxword_2M_tof,M) define(xword_tof, ` static void $1(Byte *dst, Elf64_Xword *src, size_t cnt) { Elf64_Xword *end = src + cnt; do { tofx(dst, *src, X_$2); dst += X_sizeof; } while (++src < end); }') xword_tof(xword_2L_tof,L) xword_tof(xword_2M_tof,M) /* * xlate to memory format * * ..._tom(name, data) -- macros * * Recall that the memory format may be larger than the * file format (equal versions). Use "backward" copy. * All these routines require non-null, non-zero arguments. */ define(addr_tom, ` static void $1(Elf64_Addr *dst, Byte *src, size_t cnt) { Elf64_Addr *end = dst; dst += cnt; src += cnt * A_sizeof; while (dst-- > end) { src -= A_sizeof; *dst = toma(src, A_$2); } }') addr_tom(addr_2L_tom,L) addr_tom(addr_2M_tom,M) define(dyn_11_tom, ` static void $1(Elf64_Dyn *dst, Byte *src, size_t cnt) { Elf64_Dyn *end = dst + cnt; do { dst->d_tag = tomx(src, D1_tag_$2); dst->d_un.d_val = tomx(src, D1_val_$2); src += D1_sizeof; } while (++dst < end); }') dyn_11_tom(dyn_2L11_tom,L) dyn_11_tom(dyn_2M11_tom,M) define(ehdr_11_tom, ` static void $1(Elf64_Ehdr *dst, Byte *src, size_t cnt) { Elf64_Ehdr *end = dst; dst += cnt; src += cnt * E1_sizeof; while (dst-- > end) { src -= E1_sizeof; dst->e_shstrndx = tomh(src, E1_shstrndx_$2); dst->e_shnum = tomh(src, E1_shnum_$2); dst->e_shentsize = tomh(src, E1_shentsize_$2); dst->e_phnum = tomh(src, E1_phnum_$2); dst->e_phentsize = tomh(src, E1_phentsize_$2); dst->e_ehsize = tomh(src, E1_ehsize_$2); dst->e_flags = tomw(src, E1_flags_$2); dst->e_shoff = tomo(src, E1_shoff_$2); dst->e_phoff = tomo(src, E1_phoff_$2); dst->e_entry = toma(src, E1_entry_$2); dst->e_version = tomw(src, E1_version_$2); dst->e_machine = tomh(src, E1_machine_$2); dst->e_type = tomh(src, E1_type_$2); if (dst->e_ident != &src[E1_ident]) (void) memcpy(dst->e_ident, &src[E1_ident], E1_Nident); } }') ehdr_11_tom(ehdr_2L11_tom,L) ehdr_11_tom(ehdr_2M11_tom,M) define(half_tom, ` static void $1(Elf64_Half *dst, Byte *src, size_t cnt) { Elf64_Half *end = dst; dst += cnt; src += cnt * H_sizeof; while (dst-- > end) { src -= H_sizeof; *dst = tomh(src, H_$2); } }') half_tom(half_2L_tom,L) half_tom(half_2M_tom,M) define(move_11_tom, ` static void $1(Elf64_Move *dst, unsigned char *src, size_t cnt) { Elf64_Move *end = dst + cnt; do { dst->m_value = toml(src, M1_value_$2); dst->m_info = tomw(src, M1_info_$2); dst->m_poffset = tomw(src, M1_poffset_$2); dst->m_repeat = tomh(src, M1_repeat_$2); dst->m_stride = tomh(src, M1_stride_$2); src += M1_sizeof; } while (++dst < end); }') move_11_tom(move_2L11_tom,L) move_11_tom(move_2M11_tom,M) define(movep_11_tom, ` static void $1(Elf64_Move *dst, unsigned char *src, size_t cnt) { Elf64_Move *end = dst + cnt; do { dst->m_value = toml(src, MP1_value_$2); dst->m_info = tomw(src, MP1_info_$2); dst->m_poffset = tomw(src, MP1_poffset_$2); dst->m_repeat = tomh(src, MP1_repeat_$2); dst->m_stride = tomh(src, MP1_stride_$2); src += MP1_sizeof; } while (++dst < end); }') movep_11_tom(movep_2L11_tom,L) movep_11_tom(movep_2M11_tom,M) define(note_11_tom, ` static void $1(Elf64_Nhdr *dst, unsigned char *src, size_t cnt) { /* LINTED */ Elf64_Nhdr *end = (Elf64_Nhdr *)((char *)dst + cnt); /* * Copy the note data to the destination, translating the * length fields. Clip against the size of the actual buffer * to guard against corrupt note data. */ while (dst < end) { Elf64_Nhdr *nhdr; unsigned char *namestr; void *desc; Elf64_Word field_sz; if ((offsetof(Elf64_Nhdr, n_namesz) + sizeof(Elf64_Word) + (char *) dst) >= (char *) end) break; dst->n_namesz = tomw(src, N1_namesz_$2); if ((offsetof(Elf64_Nhdr, n_descsz) + sizeof(Elf64_Word) + (char *) dst) >= (char *) end) break; dst->n_descsz = tomw(src, N1_descsz_$2); if ((offsetof(Elf64_Nhdr, n_type) + sizeof(Elf64_Word) + (char *) dst) >= (char *) end) break; dst->n_type = tomw(src, N1_type_$2); nhdr = dst; /* LINTED */ dst = (Elf64_Nhdr *)((char *)dst + sizeof (Elf64_Nhdr)); namestr = src + N1_sizeof; field_sz = S_ROUND(nhdr->n_namesz, sizeof (Elf64_Word)); if ((field_sz + (char *) dst) > (char *) end) { field_sz = (char *) end - (char *) dst; if (field_sz == 0) break; } (void)memcpy((void *)dst, namestr, field_sz); desc = namestr + field_sz; /* LINTED */ dst = (Elf64_Nhdr *)((char *)dst + field_sz); field_sz = nhdr->n_descsz; if ((field_sz + (char *) dst) > (char *) end) { field_sz = (char *) end - (char *) dst; if (field_sz == 0) break; } (void)memcpy(dst, desc, field_sz); field_sz = S_ROUND(field_sz, sizeof (Elf64_Word)); /* LINTED */ dst = (Elf64_Nhdr *)((char *)dst + field_sz); src = (unsigned char *)desc + field_sz; } }') note_11_tom(note_2L11_tom,L) note_11_tom(note_2M11_tom,M) define(off_tom, ` static void $1(Elf64_Off *dst, Byte *src, size_t cnt) { Elf64_Off *end = dst; dst += cnt; src += cnt * O_sizeof; while (dst-- > end) { src -= O_sizeof; *dst = tomo(src, O_$2); } }') off_tom(off_2L_tom,L) off_tom(off_2M_tom,M) define(phdr_11_tom, ` static void $1(Elf64_Phdr *dst, Byte *src, size_t cnt) { Elf64_Phdr *end = dst; dst += cnt; src += cnt * P1_sizeof; while (dst-- > end) { src -= P1_sizeof; dst->p_align = tomx(src, P1_align_$2); dst->p_memsz = tomx(src, P1_memsz_$2); dst->p_filesz = tomx(src, P1_filesz_$2); dst->p_paddr = toma(src, P1_paddr_$2); dst->p_vaddr = toma(src, P1_vaddr_$2); dst->p_offset = tomo(src, P1_offset_$2); dst->p_flags = tomw(src, P1_flags_$2); dst->p_type = tomw(src, P1_type_$2); } }') phdr_11_tom(phdr_2L11_tom,L) phdr_11_tom(phdr_2M11_tom,M) define(rel_11_tom, ` static void $1(Elf64_Rel *dst, Byte *src, size_t cnt) { Elf64_Rel *end = dst; dst += cnt; src += cnt * R1_sizeof; while (dst-- > end) { src -= R1_sizeof; dst->r_info = tomx(src, R1_info_$2); dst->r_offset = toma(src, R1_offset_$2); } }') rel_11_tom(rel_2L11_tom,L) rel_11_tom(rel_2M11_tom,M) define(rela_11_tom, ` static void $1(Elf64_Rela *dst, Byte *src, size_t cnt) { Elf64_Rela *end = dst; dst += cnt; src += cnt * RA1_sizeof; while (dst-- > end) { src -= RA1_sizeof; /*CONSTANTCONDITION*/ if (~(Elf64_Xword)0 == -(Elf64_Sxword)1 && /* 2s comp */ ~(~(Elf64_Xword)0 >> 1) == HI64) { dst->r_addend = tomx(src, RA1_addend_$2); } else { union { Elf64_Xword w; Elf64_Sxword sw; } u; if ((u.w = tomx(src, RA1_addend_$2)) & HI64) { /* LINTED */ u.w |= ~(Elf64_Xword)LO63; u.w = ~u.w + 1; u.sw = -u.w; } dst->r_addend = u.sw; } dst->r_info = tomx(src, RA1_info_$2); dst->r_offset = toma(src, RA1_offset_$2); } }') rela_11_tom(rela_2L11_tom,L) rela_11_tom(rela_2M11_tom,M) define(shdr_11_tom, ` static void $1(Elf64_Shdr *dst, Byte *src, size_t cnt) { Elf64_Shdr *end = dst; dst += cnt; src += cnt * SH1_sizeof; while (dst-- > end) { src -= SH1_sizeof; dst->sh_entsize = tomx(src, SH1_entsize_$2); dst->sh_addralign = tomx(src, SH1_addralign_$2); dst->sh_info = tomw(src, SH1_info_$2); dst->sh_link = tomw(src, SH1_link_$2); dst->sh_size = tomx(src, SH1_size_$2); dst->sh_offset = tomo(src, SH1_offset_$2); dst->sh_addr = toma(src, SH1_addr_$2); dst->sh_flags = tomx(src, SH1_flags_$2); dst->sh_type = tomw(src, SH1_type_$2); dst->sh_name = tomw(src, SH1_name_$2); } }') shdr_11_tom(shdr_2L11_tom,L) shdr_11_tom(shdr_2M11_tom,M) define(sword_tom, ` static void $1(Elf64_Sword *dst, Byte *src, size_t cnt) { Elf64_Sword *end = dst; dst += cnt; src += cnt * W_sizeof; while (dst-- > end) { src -= W_sizeof; /*CONSTANTCONDITION*/ if (~(Elf64_Word)0 == -(Elf64_Sword)1 && ~(~(Elf64_Word)0 >> 1) == HI32) { /* 2s comp */ *dst = tomw(src, W_$2); } else { union { Elf64_Word w; Elf64_Sword sw; } u; if ((u.w = tomw(src, W_$2)) & HI32) { u.w |= ~(Elf64_Word)LO31; u.w = ~u.w + 1; u.sw = -u.w; } *dst = u.sw; } } }') sword_tom(sword_2L_tom,L) sword_tom(sword_2M_tom,M) define(cap_11_tom, ` static void $1(Elf64_Cap *dst, unsigned char *src, size_t cnt) { Elf64_Cap *end = dst + cnt; do { dst->c_tag = tomx(src, C1_tag_$2); dst->c_un.c_val = tomx(src, C1_val_$2); src += C1_sizeof; } while (++dst < end); }') cap_11_tom(cap_2L11_tom,L) cap_11_tom(cap_2M11_tom,M) define(syminfo_11_tom, ` static void $1(Elf64_Syminfo *dst, unsigned char *src, size_t cnt) { Elf64_Syminfo *end = dst; dst += cnt; src += cnt * SI1_sizeof; while (dst-- > end) { src -= SI1_sizeof; dst->si_boundto = tomh(src, SI1_boundto_$2); dst->si_flags = tomh(src, SI1_flags_$2); } }') syminfo_11_tom(syminfo_2L11_tom,L) syminfo_11_tom(syminfo_2M11_tom,M) define(sym_11_tom, ` static void $1(Elf64_Sym *dst, Byte *src, size_t cnt) { Elf64_Sym *end = dst; dst += cnt; src += cnt * ST1_sizeof; while (dst-- > end) { src -= ST1_sizeof; dst->st_size = tomx(src, ST1_size_$2); dst->st_value = toma(src, ST1_value_$2); dst->st_shndx = tomh(src, ST1_shndx_$2); dst->st_other = tomb(src, ST1_other_$2); dst->st_info = tomb(src, ST1_info_$2); dst->st_name = tomw(src, ST1_name_$2); } }') sym_11_tom(sym_2L11_tom,L) sym_11_tom(sym_2M11_tom,M) define(word_tom, ` static void $1(Elf64_Word *dst, Byte *src, size_t cnt) { Elf64_Word *end = dst; dst += cnt; src += cnt * W_sizeof; while (dst-- > end) { src -= W_sizeof; *dst = tomw(src, W_$2); } }') word_tom(word_2L_tom,L) word_tom(word_2M_tom,M) define(verdef_11_tom, ` static void $1(Elf64_Verdef *dst, Byte *src, size_t cnt) { /* LINTED */ Elf64_Verdef *end = (Elf64_Verdef *)((Byte *)dst + cnt); while (dst < end) { Elf64_Verdaux *vaux; Byte *src_vaux; Elf64_Half i; dst->vd_version = tomh(src, VD1_version_$2); dst->vd_flags = tomh(src, VD1_flags_$2); dst->vd_ndx = tomh(src, VD1_ndx_$2); dst->vd_cnt = tomh(src, VD1_cnt_$2); dst->vd_hash = tomw(src, VD1_hash_$2); dst->vd_aux = tomw(src, VD1_aux_$2); dst->vd_next = tomw(src, VD1_next_$2); src_vaux = src + dst->vd_aux; /* LINTED */ vaux = (Elf64_Verdaux *)((Byte *)dst + dst->vd_aux); for (i = 0; i < dst->vd_cnt; i++) { vaux->vda_name = tomw(src_vaux, VDA1_name_$2); vaux->vda_next = tomw(src_vaux, VDA1_next_$2); src_vaux += vaux->vda_next; /* LINTED */ vaux = (Elf64_Verdaux *)((Byte *)vaux + vaux->vda_next); } src += dst->vd_next; /* LINTED */ dst = (Elf64_Verdef *)(dst->vd_next ? (Byte *)dst + dst->vd_next : (Byte *)end); } }') verdef_11_tom(verdef_2L11_tom,L) verdef_11_tom(verdef_2M11_tom,M) define(verneed_11_tom, ` static void $1(Elf64_Verneed *dst, Byte *src, size_t cnt) { /* LINTED */ Elf64_Verneed *end = (Elf64_Verneed *)((char *)dst + cnt); while (dst < end) { Elf64_Vernaux * vaux; Byte * src_vaux; Elf64_Half i; dst->vn_version = tomh(src, VN1_version_$2); dst->vn_cnt = tomh(src, VN1_cnt_$2); dst->vn_file = tomw(src, VN1_file_$2); dst->vn_aux = tomw(src, VN1_aux_$2); dst->vn_next = tomw(src, VN1_next_$2); src_vaux = src + dst->vn_aux; /* LINTED */ vaux = (Elf64_Vernaux *)((Byte *)dst + dst->vn_aux); for (i = 0; i < dst->vn_cnt; i++) { vaux->vna_hash = tomw(src_vaux, VNA1_hash_$2); vaux->vna_flags = tomh(src_vaux, VNA1_flags_$2); vaux->vna_other = tomh(src_vaux, VNA1_other_$2); vaux->vna_name = tomw(src_vaux, VNA1_name_$2); vaux->vna_next = tomw(src_vaux, VNA1_next_$2); src_vaux += vaux->vna_next; /* LINTED */ vaux = (Elf64_Vernaux *)((Byte *)vaux + vaux->vna_next); } src += dst->vn_next; /* LINTED */ dst = (Elf64_Verneed *)(dst->vn_next ? (Byte *)dst + dst->vn_next : (Byte *)end); } }') verneed_11_tom(verneed_2L11_tom,L) verneed_11_tom(verneed_2M11_tom,M) define(sxword_tom, ` static void $1(Elf64_Sxword *dst, Byte *src, size_t cnt) { Elf64_Sxword *end = dst; dst += cnt; src += cnt * X_sizeof; while (dst-- > end) { src -= X_sizeof; /*CONSTANTCONDITION*/ if (~(Elf64_Xword)0 == -(Elf64_Sxword)1 && ~(~(Elf64_Xword)0 >> 1) == HI64) { /* 2s comp */ *dst = tomx(src, X_$2); } else { /* other */ union { Elf64_Xword w; Elf64_Sxword sw; } u; if ((u.w = tomx(src, X_$2)) & HI64) { /* LINTED */ u.w |= ~(Elf64_Xword)LO63; u.w = ~u.w + 1; u.sw = -u.w; } *dst = u.sw; } } }') sxword_tom(sxword_2L_tom,L) sxword_tom(sxword_2M_tom,M) define(xword_tom, ` static void $1(Elf64_Xword *dst, Byte *src, size_t cnt) { Elf64_Xword *end = dst; dst += cnt; src += cnt * X_sizeof; while (dst-- > end) { src -= X_sizeof; *dst = tomx(src, X_$2); } }') xword_tom(xword_2L_tom,L) xword_tom(xword_2M_tom,M) # # 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) 1995, 2010, Oracle and/or its affiliates. All rights reserved. # This directory contains sample programs that demonstrate how to use libelf. Manual pages for libelf routines are located in section 3e: Library Functions. Each of these sample programs displays, or manipulates information from a ELF file. Each program uses libelf differently. To learn more about ELF files and their format refer to the "Linker & Libraries Guide", which is part of the "Software Developer Collection", and the "System V Application Binary Interface". The following source files are provided: pcom.c print comment: prints the .comment section of an ELF file. Demonstrates how to examine a file opened with elf_begin(ELF_C_READ) acom.c append comment: appends to, or creates a .comment section within an ELF file. Demonstrates the updating of a file with elf_begin(ELF_C_RDWR) dcom.c delete comment: deletes a .comment section from an ELF file. Demonstrates the creation of a ELF file with elf_begin(ELF_C_WRITE) tpcom.c threaded print comment: a threaded version of pcom.c. Demonstrates that libelf is MT-Safe and can be used by a threaded program. dispsyms.c print symbols: scans a ELF file for any symbol tables (SHT_SYMTAB, SHT_DYNSYM, or SHT_SUNW_LDYNSYM) and displays the symbol tables contents. Makefile make file to build the above programs. Building the demos ------------------ To build the programs: % make all To test the programs: % make test # # 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) 1995, 2010, Oracle and/or its affiliates. All rights reserved. # PROGS= pcom acom dcom tpcom dispsyms LDLIBS= -lelf OBJS= $(PROGS:%=%.o) .KEEP_STATE: all: libobj.a .WAIT $(PROGS) libobj.a: $(OBJS) ar -r $@ $(OBJS) %.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) -c $< mcs -d -a "ELF demo: object comment: $@" $@ %: %.o $(CC) $(CFLAGS) -o $@ $< $(LDLIBS) mcs -d -a "ELF demo: executable comment: $@" $@ test: test1 test2 test3 test4 test5 test6 test1: pcom FRC @ echo "" @ echo "<<< Test 1 >>>" @ echo "Print comments of pcom" pcom pcom @ echo @ echo "Print comments from archive libobj.a" pcom libobj.a test2: dcom pcom FRC @ echo "" @ echo "<<< Test 2 >>>" @ echo "Delete the comment section from pcom" TMPDIR= dcom pcom pcom pcom test3: pcom acom test2 FRC @ echo "" @ echo "<<< Test 3 >>>" @ echo "update comments from pcom and then print them out." acom "Newly Updated Comments" pcom pcom pcom test4: acom pcom test3 FRC @ echo "" @ echo "<<< Test 4 >>>" @ echo "Append to the comment section of pcom." acom "This comment has been appended" pcom pcom pcom test5: $(PROGS) FRC @ echo "" @ echo "<<< Test 5 >>>" @ echo "Relabel the new utilities using the new utilities." TMPDIR= dcom $(PROGS) cp acom acom.safe acom.safe "libelf Demonstration Tools" $(PROGS) pcom $(PROGS) $(RM) acom.safe test6: dispsyms FRC @ echo "" @ echo "<<< Test 6 >>>" @ echo "Display symbols in dispsyms itself." dispsyms dispsyms | egrep -v "LOCL|ABS|SECT|UNDEF" test-extra: tpcom FRC @ echo "" @ echo "<<< Test-extra >>>" @ echo "Using the threaded tpcom, go through and examine all" @ echo "libraries in /lib. This is an output intensive test." tpcom /lib/lib*.so.? clean: FRC $(RM) $(OBJS) $(PROGS) libobj.a core FRC: /* * 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) 1995, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * acom: Append Comment * * This program demonstrates the use of the libelf interface to * modify a ELF file. This program will open an ELF file and * either modify an existing .comment section and/or append * a new .comment section to an existing ELF file. */ #include #include #include #include #include #include #include static const char *CommentStr = ".comment"; static void update_comment(Elf *elf, const char *file, const char *comment) { Elf_Scn *scn = NULL; GElf_Shdr shdr; Elf_Data *data; size_t shstrndx; if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: gelf_getshdrstrdx() failed: %s\n", file, elf_errmsg(0)); return; } while ((scn = elf_nextscn(elf, scn)) != NULL) { /* * Do a string compare to examine each section header * to see if it is a ".comment" section. If it is then * this is the section we want to process. */ if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } if (strcmp(CommentStr, elf_strptr(elf, shstrndx, shdr.sh_name)) == 0) break; } if (scn == NULL) { int ndx; (void) printf("%s has no .comment section. " "Creating one...\n", file); /* * First add the ".comment" string to the string table */ if ((scn = elf_getscn(elf, shstrndx)) == NULL) { (void) fprintf(stderr, "%s: elf_getscn() failed: %s\n", file, elf_errmsg(0)); return; } if ((data = elf_getdata(scn, NULL)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); return; } ndx = data->d_off + data->d_size; if ((data = elf_newdata(scn)) == NULL) { (void) fprintf(stderr, "%s: elf_newdata() failed: %s\n", file, elf_errmsg(0)); return; } data->d_buf = (void *)CommentStr; data->d_size = strlen(CommentStr) + 1; data->d_align = 1; /* * Add the ".comment" section to the end of the file. * Initialize the fields in the Section Header that * libelf will not fill in. */ if ((scn = elf_newscn(elf)) == NULL) { (void) fprintf(stderr, "%s: elf_newscn() failed: %s\n", file, elf_errmsg(0)); return; } if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } shdr.sh_name = ndx; shdr.sh_type = SHT_PROGBITS; shdr.sh_flags = 0; shdr.sh_addr = 0; shdr.sh_link = 0; shdr.sh_info = 0; /* * Flush the changes to the underlying elf32 or elf64 * section header. */ (void) gelf_update_shdr(scn, &shdr); } if (shdr.sh_addr != 0) { (void) printf("%s: .comment section is part of a " "loadable segment, it cannot be changed.\n", file); return; } if ((data = elf_newdata(scn)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); return; } data->d_buf = (void *)comment; data->d_size = strlen(comment) + 1; data->d_align = 1; if (elf_update(elf, ELF_C_WRITE) == -1) (void) fprintf(stderr, "%s: elf_update() failed: %s\n", file, elf_errmsg(0)); } int main(int argc, char **argv) { int i; char *new_comment; if (argc < 3) { (void) printf("usage: %s elf_file ...\n", argv[0]); return (1); } /* * Initialize the elf library, must be called before elf_begin() * can be called. */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } /* * The new comment is passed in through the command line. * This string will be used to update the .comment section of * the specified ELF files. */ new_comment = argv[1]; for (i = 2; i < argc; i++) { int fd; Elf *elf; char *elf_fname; elf_fname = argv[i]; if ((fd = open(elf_fname, O_RDWR)) == -1) { perror("open"); continue; } /* * Attempt to open an Elf descriptor Read/Write * for each file. */ if ((elf = elf_begin(fd, ELF_C_RDWR, 0)) == NULL) { (void) fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(0)); (void) close(fd); continue; } /* * Determine what kind of elf file this is: */ if (elf_kind(elf) == ELF_K_ELF) update_comment(elf, elf_fname, new_comment); else (void) printf("%s not of type ELF_K_ELF. " "elf_kind == %d\n", elf_fname, elf_kind(elf)); (void) elf_end(elf); (void) close(fd); } return (0); } /* * 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) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * dcom: Delete Comment * * This program demonstrates the use of libelf interface to * copy the contents of one ELF file to create a new one. * dcom creates a new ELF file using elf_begin(ELF_C_WRITE). * * In order to delete a section from an ELF file you must * instead create a new ELF file and copy all but the 'selected' * sections to the new ELF file. This is because libelf is * unable to delete any sections from an ELF file, it can * only add them. * * NOTE: While this program works fine for simple ELF objects, * as they get more complex it may not properly update all of the * fields required. This program is *only* an example of how * to do this and not a complete program in itself. */ #include #include #include #include #include #include #include #include #include #include static const char *CommentStr = ".comment"; /* * Build a temporary file name that is in the * same directory as the elf file being processed. */ static char * mkname(const char *bname) { char *ptr; char buffer[MAXPATHLEN]; ptr = strcpy(buffer, bname); ptr += strlen(buffer); while (ptr >= buffer) { if (*ptr == '/') { *(ptr + 1) = '\0'; break; } ptr--; } if (ptr < buffer) { buffer[0] = '.'; buffer[1] = '\0'; } return (tempnam(buffer, 0)); } static void delete_comment(Elf *elf, int fd, const char *file) { Elf_Scn *scn = NULL; char *tfile; Elf *telf; GElf_Ehdr ehdr, tehdr; GElf_Phdr phdr, tphdr; size_t shstrndx, shnum, phnum; int tfd, *shndx, ndx = 1, off = 0; struct stat sbuf; if (gelf_getehdr(elf, &ehdr) == NULL) { (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", file, elf_errmsg(0)); return; } if (elf_getshdrnum(elf, &shnum) == -1) { (void) fprintf(stderr, "%s: elf_getshdrnum() failed: %s\n", file, elf_errmsg(0)); return; } if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n", file, elf_errmsg(0)); return; } if (elf_getphdrnum(elf, &phnum) == -1) { (void) fprintf(stderr, "%s: elf_getphdrnum() failed: %s\n", file, elf_errmsg(0)); return; } /* * shndx is an array used to map the current section * indexes to the new section indexes. */ shndx = calloc(shnum, sizeof (int)); while ((scn = elf_nextscn(elf, scn)) != NULL) { GElf_Shdr shdr; /* * Do a string compare to examine each section header * to see if it is a ".comment" section. If it is then * this is the section we want to process. */ if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if (strcmp(CommentStr, elf_strptr(elf, shstrndx, shdr.sh_name)) == 0) { shndx[ndx] = -1; off++; /* * If the .comment section is part of a loadable * segment then it can not be delted from the * ELF file. */ if (shdr.sh_addr != 0) { (void) printf("%s: .comment section is " "part of a loadable segment, it " "cannot be deleted.\n", file); free(shndx); return; } } else shndx[ndx] = ndx - off; ndx++; } /* * obtain a unique file name and open a file descriptor * pointing to that file. */ tfile = mkname(file); if ((tfd = open(tfile, O_RDWR | O_CREAT, 0600)) == -1) { perror("temp open"); return; } /* * Create a new ELF to duplicate the ELF file into. */ if ((telf = elf_begin(tfd, ELF_C_WRITE, 0)) == NULL) { (void) fprintf(stderr, "elf_begin(ELF_C_WRITE) failed: %s\n", elf_errmsg(0)); return; } if (gelf_newehdr(telf, gelf_getclass(elf)) == NULL) { (void) fprintf(stderr, "%s: elf_newehdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if (gelf_getehdr(telf, &tehdr) == NULL) { (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } scn = NULL; ndx = 1; while ((scn = elf_nextscn(elf, scn)) != NULL) { Elf_Scn *tscn; Elf_Data *data, *tdata; GElf_Shdr shdr, tshdr; if (shndx[ndx] == -1) { ndx++; continue; } /* * Duplicate all but the .comment section in the * new file. */ if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if ((tscn = elf_newscn(telf)) == NULL) { (void) fprintf(stderr, "%s: elf_newscn() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if (gelf_getshdr(tscn, &tshdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } tshdr = shdr; tshdr.sh_link = shndx[shdr.sh_link]; /* * The relocation sections sh_info field also contains * a section index that needs to be adjusted. This is * the only section who's sh_info field contains * a section index according to the ABI. * * If their are non-ABI sections who's sh_info field * contains section indexes they will not properly * be updated by this routine. */ if (shdr.sh_type == SHT_REL) tshdr.sh_info = shndx[ndx]; /* * Flush the changes to the underlying elf32 or elf64 * section header. */ (void) gelf_update_shdr(tscn, &tshdr); if ((data = elf_getdata(scn, 0)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if ((tdata = elf_newdata(tscn)) == NULL) { (void) fprintf(stderr, "%s: elf_newdata() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } *tdata = *data; ndx++; } tehdr = ehdr; if (shndx[shstrndx] < SHN_LORESERVE) tehdr.e_shstrndx = shndx[shstrndx]; else { Elf_Scn *_scn; GElf_Shdr shdr0; /* * 'ELF Extended Sections' are enabled - we must * store the shstrndx in Shdr[0].sh_link */ if ((_scn = elf_getscn(telf, 0)) == NULL) { (void) fprintf(stderr, "%s: elf_getscn() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } if (gelf_getshdr(_scn, &shdr0) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); free(shndx); return; } tehdr.e_shstrndx = SHN_XINDEX; shdr0.sh_link = shndx[shstrndx]; (void) gelf_update_shdr(_scn, &shdr0); } (void) gelf_update_ehdr(telf, &tehdr); free(shndx); /* * Duplicate all program headers contained in the ELF file. */ if (phnum != 0) { if (gelf_newphdr(telf, phnum) == NULL) { (void) fprintf(stderr, "%s: elf_newphdr() failed: %s\n", file, elf_errmsg(0)); return; } for (ndx = 0; ndx < (int)phnum; ndx++) { if (gelf_getphdr(elf, ndx, &phdr) == NULL || gelf_getphdr(telf, ndx, &tphdr) == NULL) { (void) fprintf(stderr, "%s: elf_getphdr() failed: %s\n", file, elf_errmsg(0)); return; } tphdr = phdr; (void) gelf_update_phdr(telf, ndx, &tphdr); } } /* * The new Elf file has now been fully described to libelf. * elf_update() will construct the new Elf file and write * it out to disk. */ if (elf_update(telf, ELF_C_WRITE) == -1) { (void) fprintf(stderr, "elf_update() failed: %s\n", elf_errmsg(0)); (void) elf_end(telf); (void) close(tfd); return; } (void) elf_end(telf); /* * set new files permissions to the original files * permissions. */ (void) fstat(fd, &sbuf); (void) fchmod(tfd, sbuf.st_mode); (void) close(tfd); /* * delete the original file and rename the new file * to the orignal file. */ (void) rename(tfile, file); } int main(int argc, char ** argv) { int i; if (argc < 2) { (void) printf("usage: %s elf_file ...\n", argv[0]); return (1); } /* * Initialize the elf library, must be called before elf_begin() * can be called. */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } for (i = 1; i < argc; i++) { int fd; Elf *elf; char *elf_fname; elf_fname = argv[i]; if ((fd = open(elf_fname, O_RDONLY)) == -1) { perror("open"); continue; } /* * Attempt to open an Elf descriptor Read/Write * for each file. */ if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { (void) fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(0)); (void) close(fd); continue; } /* * Determine what kind of elf file this is: */ if (elf_kind(elf) != ELF_K_ELF) { /* * can only delete comment sections from * ELF files. */ (void) printf("%s not of type ELF_K_ELF. " "elf_kind == %d\n", elf_fname, elf_kind(elf)); } else delete_comment(elf, fd, elf_fname); (void) elf_end(elf); (void) close(fd); } return (0); } /* * 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) 2002, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * dispsyms: Display Symbols * * This program demonstrates the use of the libelf interface to * read an ELF file. dispsyms will open an ELF file using * elf_begin(ELF_C_READ) and examine search the ELF file * for a symbol table (SHT_SYMTAB, SHT_DYNSYM, or SHT_SUNW_LDYNSYM). * It will display the contents of any symbol tables it finds. * * Note: This program also understands about the use * of 'Extended ELF Section indexes' and will * decode a corresponding SHT_SYMTAB_SHNDX * section if required. */ #include #include #include #include #include #include #include static const char *symbind[STB_NUM] = { /* STB_LOCL */ "LOCL", /* STB_GLOBAL */ "GLOB", /* STB_WEAK */ "WEAK" }; static const char *symtype[STT_NUM] = { /* STT_NOTYPE */ "NOTY", /* STT_OBJECT */ "OBJT", /* STT_FUNC */ "FUNC", /* STT_SECTION */ "SECT", /* STT_FILE */ "FILE", /* STT_COMMON */ "COMM", /* STT_TLS */ "TLS" }; #if STT_NUM != (STT_TLS + 1) #error "STT_NUM has grown. Update symtype[]." #endif #define INTSTRLEN 32 static void print_symtab(Elf *elf, const char *file) { Elf_Scn *scn = NULL; GElf_Shdr shdr; GElf_Ehdr ehdr; size_t shstrndx; if (gelf_getehdr(elf, &ehdr) == NULL) { (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", file, elf_errmsg(0)); return; } if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n", file, elf_errmsg(0)); return; } while ((scn = elf_nextscn(elf, scn)) != NULL) { uint_t symcnt, ndx, nosymshndx; Elf_Data *symdata, *shndxdata; if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } if ((shdr.sh_type != SHT_SYMTAB) && (shdr.sh_type != SHT_DYNSYM) && (shdr.sh_type != SHT_SUNW_LDYNSYM)) continue; /* * Get the data associated with the Symbol * section. */ if ((symdata = elf_getdata(scn, NULL)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); return; } /* * Print symbol table title and header for symbol display */ (void) printf("\nSymTab: %s:%s\n", file, elf_strptr(elf, shstrndx, shdr.sh_name)); (void) printf(" index value size type " "bind oth shndx name\n"); /* * We now iterate over the full symbol table printing * the symbols as we go. */ shndxdata = 0; nosymshndx = 0; symcnt = shdr.sh_size / shdr.sh_entsize; for (ndx = 0; ndx < symcnt; ndx++) { GElf_Sym sym; Elf32_Word shndx; uint_t type, bind, specshndx; char bindbuf[INTSTRLEN]; char typebuf[INTSTRLEN]; char shndxbuf[INTSTRLEN]; const char *bindstr, *typestr, *shndxstr; /* * Get a symbol entry */ if (gelf_getsymshndx(symdata, shndxdata, ndx, &sym, &shndx) == NULL) { (void) fprintf(stderr, "%s: gelf_getsymshndx() failed: %s\n", file, elf_errmsg(0)); return; } /* * Check to see if this symbol's st_shndx is using * the 'Extended SHNDX table' for a SYMTAB. * * If it is - and we haven't searched before, go * find the associated SHT_SYMTAB_SHNDX section. */ if ((sym.st_shndx == SHN_XINDEX) && (shndxdata == 0) && (nosymshndx == 0)) { Elf_Scn *_scn = NULL; GElf_Shdr _shdr; GElf_Word symscnndx; specshndx = 0; symscnndx = elf_ndxscn(scn); while ((_scn = elf_nextscn(elf, _scn)) != NULL) { if (gelf_getshdr(_scn, &_shdr) == NULL) break; /* * We've found the Symtab SHNDX table * if it's of type SHT_SYMTAB_SHNDX * and it's shdr.sh_link points to the * section index for the current symbol * table. */ if ((_shdr.sh_type == SHT_SYMTAB_SHNDX) && (_shdr.sh_link == symscnndx) && ((shndxdata = elf_getdata(_scn, NULL)) != NULL)) break; } /* * Get a symbol entry */ if (shndxdata && (gelf_getsymshndx(symdata, shndxdata, ndx, &sym, &shndx) == NULL)) { (void) fprintf(stderr, "%s: gelf_getsymshndx() " "failed: %s\n", file, elf_errmsg(0)); return; } /* * No Symtab SHNDX table was found. We could * give a fatal error here - instead we'll * just mark that fact and display as much of * the symbol table as we can. Any symbol * displayed with a XINDX section index has * a bogus value. */ if (shndxdata == 0) nosymshndx = 1; } /* * Decode the type & binding information */ type = GELF_ST_TYPE(sym.st_info); bind = GELF_ST_BIND(sym.st_info); if (type < STT_NUM) typestr = symtype[type]; else { (void) snprintf(typebuf, INTSTRLEN, "%d", type); typestr = typebuf; } if (bind < STB_NUM) bindstr = symbind[bind]; else { (void) snprintf(bindbuf, INTSTRLEN, "%d", bind); bindstr = bindbuf; } specshndx = 0; if (sym.st_shndx < SHN_LORESERVE) shndx = sym.st_shndx; else if ((sym.st_shndx != SHN_XINDEX) || (shndxdata == NULL)) { shndx = sym.st_shndx; specshndx = 1; } if (shndx == SHN_UNDEF) { shndxstr = (const char *)"UNDEF"; } else if (specshndx) { if (shndx == SHN_ABS) shndxstr = (const char *)"ABS"; else if (shndx == SHN_COMMON) shndxstr = (const char *)"COMM"; else if (shndx == SHN_XINDEX) shndxstr = (const char *)"XIND"; else { (void) snprintf(shndxbuf, INTSTRLEN, "%ld", shndx); shndxstr = shndxbuf; } } else { (void) snprintf(shndxbuf, INTSTRLEN, "%ld", shndx); shndxstr = shndxbuf; } /* * Display the symbol entry. */ (void) printf("[%3d] 0x%08llx 0x%08llx %-4s " "%-6s %2d %5s %s\n", ndx, sym.st_value, sym.st_size, typestr, bindstr, sym.st_other, shndxstr, elf_strptr(elf, shdr.sh_link, sym.st_name)); } } } static void process_elf(Elf *elf, char *file, int fd, int member) { Elf_Cmd cmd; Elf *_elf; switch (elf_kind(elf)) { case ELF_K_ELF: /* * This is an ELF file, now attempt to find it's * .comment section and to display it. */ print_symtab(elf, file); break; case ELF_K_AR: /* * Archives contain multiple ELF files, which can each * in turn be examined with libelf. * * The below loop will iterate over each member of the * archive and recursively call process_elf(). */ cmd = ELF_C_READ; while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { Elf_Arhdr *arhdr; char buffer[1024]; arhdr = elf_getarhdr(_elf); /* * Build up file names based off of * 'archivename(membername)'. */ (void) snprintf(buffer, 1024, "%s(%s)", file, arhdr->ar_name); /* * Recursively process the ELF members. */ process_elf(_elf, buffer, fd, 1); cmd = elf_next(_elf); (void) elf_end(_elf); } break; default: if (!member) (void) fprintf(stderr, "%s: unexpected elf_kind(): 0x%x\n", file, elf_kind(elf)); return; } } int main(int argc, char **argv) { int i; if (argc < 2) { (void) printf("usage: %s elf_file ...\n", argv[0]); return (1); } /* * Initialize the elf library, must be called before elf_begin() * can be called. */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } for (i = 1; i < argc; i++) { int fd; Elf *elf; char *elf_fname; elf_fname = argv[i]; if ((fd = open(elf_fname, O_RDONLY)) == -1) { perror("open"); continue; } /* * Attempt to open an Elf descriptor Read-Only * for each file. */ if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { (void) fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(0)); (void) close(fd); continue; } /* * Process each elf descriptor. */ process_elf(elf, elf_fname, fd, 0); (void) elf_end(elf); (void) close(fd); } return (0); } /* * 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) 1995, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * pcom: Print Comment * * This program demonstrates the use of the libelf interface to * read an ELF file. pcom will open an ELF file using * elf_begin(ELF_C_READ) and examine search the ELF file * for a .comment section. If a .comment section is found it's * contents will be displayed on stdout. */ #include #include #include #include #include #include #include static const char *CommentStr = ".comment"; static void print_comment(Elf *elf, const char *file) { Elf_Scn *scn = NULL; GElf_Shdr shdr; Elf_Data *data; size_t shstrndx; (void) printf("%s .comment:\n", file); if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n", file, elf_errmsg(0)); return; } while ((scn = elf_nextscn(elf, scn)) != NULL) { /* * Do a string compare to examine each section header * to see if it is a ".comment" section. If it is then * this is the section we want to process. */ if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } if (strcmp(CommentStr, elf_strptr(elf, shstrndx, shdr.sh_name)) == 0) { int i; char *ptr; /* * Get the data associated with the .comment * section. */ if ((data = elf_getdata(scn, NULL)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); return; } /* * Data in a .comment section is a list of 'null' * terminated strings. The following will print * one string per line. */ for (i = 0, ptr = (char *)data->d_buf; i < data->d_size; i++) if (ptr[i]) { (void) puts(&ptr[i]); i += strlen(&ptr[i]); } (void) putchar('\n'); } } } static void process_elf(Elf *elf, char *file, int fd, int member) { Elf_Cmd cmd; Elf *_elf; switch (elf_kind(elf)) { case ELF_K_ELF: /* * This is an ELF file, now attempt to find it's * .comment section and to display it. */ print_comment(elf, file); break; case ELF_K_AR: /* * Archives contain multiple ELF files, which can each * in turn be examined with libelf. * * The below loop will iterate over each member of the * archive and recursively call process_elf(). */ cmd = ELF_C_READ; while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { Elf_Arhdr *arhdr; char buffer[1024]; arhdr = elf_getarhdr(_elf); /* * Build up file names based off of * 'archivename(membername)'. */ (void) sprintf(buffer, "%s(%s)", file, arhdr->ar_name); /* * Recursively process the ELF members. */ process_elf(_elf, buffer, fd, 1); cmd = elf_next(_elf); (void) elf_end(_elf); } break; default: if (!member) (void) fprintf(stderr, "%s: unexpected elf_kind(): 0x%x\n", file, elf_kind(elf)); return; } } int main(int argc, char **argv) { int i; if (argc < 2) { (void) printf("usage: %s elf_file ...\n", argv[0]); return (1); } /* * Initialize the elf library, must be called before elf_begin() * can be called. */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } for (i = 1; i < argc; i++) { int fd; Elf *elf; char *elf_fname; elf_fname = argv[i]; if ((fd = open(elf_fname, O_RDONLY)) == -1) { perror("open"); continue; } /* * Attempt to open an Elf descriptor Read/Write * for each file. */ if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { (void) fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(0)); (void) close(fd); continue; } /* * Process each elf descriptor. */ process_elf(elf, elf_fname, fd, 0); (void) elf_end(elf); (void) close(fd); } return (0); } /* * 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) 1995, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * tpcom: Threaded Print Comment * * tpcom is a threaded version of the pcom program. It will create * a new thread for each new ELF descriptor that it examines. It * will then examine each elf descriptor and print the .comment section * if found. * * This program demonstrates that libelf is MT-Safe and the usage * of elf_begin(ELF_C_READ). */ #include #include #include #include #include #include #include #include #define NUMLWPS 32 /* arbitrary number of LWPS */ static const char *CommentStr = ".comment"; /* * arguments to be passed into process_elf(). */ typedef struct { Elf *pe_elf; char *pe_file; /* elf member name */ int pe_fd; short pe_member; /* is this an archive member? */ } pe_args; static mutex_t printlock = DEFAULTMUTEX; /* printlock used to */ /* group output */ /* of comment sections */ static void print_comment(Elf *elf, const char *file) { Elf_Scn *scn = NULL; GElf_Shdr shdr; Elf_Data *data; size_t shstrndx; if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n", file, elf_errmsg(0)); return; } while ((scn = elf_nextscn(elf, scn)) != NULL) { /* * Do a string compare to examine each section header * to see if it is a ".comment" section. If it is then * this is the section we want to process. */ if (gelf_getshdr(scn, &shdr) == NULL) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } if (strcmp(CommentStr, elf_strptr(elf, shstrndx, shdr.sh_name)) == 0) { int i; char *ptr; (void) mutex_lock(&printlock); (void) printf("%s .comment:\n", file); /* * Get the data associated with the .comment * section. */ if ((data = elf_getdata(scn, NULL)) == NULL) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); (void) mutex_unlock(&printlock); return; } /* * Data in a .comment section is a list of 'null' * terminated strings. The following will print * one string per line. */ for (i = 0, ptr = (char *)data->d_buf; i < data->d_size; i++) if (ptr[i]) { (void) puts(&ptr[i]); i += strlen(&ptr[i]); } (void) putchar('\n'); (void) mutex_unlock(&printlock); } } } static void process_elf(pe_args *pep) { Elf_Cmd cmd; Elf *_elf; switch (elf_kind(pep->pe_elf)) { case ELF_K_ELF: print_comment(pep->pe_elf, pep->pe_file); break; case ELF_K_AR: cmd = ELF_C_READ; while ((_elf = elf_begin(pep->pe_fd, cmd, pep->pe_elf)) != NULL) { Elf_Arhdr *arhdr; pe_args *_pep; int rc; if ((arhdr = elf_getarhdr(_elf)) == NULL) { (void) fprintf(stderr, "%s: elf_getarhdr() failed: %s\n", pep->pe_file, elf_errmsg(0)); } cmd = elf_next(_elf); _pep = malloc(sizeof (pe_args)); _pep->pe_elf = _elf; _pep->pe_file = malloc(strlen(pep->pe_file) + strlen(arhdr->ar_name) + 5); (void) sprintf(_pep->pe_file, "%s(%s)", pep->pe_file, arhdr->ar_name); _pep->pe_fd = pep->pe_fd; _pep->pe_member = 1; if ((rc = thr_create(NULL, 0, (void *(*)(void *))process_elf, (void *)_pep, THR_DETACHED, 0)) != 0) { (void) fprintf(stderr, "thr_create() failed, rc = %d\n", rc); } } break; default: if (!pep->pe_member) { (void) mutex_lock(&printlock); (void) fprintf(stderr, "%s: unexpected elf_kind(): 0x%x\n", pep->pe_file, elf_kind(pep->pe_elf)); (void) mutex_unlock(&printlock); } } (void) elf_end(pep->pe_elf); if (pep->pe_member) free(pep->pe_file); free(pep); thr_exit(0); } int main(int argc, char ** argv) { int i; if (argc < 2) { (void) printf("usage: %s elf_file ...\n", argv[0]); return (1); } /* * Initialize the elf library, must be called before elf_begin() * can be called. */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } /* * create an arbitrary number of LWP's to run the * threads that will be created. */ if (thr_setconcurrency(NUMLWPS) != 0) { (void) fprintf(stderr, "thread setconcurrency failed\n"); return (1); } for (i = 1; i < argc; i++) { int fd; Elf *elf; pe_args *pep; int rc; char *elf_fname; elf_fname = argv[i]; if ((fd = open(elf_fname, O_RDONLY)) == -1) { perror("open"); continue; } /* * Attempt to open an Elf descriptor Read/Write * for each file. */ if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { (void) mutex_lock(&printlock); (void) fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(0)); (void) mutex_unlock(&printlock); (void) close(fd); continue; } pep = malloc(sizeof (pe_args)); pep->pe_elf = elf; pep->pe_file = elf_fname; pep->pe_fd = fd; pep->pe_member = 0; if ((rc = thr_create(NULL, 0, (void *(*)(void *))process_elf, (void *)pep, THR_DETACHED, 0)) != 0) { (void) mutex_lock(&printlock); (void) fprintf(stderr, "thr_create() failed with code: %d\n", rc); (void) mutex_unlock(&printlock); return (1); } } thr_exit(0); return (0); } /* * 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 */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * C++ Demangler Source Code * @(#)master 1.5 * 7/27/88 13:54:37 */ #include #include #include #include #include #include "elf_dem.h" #include "String.h" /* * This code emulates the C++ String package * in a crude way. */ jmp_buf jbuf; /* * This function will expand the space * available to a String so that more data * can be appended to it */ static String * grow(s) String *s; { String *ns; int sz = s->sg.max * 2; assert(sz > 0); #ifdef ELF if ((ns = (String *)malloc(sz + sizeof (StringGuts) + 1)) == NULL) longjmp(jbuf, 1); (void) memcpy(ns, s, s->sg.max + sizeof (StringGuts) + 1); free(s); #else if ((ns = (String *)realloc(s, sz + sizeof (StringGuts) + 1)) == NULL) longjmp(jbuf, 1); #endif ns->sg.max = sz; return (ns); } /* * This function will expand the space * available to a String so that more data * can be prepended to it. */ static String * ror(s, n) String *s; int n; { assert(s != 0); while (s->sg.end + n > s->sg.max) s = grow(s); #ifdef __STDC__ assert(n >= 0); assert(s->sg.end >= s->sg.start); (void) memmove(s->data + n, s->data, s->sg.end - s->sg.start); #else { int i; for (i = s->sg.end - 1; i >= s->sg.start; i--) s->data[i+n] = s->data[i]; } #endif s->sg.end += n; s->sg.start += n; s->data[s->sg.end] = 0; return (s); } /* * This function will prepend c * to s */ String * prep_String(c, s) char *c; String *s; { return (nprep_String(c, s, ID_NAME_MAX)); } /* * This function will prepend the * first n characters of c to s */ String * nprep_String(c, s, n) const char *c; String *s; int n; { int len = strlen(c); assert(s != 0); if (len > n) len = n; if (len > s->sg.start) s = ror(s, len - s->sg.start); s->sg.start -= len; (void) memcpy(s->data + s->sg.start, c, len); return (s); } /* * This function will append * c to s. */ String * app_String(s, c) String *s; const char *c; { return (napp_String(s, c, ID_NAME_MAX)); } /* * This function will append the * first n characters of c to s */ String * napp_String(String *s, const char *c, int n) { int len = strlen(c); int catlen; assert(s != 0); if (n < len) len = n; catlen = s->sg.end + len; while (catlen > s->sg.max) s = grow(s); (void) memcpy(s->data + s->sg.end, c, len); s->sg.end += len; s->data[s->sg.end] = '\0'; return (s); } /* * This function initializes a * String. It returns its argument if * its argument is non-zero. * This prevents the same string * from being re-initialized. */ String * mk_String(s) String *s; { if (s) return (s); s = (String *)malloc(STRING_START + sizeof (StringGuts) + 1); if (s == NULL) longjmp(jbuf, 1); s->sg.start = s->sg.end = STRING_START/2; s->sg.max = STRING_START; s->data[s->sg.end] = '\0'; return (s); } void free_String(s) String *s; { if (s) free(s); } /* * This function copies * c into s. * Used for initialization. */ String * set_String(s, c) String *s; char *c; { int len = strlen(c)*2; while (len > s->sg.max) s = grow(s); s->sg.start = s->sg.end = s->sg.max / 2; s = app_String(s, c); return (s); } /* * Chop n characters off the end of a string. * Return the truncated string. */ String * trunc_String(String *s, int n) { assert(n <= s->sg.end - s->sg.start); s->sg.end -= n; s->data[s->sg.end] = '\0'; return (s); } /* * 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 */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * C++ Demangler Source Code * @(#)master 1.5 * 7/27/88 13:54:37 */ #define STRING_START 32 #define PTR(S) ((S)->data + (S)->sg.start) typedef struct { int start,end,max; } StringGuts; typedef struct { StringGuts sg; char data[1]; } String; extern String *prep_String(); extern String *nprep_String(); extern String *app_String(); extern String *napp_String(); extern String *mk_String(); extern void free_String(); extern String *set_String(); extern String *trunc_String(); extern const char *findop(); /* * 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 */ /* * Copyright (c) 1988 AT&T * All Rights Reserved * * * Copyright (c) 1998 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include "elf_dem.h" #include "String.h" #include "msg.h" /* This structure is used to keep * track of pointers to argument * descriptions in the mangled string. * This is needed for N and T encodings * to work. */ typedef struct { char *list[10]; int pos; } Place; static Place here; /* Strings and flags needed by the argument demangles. The declarator * is built up in ptr. Type modifiers are held in the flag fields. * The type itself is passed in separately. */ typedef struct { String *ptr; int Sign,Uns,Cons,Vol; } Arg_Remem; /* initialize Arg_Remem */ static void mkar(Arg_Remem *r) { r->ptr = mk_String((String *)0); r->Sign = r->Uns = r->Cons = r->Vol = 0; } /* free data for Arg_Remem */ static void delar(Arg_Remem *r) { free_String(r->ptr); } /* This routine formats a single argument * on the buffer sptr. * c is the type or class name, n is its length. */ static void nsetarg(String ** sptr, Arg_Remem * r, const char * c, int n) { r->ptr = nprep_String(c, r->ptr, n); if(r->Cons) r->ptr = prep_String(MSG_ORIG(MSG_STR_CONST_1), r->ptr); if(r->Vol) r->ptr = prep_String(MSG_ORIG(MSG_STR_VOLATILE_1), r->ptr); if(r->Uns) r->ptr = prep_String(MSG_ORIG(MSG_STR_UNSIGNED), r->ptr); else if(r->Sign) r->ptr = prep_String(MSG_ORIG(MSG_STR_SIGNED), r->ptr); *sptr = app_String(*sptr,PTR(r->ptr)); delar(r); } /* This routine formats a single argument * on the buffer sptr. * c is the null terminated type or class name. */ static void setarg(String ** sptr, Arg_Remem * r, const char * c) { nsetarg(sptr, r, c, ID_NAME_MAX); } /* Demangle a single function argument. * Returns the number of characters processed from c. */ int demangle_doarg(String **sptr, char *c) { int i; Arg_Remem ar; mkar(&ar); if(here.pos < 10 && here.pos >= 0) here.list[here.pos++] = c; for(i=0;c[i];i++) { /* Loop until you find a type. Then call setarg and return. */ switch(c[i]) { case 'T': { Place tmp; tmp = here; here.pos = c[1] - '1'; if(here.pos < 0 || here.pos >= tmp.pos-1) { delar(&ar); return -1; } (void) demangle_doarg(sptr,here.list[here.pos]); here = tmp; delar(&ar); return 2; } case 'N': { Place tmp; int cycles,pos; cycles = c[1] - '0'; pos = c[2] - '1'; here.pos += cycles - 1; tmp = here; if(cycles <= 1 || cycles > 9 || pos < 0 || pos >= tmp.pos-1) { delar(&ar); return -1; } while(cycles--) { here = tmp; here.pos = pos; (void) demangle_doarg(sptr,here.list[here.pos]); (*sptr) = app_String(*sptr, MSG_ORIG(MSG_STR_COMMA)); } *sptr = trunc_String(*sptr, 1); here = tmp; delar(&ar); return 3; } /* Qualifiers to type names */ case 'S': ar.Sign = 1; break; case 'U': ar.Uns = 1; break; case 'C': ar.Cons = 1; break; case 'V': ar.Vol = 1; break; /* Pointers, references, and Member Pointers */ case 'P': case 'R': case 'M': if(ar.Cons) { ar.ptr = prep_String(MSG_ORIG(MSG_STR_CONST_2), ar.ptr); ar.Cons = 0; } if(ar.Vol) { ar.ptr = prep_String(MSG_ORIG(MSG_STR_VOLATILE_2), ar.ptr); ar.Vol = 0; } if(c[i] == 'P') ar.ptr = prep_String(MSG_ORIG(MSG_STR_STAR), ar.ptr); else if(c[i] == 'R') ar.ptr = prep_String(MSG_ORIG(MSG_STR_AMP), ar.ptr); else { int cnt = 0; char *s; ar.ptr = prep_String(MSG_ORIG(MSG_STR_DBLCOLSTAR), ar.ptr); /* Skip over the 'M' */ i++; cnt = strtol(c+i, &s, 10); i = s - c; ar.ptr = nprep_String(c+i,ar.ptr,cnt); ar.ptr = prep_String(MSG_ORIG(MSG_STR_SPACE), ar.ptr); i += cnt; /* The loop increments i */ i--; } break; /* Demangle for basic built-in types */ case 'i': setarg(sptr, &ar, MSG_ORIG(MSG_STR_INT)); return i + 1; case 'c': setarg(sptr, &ar, MSG_ORIG(MSG_STR_CHAR)); return i + 1; case 's': setarg(sptr, &ar, MSG_ORIG(MSG_STR_SHORT)); return i + 1; case 'l': setarg(sptr, &ar, MSG_ORIG(MSG_STR_LONG)); return i + 1; case 'f': setarg(sptr, &ar, MSG_ORIG(MSG_STR_FLOAT)); return i + 1; case 'd': setarg(sptr, &ar, MSG_ORIG(MSG_STR_DOUBLE)); return i + 1; case 'r': setarg(sptr, &ar, MSG_ORIG(MSG_STR_LONGDOUBLE)); return i + 1; /* Class encodings */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { int cnt = 0; char *s; cnt = strtol(c+i, &s, 10); i = s - c; if ((int) strlen(c+i) < cnt) { delar(&ar); return -1; } nsetarg(sptr,&ar,c+i,cnt); return i+cnt; } /* Ellipsis and void */ case 'e': setarg(sptr, &ar, MSG_ORIG(MSG_STR_ELIPSE)); return i + 1; case 'v': setarg(sptr, &ar, MSG_ORIG(MSG_STR_VOID)); return i + 1; /* Arrays */ case 'A': if(*PTR(ar.ptr)) { ar.ptr = prep_String(MSG_ORIG(MSG_STR_OPENPAR), ar.ptr); ar.ptr = app_String(ar.ptr, MSG_ORIG(MSG_STR_CLOSEPAR)); } ar.ptr = app_String(ar.ptr, MSG_ORIG(MSG_STR_OPENBRAK)); { int cnt = 0; i++; while(isdigit(c[i+cnt])) cnt++; ar.ptr = napp_String(ar.ptr,c+i,cnt); i += cnt; if(c[i] != '_') { delar(&ar); return -1; } } ar.ptr = app_String(ar.ptr, MSG_ORIG(MSG_STR_CLOSEBRAK)); break; /* Functions * This will always be called as a pointer * to a function. */ case 'F': ar.ptr = prep_String(MSG_ORIG(MSG_STR_OPENPAR), ar.ptr); ar.ptr = app_String(ar.ptr, MSG_ORIG(MSG_STR_CLOSEPAR)); { Place tmp; tmp = here; i++; i += demangle_doargs(&ar.ptr,c+i); if(c[i] != '_') { delar(&ar); return -1; } here = tmp; } break; /* Needed when this is called to demangle * an argument of a pointer to a function. */ case '_': delar(&ar); return 0; default: delar(&ar); return -1; } } /* Did the argument list terminate properly? */ { int rc = 0; if(*PTR(ar.ptr) || ar.Uns || ar.Sign || ar.Cons || ar.Vol) rc = -1; delar(&ar); return rc; } } /* This function is called to demangle * an argument list. * Returns the number of characters processed from c. */ int demangle_doargs(String **sptr, char *c) { int i = 0, n = 0; here.pos = 0; *sptr = app_String(*sptr,MSG_ORIG(MSG_STR_OPENPAR)); while (*c && (i = demangle_doarg(sptr,c)) > 0) { c += i; n += i; (*sptr) = app_String(*sptr,(*c && *c == 'e') ? MSG_ORIG(MSG_STR_SPACE) : MSG_ORIG(MSG_STR_COMMA)); } if(i < 0) return -1; *sptr = app_String(trunc_String(*sptr, 1), MSG_ORIG(MSG_STR_CLOSEPAR)); return n; } /* * 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 */ /* * Copyright (c) 1988 AT&T * All Rights Reserved * * * Copyright (c) 1998 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include #include #include "elf_dem.h" #include "String.h" #include "msg.h" /* * The variable "hold" contains the pointer to the array initially * handed to demangle. It is returned if it is not possible to * demangle the string. NULL is returned if a memory allocation * problem is encountered. Thus one can do the following: * * char *mn = "Some mangled name"; * char *dm = mangle(mn); * if (dm == NULL) * printf("allocation error\n"); * else if (dm == mn) * printf("name could not be demangled\n"); * else * printf("demangled name is: %s\n",dm); */ static char *hold; /* * this String is the working buffer for the demangle * routine. A pointer into this String is returned * from demangle when it is possible to demangle the * String. For this reason, the pointer should not * be saved between calls of demangle(), nor freed. */ static String *s = 0; static int getint(char **c) { return (strtol(*c, c, 10)); } /* * If a mangled name has a __ * that is not at the very beginning * of the string, then this routine * is called to demangle that part * of the name. All overloaded functions, * and class members fall into this category. * * c should start with two underscores followed by a non-zero digit or an F. */ static char * second(char *c) { int n; if (strncmp(c, MSG_ORIG(MSG_STR_DBLUNDBAR), 2)) return (hold); c += 2; if (!(isdigit(*c) || *c == 'F')) return (hold); if (isdigit(*c)) { /* a member */ n = getint(&c); if (n == 0 || (int)strlen(c) < n) return (hold); s = prep_String(MSG_ORIG(MSG_STR_DBLCOL), s); s = nprep_String(c, s, n); c += n; } if (*c == 'F') { /* an overloaded function */ switch (*++c) { case '\0': return (hold); case 'v': s = app_String(s, MSG_ORIG(MSG_STR_OPENCLOSEPAR)); break; default: if (demangle_doargs(&s, c) < 0) return (hold); } } return (PTR(s)); } char * demangle(char *c) { volatile int i = 0; extern jmp_buf jbuf; static mutex_t mlock = DEFAULTMUTEX; (void) mutex_lock(&mlock); if (setjmp(jbuf)) { (void) mutex_unlock(&mlock); return (0); } hold = c; s = mk_String(s); s = set_String(s, MSG_ORIG(MSG_STR_EMPTY)); if (c == 0 || *c == 0) { c = hold; (void) mutex_unlock(&mlock); return (c); } if (strncmp(c, MSG_ORIG(MSG_STR_DBLUNDBAR), 2) != 0) { /* * If a name does not begin with a __ * but it does contain one, it is either * a member or an overloaded function. */ while (c[i] && strncmp(c+i, MSG_ORIG(MSG_STR_DBLUNDBAR), 2)) i++; if (c[i]) { /* Advance to first non-underscore */ while (c[i+2] == '_') i++; } if (strncmp(c+i, MSG_ORIG(MSG_STR_DBLUNDBAR), 2) == 0) { /* Copy the simple name */ s = napp_String(s, c, i); /* Process the signature */ c = second(c+i); (void) mutex_unlock(&mlock); return (c); } else { c = hold; (void) mutex_unlock(&mlock); return (c); } } else { const char *x; int oplen; c += 2; /* * For automatic variables, or internal static * variables, a __(number) is prepended to the * name. If this is encountered, strip this off * and return. */ if (isdigit(*c)) { while (isdigit(*c)) c++; (void) mutex_unlock(&mlock); return (c); } /* * Handle operator functions -- this * automatically calls second, since * all operator functions are overloaded. */ x = findop(c, &oplen); if (x != NULL) { s = app_String(s, MSG_ORIG(MSG_STR_OPERATOR_1)); s = app_String(s, x); c += oplen; c = second(c); (void) mutex_unlock(&mlock); return (c); } /* * Operator cast does not fit the mould * of the other operators. Its type name * is encoded. The cast function must * take a void as an argument. */ if (strncmp(c, MSG_ORIG(MSG_STR_OP), 2) == 0) { int r; s = app_String(s, MSG_ORIG(MSG_STR_OPERATOR_2)); c += 2; r = demangle_doarg(&s, c); if (r < 0) { c = hold; (void) mutex_unlock(&mlock); return (c); } c += r; c = second(c); (void) mutex_unlock(&mlock); return (c); } /* * Constructors and Destructors are also * a special case of operator name. Note * that the destructor, while overloaded, * must always take the same arguments -- * none. */ if ((*c == 'c' || *c == 'd') && strncmp(c+1, MSG_ORIG(MSG_STR_TDBLUNDBAR), 3) == 0) { int n; char *c2 = c+2; char cx = c[0]; c += 4; n = getint(&c); if (n == 0) { c = hold; (void) mutex_unlock(&mlock); return (c); } s = napp_String(s, c, n); if (cx == 'd') s = prep_String(MSG_ORIG(MSG_STR_TILDE), s); c = second(c2); (void) mutex_unlock(&mlock); return (c); } c = hold; (void) mutex_unlock(&mlock); return (c); } } /* * 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 */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* ELF interface header file for the C++ demangler. The C++ demangler is shared by the ELF library and the C++ translator. Because the translator is used on many different operating systems, not all of which use ELF, we have set up this library so that it may be compiled to work with or without libelf. The default is to compile for ELF. Undefine the macro "ELF" in the makefile before compiling for the translator. These macros tack an _elf_ on to the beginning of all global names which should hidden outside of the demangler module. The only visible name at this time is the function "demangle" which is mapped to "elf_demangle" for the ELF library. Note that we use "_elf_" to hide names even for the translator. We could have used just "_" but since the names are hidden why should we bother. */ #define app_String _elf_app_String #define demangle_doarg _elf_demangle_doarg #define demangle_doargs _elf_demangle_doargs #define findop _elf_findop #define free_String _elf_free_String #define mk_String _elf_mk_String #define napp_String _elf_napp_String #define nplist _elf_nplist #define nprep_String _elf_nprep_String #define prep_String _elf_prep_String #define set_String _elf_set_String #define trunc_String _elf_trunc_String #define jbuf _elf_jbuf extern int demangle_doarg(); extern int demangle_doargs(); #if defined(ELF) #define demangle elf_demangle /* Make sure that realloc isn't called inadvertantly. */ #define realloc __can_not_use_realloc_in_elf__ #else /* defined(ELF) */ #include #endif /* defined(ELF) */ #ifdef __STDC__ # include # define ID_NAME_MAX INT_MAX #else /* The only requirement on this is that it must be greater than the length of any symbol. */ # define ID_NAME_MAX 30000 #endif /* * 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 */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 1998 by Sun Microsystems, Inc. * All rights reserved. */ #include "libelf.h" #include #include #include #include #include "syms.h" #include "gelf.h" #undef n_name /* This undef is to handle a #define in syms.h */ /* which conflicts with the member nlist->n_name */ /* as defined in nlist.h */ #define SPACE 100 /* number of symbols read at a time */ #define ISELF (strncmp(magic_buf, ELFMAG, SELFMAG) == 0) int end_elf_job(int fd, Elf * elfdes) { (void) elf_end(elfdes); (void) close(fd); return (-1); } int _elf_nlist(int fd, struct nlist * list) { Elf *elfdes; /* ELF descriptor */ GElf_Ehdr ehdr; /* ELF Ehdr */ GElf_Shdr s_buf; /* buffer storing section header */ Elf_Data *symdata; /* buffer points to symbol table */ Elf_Scn *secidx = 0; /* index of the section header table */ GElf_Sym sym; /* buffer storing one symbol information */ unsigned strtab; /* index of symbol name in string table */ long count; /* number of symbols */ long ii; /* loop control */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) close(fd); return (-1); } elfdes = elf_begin(fd, ELF_C_READ, (Elf *)0); if (gelf_getehdr(elfdes, &ehdr) == 0) return (end_elf_job(fd, elfdes)); while ((secidx = elf_nextscn(elfdes, secidx)) != 0) { if ((gelf_getshdr(secidx, &s_buf)) == 0) return (end_elf_job(fd, elfdes)); if (s_buf.sh_type != SHT_SYMTAB) /* not symbol table */ continue; symdata = elf_getdata(secidx, (Elf_Data *)0); if (symdata == 0) return (end_elf_job(fd, elfdes)); if (symdata->d_size == 0) break; strtab = s_buf.sh_link; count = symdata->d_size / s_buf.sh_entsize; for (ii = 1; ii < count; ++ii) { struct nlist *p; register char *name; /* LINTED */ (void) gelf_getsym(symdata, (int)ii, &sym); name = elf_strptr(elfdes, strtab, (size_t)sym.st_name); if (name == 0) continue; for (p = list; p->n_name && p->n_name[0]; ++p) { if (strcmp(p->n_name, name)) continue; p->n_value = (long)sym.st_value; p->n_type = GELF_ST_TYPE(sym.st_info); p->n_scnum = sym.st_shndx; break; } } break; /* * Currently there is only one symbol table section * in an object file, but this restriction may be * relaxed in the future. */ } (void) elf_end(elfdes); (void) close(fd); return (0); } int nlist(const char * name, struct nlist * list) { register struct nlist *p; char magic_buf[EI_NIDENT]; int fd; for (p = list; p->n_name && p->n_name[0]; p++) { /* n_name can be ptr */ p->n_type = 0; p->n_value = 0L; p->n_scnum = 0; p->n_sclass = 0; p->n_numaux = 0; } if ((fd = open(name, 0)) < 0) return (-1); if (read(fd, magic_buf, EI_NIDENT) == -1) { (void) close(fd); return (-1); } if (lseek(fd, 0L, 0) == -1L) { /* rewind to beginning of object file */ (void) close(fd); return (-1); } #ifndef _LP64 if (ISELF && (magic_buf[EI_CLASS] == ELFCLASS32)) #else if (ISELF) /* 64-bit case handles both Elf32 and Elf64 */ #endif return (_elf_nlist(fd, list)); else { (void) close(fd); return (-1); } } /* * 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 */ /* * Copyright (c) 1988 AT&T * All Rights Reserved * * * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ #include "elf_dem.h" #include #include "msg.h" struct name_pair { #ifdef __lint char * s1, * s2; #else int s1, s2; #endif }; struct name_pair nplist[100] = { /* MSG_ORIG(MSG_STR_LT) MSG_ORIG(MSG_STR_OPNANGBRAK) */ { MSG_STR_LT, MSG_STR_OPNANGBRAK }, /* MSG_ORIG(MSG_STR_LS) MSG_ORIG(MSG_STR_DBLOPNANGBRAK) */ { MSG_STR_LS, MSG_STR_DBLOPNANGBRAK }, /* MSG_ORIG(MSG_STR_DV) MSG_ORIG(MSG_STR_SLASH) */ { MSG_STR_DV, MSG_STR_SLASH }, /* MSG_ORIG(MSG_STR_GT) MSG_ORIG(MSG_STR_CLOANGBRAK) */ { MSG_STR_GT, MSG_STR_CLOANGBRAK }, /* MSG_ORIG(MSG_STR_RS) MSG_ORIG(MSG_STR_DBLCLOANGBRAK) */ { MSG_STR_RS, MSG_STR_DBLCLOANGBRAK }, /* MSG_ORIG(MSG_STR_MD) MSG_ORIG(MSG_STR_PERCENT) */ { MSG_STR_MD, MSG_STR_PERCENT }, /* MSG_ORIG(MSG_STR_LE) MSG_ORIG(MSG_STR_OPNANGBRAKEQU) */ { MSG_STR_LE, MSG_STR_OPNANGBRAKEQU }, /* MSG_ORIG(MSG_STR_ML) MSG_ORIG(MSG_STR_STAR) */ { MSG_STR_ML, MSG_STR_STAR }, /* MSG_ORIG(MSG_STR_PL) MSG_ORIG(MSG_STR_PLUS) */ { MSG_STR_PL, MSG_STR_PLUS }, /* MSG_ORIG(MSG_STR_GE) MSG_ORIG(MSG_STR_CLOANGBRAKEQU) */ { MSG_STR_GE, MSG_STR_CLOANGBRAKEQU }, /* MSG_ORIG(MSG_STR_AD) MSG_ORIG(MSG_STR_AMP) */ { MSG_STR_AD, MSG_STR_AMP }, /* MSG_ORIG(MSG_STR_MI) MSG_ORIG(MSG_STR_MINUS) */ { MSG_STR_MI, MSG_STR_MINUS }, /* MSG_ORIG(MSG_STR_NE) MSG_ORIG(MSG_STR_BANGEQU) */ { MSG_STR_NE, MSG_STR_BANGEQU }, /* MSG_ORIG(MSG_STR_OR) MSG_ORIG(MSG_STR_PIPE) */ { MSG_STR_OR, MSG_STR_PIPE }, /* MSG_ORIG(MSG_STR_ER) MSG_ORIG(MSG_STR_CARAT) */ { MSG_STR_ER, MSG_STR_CARAT }, /* MSG_ORIG(MSG_STR_AA) MSG_ORIG(MSG_STR_DBLAMP) */ { MSG_STR_AA, MSG_STR_DBLAMP }, /* MSG_ORIG(MSG_STR_OO) MSG_ORIG(MSG_STR_DBLPIPE) */ { MSG_STR_OO, MSG_STR_DBLPIPE }, /* MSG_ORIG(MSG_STR_AS) MSG_ORIG(MSG_STR_EQU) */ { MSG_STR_AS, MSG_STR_EQU }, /* MSG_ORIG(MSG_STR_APL) MSG_ORIG(MSG_STR_PLUSEQU) */ { MSG_STR_APL, MSG_STR_PLUSEQU }, /* MSG_ORIG(MSG_STR_AMI) MSG_ORIG(MSG_STR_MINUSEQU) */ { MSG_STR_AMI, MSG_STR_MINUSEQU }, /* MSG_ORIG(MSG_STR_AMU) MSG_ORIG(MSG_STR_STARTEQU) */ { MSG_STR_AMU, MSG_STR_STARTEQU }, /* MSG_ORIG(MSG_STR_ADV) MSG_ORIG(MSG_STR_SLASHEQU) */ { MSG_STR_ADV, MSG_STR_SLASHEQU }, /* MSG_ORIG(MSG_STR_AMD) MSG_ORIG(MSG_STR_PERCENTEQU) */ { MSG_STR_AMD, MSG_STR_PERCENTEQU }, /* MSG_ORIG(MSG_STR_AAD) MSG_ORIG(MSG_STR_AMPEQU) */ { MSG_STR_AAD, MSG_STR_AMPEQU }, /* MSG_ORIG(MSG_STR_AOR) MSG_ORIG(MSG_STR_PIPEEQU) */ { MSG_STR_AOR, MSG_STR_PIPEEQU }, /* MSG_ORIG(MSG_STR_AER) MSG_ORIG(MSG_STR_CARATEQU) */ { MSG_STR_AER, MSG_STR_CARATEQU }, /* MSG_ORIG(MSG_STR_ALS) MSG_ORIG(MSG_STR_DBLOPENABKEQU) */ { MSG_STR_ALS, MSG_STR_DBLOPENABKEQU }, /* MSG_ORIG(MSG_STR_ARS) MSG_ORIG(MSG_STR_DBLCLOSABKEQU) */ { MSG_STR_ARS, MSG_STR_DBLCLOSABKEQU }, /* MSG_ORIG(MSG_STR_PP) MSG_ORIG(MSG_STR_DBLPLUS) */ { MSG_STR_PP, MSG_STR_DBLPLUS }, /* MSG_ORIG(MSG_STR_MM) MSG_ORIG(MSG_STR_DBLMINUS) */ { MSG_STR_MM, MSG_STR_DBLMINUS }, /* MSG_ORIG(MSG_STR_VC) MSG_ORIG(MSG_STR_OPENCLOBRAK) */ { MSG_STR_VC, MSG_STR_OPENCLOBRAK }, /* MSG_ORIG(MSG_STR_CL) MSG_ORIG(MSG_STR_OPENCLOSEPAR) */ { MSG_STR_CL, MSG_STR_OPENCLOSEPAR }, /* MSG_ORIG(MSG_STR_RF) MSG_ORIG(MSG_STR_MINUSCLOANGBK) */ { MSG_STR_RF, MSG_STR_MINUSCLOANGBK }, /* MSG_ORIG(MSG_STR_EQ) MSG_ORIG(MSG_STR_DBLEQU) */ { MSG_STR_EQ, MSG_STR_DBLEQU }, /* MSG_ORIG(MSG_STR_CO) MSG_ORIG(MSG_STR_TILDE) */ { MSG_STR_CO, MSG_STR_TILDE }, /* MSG_ORIG(MSG_STR_NT) MSG_ORIG(MSG_STR_BANG) */ { MSG_STR_NT, MSG_STR_BANG }, /* MSG_ORIG(MSG_STR_NW) MSG_ORIG(MSG_STR_NEW) */ { MSG_STR_NW, MSG_STR_NEW }, /* MSG_ORIG(MSG_STR_DL) MSG_ORIG(MSG_STR_DELETE) */ { MSG_STR_DL, MSG_STR_DELETE }, { 0, 0 } }; /* This routine demangles an overloaded operator function */ const char * findop(char * c, int * oplen) { register int i, opl; for (opl = 0; c[opl] && c[opl] != '_'; opl++) ; *oplen = opl; for (i = 0; nplist[i].s1; i++) { if (strncmp(MSG_ORIG(nplist[i].s1), c, opl) == 0) return (MSG_ORIG(nplist[i].s2)); } return (0); } /* * 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 */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #ifndef _STORCLASS_H #define _STORCLASS_H #ifdef __cplusplus extern "C" { #endif /* * STORAGE CLASSES */ #define C_EFCN -1 /* physical end of function */ #define C_NULL 0 #define C_AUTO 1 /* automatic variable */ #define C_EXT 2 /* external symbol */ #define C_STAT 3 /* static */ #define C_REG 4 /* register variable */ #define C_EXTDEF 5 /* external definition */ #define C_LABEL 6 /* label */ #define C_ULABEL 7 /* undefined label */ #define C_MOS 8 /* member of structure */ #define C_ARG 9 /* function argument */ #define C_STRTAG 10 /* structure tag */ #define C_MOU 11 /* member of union */ #define C_UNTAG 12 /* union tag */ #define C_TPDEF 13 /* type definition */ #define C_USTATIC 14 /* undefined static */ #define C_ENTAG 15 /* enumeration tag */ #define C_MOE 16 /* member of enumeration */ #define C_REGPARM 17 /* register parameter */ #define C_FIELD 18 /* bit field */ #define C_BLOCK 100 /* ".bb" or ".eb" */ #define C_FCN 101 /* ".bf" or ".ef" */ #define C_EOS 102 /* end of structure */ #define C_FILE 103 /* file name */ /* * The following storage class is a "dummy" used only by STS * for line number entries reformatted as symbol table entries */ #define C_LINE 104 #define C_ALIAS 105 /* duplicate tag */ #define C_HIDDEN 106 /* special storage class for external */ /* symbols in dmert public libraries */ #define C_SHADOW 107 /* shadow symbol */ #ifdef __cplusplus } #endif #endif /* _STORCLASS_H */ /* * 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 */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #ifndef _SYMS_H #define _SYMS_H /* * Hammerhead: syms.h + storclass.h were removed from the public head/ header * set in 9b1f00375a ("delete public headers with zero consumers"). The premise * held only for PUBLIC consumers — cmd/sgs/libelf/misc/nlist.c still includes * "syms.h" as a build-local header. They now live privately beside nlist.c * instead of shipping to /usr/include; the include below is local accordingly. */ /* Storage Classes are defined in storclass.h */ #include "storclass.h" #ifdef __cplusplus extern "C" { #endif /* Number of characters in a symbol name */ #define SYMNMLEN 8 /* Number of characters in a file name */ #define FILNMLEN 14 /* Number of array dimensions in auxiliary entry */ #define DIMNUM 4 struct syment { union { char _n_name[SYMNMLEN]; /* old COFF version */ struct { long _n_zeroes; /* new == 0 */ long _n_offset; /* offset into string table */ } _n_n; char *_n_nptr[2]; /* allows for overlaying */ } _n; unsigned long n_value; /* value of symbol */ short n_scnum; /* section number */ unsigned short n_type; /* type and derived type */ char n_sclass; /* storage class */ char n_numaux; /* number of aux. entries */ }; #define n_name _n._n_name #define n_nptr _n._n_nptr[1] #define n_zeroes _n._n_n._n_zeroes #define n_offset _n._n_n._n_offset /* * Relocatable symbols have a section number of the * section in which they are defined. Otherwise, section * numbers have the following meanings: */ /* undefined symbol */ #define N_UNDEF 0 /* value of symbol is absolute */ #define N_ABS -1 /* special debugging symbol -- value of symbol is meaningless */ #define N_DEBUG -2 /* indicates symbol needs transfer vector (preload) */ #define N_TV (unsigned short)-3 /* indicates symbol needs transfer vector (postload) */ #define P_TV (unsigned short)-4 /* * The fundamental type of a symbol packed into the low * 4 bits of the word. */ #define _EF ".ef" #define T_NULL 0 #define T_ARG 1 /* function argument (only used by compiler) */ #define T_CHAR 2 /* character */ #define T_SHORT 3 /* short integer */ #define T_INT 4 /* integer */ #define T_LONG 5 /* long integer */ #define T_FLOAT 6 /* floating point */ #define T_DOUBLE 7 /* double word */ #define T_STRUCT 8 /* structure */ #define T_UNION 9 /* union */ #define T_ENUM 10 /* enumeration */ #define T_MOE 11 /* member of enumeration */ #define T_UCHAR 12 /* unsigned character */ #define T_USHORT 13 /* unsigned short */ #define T_UINT 14 /* unsigned integer */ #define T_ULONG 15 /* unsigned long */ /* * derived types are: */ #define DT_NON 0 /* no derived type */ #define DT_PTR 1 /* pointer */ #define DT_FCN 2 /* function */ #define DT_ARY 3 /* array */ /* * type packing constants */ #define N_BTMASK 017 #define N_TMASK 060 #define N_TMASK1 0300 #define N_TMASK2 0360 #define N_BTSHFT 4 #define N_TSHIFT 2 /* * MACROS */ /* Basic Type of x */ #define BTYPE(x) ((x) & N_BTMASK) /* Is x a pointer ? */ #define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT)) /* Is x a function ? */ #define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT)) /* Is x an array ? */ #define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT)) /* Is x a structure, union, or enumeration TAG? */ #define ISTAG(x) ((x) == C_STRTAG || (x) == C_UNTAG || (x) == C_ENTAG) #define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) /* * AUXILIARY ENTRY FORMAT */ union auxent { struct { long x_tagndx; /* str, un, or enum tag indx */ union { struct { unsigned short x_lnno; /* declaration line */ /* number */ unsigned short x_size; /* str, union, array */ /* size */ } x_lnsz; long x_fsize; /* size of function */ } x_misc; union { struct /* if ISFCN, tag, or .bb */ { long x_lnnoptr; /* ptr to fcn line # */ long x_endndx; /* entry ndx past */ /* block end */ } x_fcn; struct /* if ISARY, up to 4 dimen. */ { unsigned short x_dimen[DIMNUM]; } x_ary; } x_fcnary; unsigned short x_tvndx; /* tv index */ } x_sym; struct { char x_fname[FILNMLEN]; } x_file; struct { long x_scnlen; /* section length */ unsigned short x_nreloc; /* number of reloc entries */ unsigned short x_nlinno; /* number of line numbers */ } x_scn; struct { long x_tvfill; /* tv fill value */ unsigned short x_tvlen; /* length of .tv */ unsigned short x_tvran[2]; /* tv range */ } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ }; #define SYMENT struct syment #define SYMESZ 18 /* sizeof(SYMENT) */ #define AUXENT union auxent #define AUXESZ 18 /* sizeof(AUXENT) */ /* Defines for "special" symbols */ #define _ETEXT "etext" #define _EDATA "edata" #define _END "end" #define _START "_start" #ifdef __cplusplus } #endif #endif /* _SYMS_H */