Esempio n. 1
0
BinaryFile* ElfArchiveFile::GetMember(int i)
{
	// Sanity checks on the index
	if (i < 0) return 0;
	if (i >= m_FileMap.size()) return 0;

	// Lazy creation. Check to see if already created
	if (i >= m_Members.size() || (m_Members[i] == 0))
	{
		// Now we have to create one. We set the constructor argument
		// bArchive to true, so it knows it's an archive member
		BinaryFile* pBF = new ElfBinaryFile(true);
		if (pBF == 0) return 0;
		// Load the file for the user. First find the offset
		int iOffset = m_Offsets[i];
		if (iOffset == 0) return 0;
		if (elf_rand(m_arf, iOffset) != iOffset)
		{
			return 0;
		}
		Elf* elf;				// Elf handle for the new member
		if ((elf = elf_begin(m_filedes, ELF_C_READ, m_arf)) == 0)
		{
			return 0;
		}
		// We have to get our father to load the file, since he is a
		// friend of class BinaryFile, but we aren't
		if (PostLoadMember(pBF, elf) == 0) return 0;
		m_Members[i] = pBF;
		return pBF;
	}
	// Else already seen
	return m_Members[i];
}
Esempio n. 2
0
bool ElfArchiveFile::Load(const char* pName)
{
	// Load the elf file
	Elf* elf;

	m_filedes = open(pName, O_RDONLY);
	if (m_filedes == -1)
	{
		printf("Could not open %s\n", pName);
		return false;
	}

	elf_version(EV_CURRENT);
	m_arf = elf_begin(m_filedes, ELF_C_READ, (Elf*)0);
	if (elf_kind(m_arf) != ELF_K_AR)
	{
		printf("Error - %s is not an archive (.a) file\n", pName);
		return false;
	}

	// Load the symbol table. We assume that each member has at
	// least one symbol.
	// We want a map from symbol to index; to do this, we need to know
	// the current index and last offset seen
	int iLastOffset = 0;
	int iOffset = 0;
	unsigned int uNumSyms;
	int iIndex = -1;		// 0,1,2... for 1st,2nd,3rd... member

    Elf_Arsym* asym;
    asym = elf_getarsym(m_arf, &uNumSyms);
	uNumSyms--;
    if (asym == 0)
    {
        printf("Get archive symbol table failed\n");
        return false;
    }

	for (unsigned u=0; u < uNumSyms; u++)
	{
		iOffset = asym[u].as_off;
		// Last entry is null, but should never see it
		if (iOffset == 0) break;
		if (iOffset != iLastOffset)
		{
			// This is a new member. Use a new index
			iIndex++;
			iLastOffset = iOffset;

			// Seek to that member
			if (elf_rand(m_arf, iOffset) == 0)
			{
				printf("Could not seek to offset %d\n", iOffset);
				return false;
			}
			if ((elf = elf_begin(m_filedes, ELF_C_READ, m_arf)) == 0)
			{
				printf("Could not begin member at offset %d\n", iOffset);
				return false;
			}
			Elf_Arhdr* ahdr;
			ahdr = elf_getarhdr(elf);
			if (ahdr == 0)
			{
				printf("Could not get header information "
					"for member at offset %d\n", iOffset);
				return false;
			}
			// Add the name to the map
			m_FileMap[ahdr->ar_name] = iIndex;
			// And to the vector of pointers to file names
			m_FileNames.push_back(ahdr->ar_name);
			// Also add the offset. These are supposed to be relatively
			// implementation independant
			m_Offsets.push_back(iOffset);
		}
		// Add an entry to the symbol->offset map
		m_SymMap[asym[u].as_name] = iIndex;
	}

	// Now we know the correct size for the vector of members.
	// Ugh - can't call constructor any more
	//m_Members.vector(GetNumMembers(), (BinaryFile*)0);
	m_Members.reserve(GetNumMembers());

	return true;
}
Esempio n. 3
0
/*
 * Read the archive symbol table.  For each symbol in the table, determine
 * whether that symbol satisfies an unresolved reference, tentative reference,
 * or a reference that expects hidden or protected visibility.  If so, the
 * corresponding object from the archive is processed.  The archive symbol
 * table is searched until we go through a complete pass without satisfying any
 * unresolved symbols
 *
 * entry:
 *	name - Name of archive
 *	fd - Open file descriptor for archive
 *	adp - Archive descriptor
 *	ofl - output descriptor
 *	found - Address of variable to set to TRUE if any objects are extracted
 *	rej - Rejection descriptor to pass to ld_process_ifl().
 *
 * exit:
 *	Returns FALSE on fatal error. On success, *found will be TRUE
 *	if any object was extracted, rej will be set if any object
 *	was rejected, and TRUE is returned.
 */
static Boolean
ar_extract_bysym(const char *name, int fd, Ar_desc *adp,
    Ofl_desc *ofl, Boolean *found, Rej_desc *rej)
{
	Elf_Arsym *	arsym;
	Elf *		arelf;
	Ar_aux *	aup;
	Sym_desc *	sdp;
	const char	*arname, *arpath;
	Boolean		again = FALSE;
	uintptr_t	err;

	/*
	 * An archive without a symbol table should not reach this function,
	 * because it can only get past ld_ar_setup() in the case where
	 * the archive is first seen under the influence of '-z allextract'.
	 * That will cause the entire archive to be extracted, and any
	 * subsequent reference to the archive will be ignored by
	 * ld_process_archive().
	 */
	if (adp->ad_start == NULL) {
		assert(adp->ad_start != NULL);
		return (TRUE);
	}

	/*
	 * Loop through archive symbol table until we make a complete pass
	 * without satisfying an unresolved reference.  For each archive
	 * symbol, see if there is a symbol with the same name in ld's
	 * symbol table.  If so, and if that symbol is still unresolved or
	 * tentative, process the corresponding archive member.
	 */
	do {
		DBG_CALL(Dbg_file_ar(ofl->ofl_lml, name, again));
		DBG_CALL(Dbg_syms_ar_title(ofl->ofl_lml, name, again));
		again = FALSE;

		for (arsym = adp->ad_start, aup = adp->ad_aux; arsym->as_name;
		    ++arsym, ++aup) {
			Ar_mem		*amp;
			Sym		*sym;
			Boolean		visible = TRUE;
			Boolean		vers;
			Ifl_desc	*ifl;

			/*
			 * If the auxiliary members value indicates that this
			 * member has been processed then this symbol will have
			 * been added to the output file image already or the
			 * object was rejected in which case we don't want to
			 * process it again.
			 */
			if (aup->au_mem == FLG_ARMEM_PROC)
				continue;

			/*
			 * If the auxiliary symbol element is non-zero lookup
			 * the symbol from the internal symbol table.
			 */
			if ((sdp = aup->au_syms) == NULL) {
				if ((sdp = ld_sym_find(arsym->as_name,
				    /* LINTED */
				    (Word)arsym->as_hash, NULL, ofl)) == NULL) {
					DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml,
					    name, arsym));
					continue;
				}
				aup->au_syms = sdp;
			}

			/*
			 * With '-z allextract', all members will be extracted.
			 *
			 * This archive member is a candidate for extraction if
			 * the internal symbol originates from an explicit file,
			 * and represents an undefined or tentative symbol.
			 *
			 * By default, weak references do not cause archive
			 * extraction, however the -zweakextract flag overrides
			 * this default.
			 *
			 * If this symbol has already been bound to a versioned
			 * shared object, but the shared objects version is not
			 * available, then a definition of this symbol from
			 * within the archive is a better candidate.  Similarly,
			 * if this symbol has been bound to a shared object, but
			 * the original reference expected hidden or protected
			 * visibility, then a definition of this symbol from
			 * within the archive is a better candidate.
			 */
			vers = TRUE;
			ifl = sdp->sd_file;

			sym = sdp->sd_sym;

			if (sdp->sd_ref == REF_DYN_NEED) {
				uchar_t	vis;

				if (ifl->ifl_vercnt) {
					Word		vndx;
					Ver_index	*vip;

					vndx = sdp->sd_aux->sa_dverndx;
					vip = &ifl->ifl_verndx[vndx];
					if (!(vip->vi_flags & FLG_VER_AVAIL))
						vers = FALSE;
				}

				vis = ELF_ST_VISIBILITY(sym->st_other);
				visible = sym_vis[vis];
			}

			if (((ifl->ifl_flags & FLG_IF_NEEDED) == 0) ||
			    (visible && vers && (sym->st_shndx != SHN_UNDEF) &&
			    (sym->st_shndx != SHN_COMMON)) ||
			    ((ELF_ST_BIND(sym->st_info) == STB_WEAK) &&
			    (!(ofl->ofl_flags1 & FLG_OF1_WEAKEXT)))) {
				DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml,
				    name, arsym));
				continue;
			}

			/*
			 * Determine if we have already extracted this member,
			 * and if so reuse the Ar_mem information.
			 */
			if ((amp = aup->au_mem) != 0) {
				arelf = amp->am_elf;
				arname = amp->am_name;
				arpath = amp->am_path;
			} else {
				/*
				 * Set up a new elf descriptor for this member.
				 */
				if (elf_rand(adp->ad_elf, arsym->as_off) !=
				    arsym->as_off) {
					ld_eprintf(ofl, ERR_ELF,
					    MSG_INTL(MSG_ELF_ARMEM), name,
					    EC_WORD(arsym->as_off),
					    demangle(arsym->as_name));
					return (FALSE);
				}

				if ((arelf = elf_begin(fd, ELF_C_READ,
				    adp->ad_elf)) == NULL) {
					ld_eprintf(ofl, ERR_ELF,
					    MSG_INTL(MSG_ELF_BEGIN), name);
					return (FALSE);
				}

				/* Get member filename */
				if ((arname = ar_member_name(name, arelf,
				    ofl)) == NULL)
					return (FALSE);

				/* Construct the member's full pathname */
				if ((arpath = ar_member_path(name, arname)) ==
				    NULL)
					return (S_ERROR);

				/*
				 * Determine whether the support libraries wish
				 * to process this open. See comments in
				 * ld_process_open().
				 */
				ld_sup_open(ofl, &arpath, &arname, &fd,
				    (FLG_IF_EXTRACT | FLG_IF_NEEDED),
				    &arelf, adp->ad_elf, arsym->as_off,
				    elf_kind(arelf));
				if (arelf == NULL) {
					/* Ignore this archive member */
					aup->au_mem = FLG_ARMEM_PROC;
					continue;
				}
			}

			/*
			 * The symbol for which this archive member is being
			 * processed may provide a better alternative to the
			 * symbol that is presently known.  Two cases are
			 * covered:
			 *
			 *  i.	The present symbol represents tentative data.
			 *	The archive member may provide a data
			 *	definition symbol.
			 *  ii.	The present symbol represents a reference that
			 *	has seen a definition within a shared object
			 *	dependency, but the reference expects to be
			 *	reduced to hidden or protected visibility.
			 */
			if ((sym->st_shndx == SHN_COMMON) ||
			    (visible == FALSE)) {
				/*
				 * If we don't already have a member structure
				 * allocate one.
				 */
				if (!amp) {
					if ((amp = libld_calloc(sizeof (Ar_mem),
					    1)) == NULL)
						return (FALSE);
					amp->am_elf = arelf;
					amp->am_name = arname;
					amp->am_path = arpath;
				}
				DBG_CALL(Dbg_syms_ar_checking(ofl->ofl_lml,
				    name, arname, arsym));
				if ((err = process_member(amp, arsym->as_name,
				    sdp, ofl)) == S_ERROR)
					return (FALSE);

				/*
				 * If it turns out that we don't need this
				 * member simply initialize all other auxiliary
				 * entries that match this offset with this
				 * members address.  In this way we can resuse
				 * this information if we recurse back to this
				 * symbol.
				 */
				if (err == 0) {
					if (aup->au_mem == NULL)
						ld_ar_member(adp, arsym,
						    aup, amp);
					continue;
				}
			}

			/*
			 * Process the archive member.  Retain any error for
			 * return to the caller.
			 */
			DBG_CALL(Dbg_syms_ar_resolve(ofl->ofl_lml,
			    name, arname, arsym));
			switch (ar_input(fd, adp, ofl, arelf, arpath,
			    rej)) {
			case S_ERROR:
				return (FALSE);
			case 0:
				/*
				 * Mark the member as extracted so that we
				 * don't try and process it again on a rescan.
				 */
				ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC);
				continue;
			}

			/*
			 * Note that this archive has contributed something
			 * during this specific operation, and also signal
			 * the need to rescan the archive.
			 */
			*found = again = TRUE;

			ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC);
		}
	} while (again);

	return (TRUE);
}
Esempio n. 4
0
/*
 * Extract every object in the given archive directly without going through
 * the symbol table.
 *
 * entry:
 *	name - Name of archive
 *	fd - Open file descriptor for archive
 *	adp - Archive descriptor
 *	ofl - output descriptor
 *	found - Address of variable to set to TRUE if any objects are extracted
 *	rej - Rejection descriptor to pass to ld_process_ifl().
 *
 * exit:
 *	Returns FALSE on fatal error. On success, *found will be TRUE
 *	if any object was extracted, rej will be set if any object
 *	was rejected, and TRUE is returned.
 */
static Boolean
ar_extract_all(const char *name, int fd, Ar_desc *adp, Ofl_desc *ofl,
    Boolean *found, Rej_desc *rej)
{
	Elf_Cmd		cmd = ELF_C_READ;
	Elf		*arelf;
	const char	*arname, *arpath;
	size_t		off, next_off;

	DBG_CALL(Dbg_file_ar(ofl->ofl_lml, name, FALSE));

	while ((arelf = elf_begin(fd, cmd, adp->ad_elf)) != NULL) {
		/*
		 * Call elf_next() so that the next call to elf_begin() will
		 * fetch the archive member following this one. We do this now
		 * because it simplifies the logic below, and because the
		 * support libraries called below can set our handle to NULL.
		 */
		cmd = elf_next(arelf);

		/* Get member filename */
		if ((arname = ar_member_name(name, arelf, ofl)) == NULL)
			return (FALSE);

		/*
		 * Skip the symbol table, string table, or any other special
		 * archive member. These all start with a '/' character.
		 */
		if (*arname == '/') {
			(void) elf_end(arelf);
			continue;
		}

		/* Obtain archive member offset within the file */
		off = _elf_getarhdrbase(arelf);

		/*
		 * ld_sup_open() will reset the current iteration point for
		 * the archive to point at this member rather than the next
		 * one for the benefit of the support libraries. Since
		 * this loop relies on the current position not changing
		 * underneath it, we save and restore the current
		 * position around the support library call.
		 */
		next_off = _elf_getnextoff(adp->ad_elf);

		/* Construct the member's full pathname */
		if ((arpath = ar_member_path(name, arname)) == NULL)
			return (S_ERROR);

		/*
		 * Determine whether the support libraries wish to process
		 * this open. See comments in ld_process_open().
		 */
		ld_sup_open(ofl, &arpath, &arname, &fd,
		    (FLG_IF_EXTRACT | FLG_IF_NEEDED), &arelf, adp->ad_elf,
		    off, elf_kind(arelf));
		(void) elf_rand(adp->ad_elf, next_off);
		if (arelf == NULL)
			continue;

		DBG_CALL(Dbg_syms_ar_force(ofl->ofl_lml, name, arname));
		switch (ar_input(fd, adp, ofl, arelf, arpath, rej)) {
		case S_ERROR:
			return (FALSE);
		case 0:
			continue;
		}

		*found = TRUE;

	}

	/*
	 * As this archive was extracted by -z allextract, the ar_aux table
	 * and elf descriptor can be freed.  Set ad_elf to NULL to mark the
	 * archive is completely processed.
	 */
	(void) elf_end(adp->ad_elf);
	adp->ad_elf = NULL;

	return (TRUE);
}
Esempio n. 5
0
static int
archive(const char *file, int fd, Elf *elf, uint_t flags,
    const char *wname, int wfd, uchar_t osabi)
{
	Elf_Cmd		cmd = ELF_C_READ;
	Elf_Arhdr	*arhdr;
	Elf		*_elf = NULL;
	size_t		ptr;
	Elf_Arsym	*arsym = NULL;

	/*
	 * Determine if the archive symbol table itself is required.
	 */
	if ((flags & FLG_SHOW_SYMBOLS) &&
	    match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) {
		/*
		 * Get the archive symbol table.
		 */
		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
			/*
			 * The arsym could be 0 even though there was no error.
			 * Print the error message only when there was
			 * real error from elf_getarsym().
			 */
			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
			return (0);
		}
	}

	/*
	 * Print the archive symbol table only when the archive symbol
	 * table exists and it was requested to print.
	 */
	if (arsym) {
		size_t		cnt;
		char		index[MAXNDXSIZE];
		size_t		offset = 0, _offset = 0;
		const char	*fmt_arsym1, *fmt_arsym2;

		/*
		 * Print out all the symbol entries. The format width used
		 * corresponds to whether the archive symbol table is 32
		 * or 64-bit. We see them via Elf_Arhdr as size_t values
		 * in either case with no information loss (see the comments
		 * in libelf/getarsym.c) so this is done simply to improve
		 * the user presentation.
		 */
		if (_elf_getarsymwordsize(elf) == 8) {
			dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB_64));
			dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS_64));

			fmt_arsym1 = MSG_ORIG(MSG_FMT_ARSYM1_64);
			fmt_arsym2 = MSG_ORIG(MSG_FMT_ARSYM2_64);
		} else {
			dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB_32));
			dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS_32));

			fmt_arsym1 = MSG_ORIG(MSG_FMT_ARSYM1_32);
			fmt_arsym2 = MSG_ORIG(MSG_FMT_ARSYM2_32);
		}

		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
			/*
			 * For each object obtain an elf descriptor so that we
			 * can establish the members name.  Note, we have had
			 * archives where the archive header has not been
			 * obtainable so be lenient with errors.
			 */
			if ((offset == 0) || ((arsym->as_off != 0) &&
			    (arsym->as_off != _offset))) {

				if (_elf)
					(void) elf_end(_elf);

				if (elf_rand(elf, arsym->as_off) !=
				    arsym->as_off) {
					failure(file, MSG_ORIG(MSG_ELF_RAND));
					arhdr = NULL;
				} else if ((_elf = elf_begin(fd,
				    ELF_C_READ, elf)) == 0) {
					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
					arhdr = NULL;
				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
					failure(file,
					    MSG_ORIG(MSG_ELF_GETARHDR));
					arhdr = NULL;
				}

				_offset = arsym->as_off;
				if (offset == 0)
					offset = _offset;
			}

			(void) snprintf(index, MAXNDXSIZE,
			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
			if (arsym->as_off)
				dbg_print(0, fmt_arsym1, index,
				    EC_XWORD(arsym->as_off),
				    arhdr ? arhdr->ar_name :
				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
				    demangle(arsym->as_name, flags) :
				    MSG_INTL(MSG_STR_NULL)));
			else
				dbg_print(0, fmt_arsym2, index,
				    EC_XWORD(arsym->as_off));
		}

		if (_elf)
			(void) elf_end(_elf);

		/*
		 * If we only need the archive symbol table return.
		 */
		if ((flags & FLG_SHOW_SYMBOLS) &&
		    match(MATCH_F_STRICT | MATCH_F_NAME,
		    MSG_ORIG(MSG_ELF_ARSYM), -1, -1))
			return (0);

		/*
		 * Reset elf descriptor in preparation for processing each
		 * member.
		 */
		if (offset)
			(void) elf_rand(elf, offset);
	}

	/*
	 * Process each object within the archive.
	 */
	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
		char	name[MAXPATHLEN];

		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
			return (0);
		}
		if (*arhdr->ar_name != '/') {
			(void) snprintf(name, MAXPATHLEN,
			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);

			switch (elf_kind(_elf)) {
			case ELF_K_AR:
				if (archive(name, fd, _elf, flags,
				    wname, wfd, osabi) == 1)
					return (1);
				break;
			case ELF_K_ELF:
				if (decide(name, fd, _elf, flags,
				    wname, wfd, osabi) == 1)
					return (1);
				break;
			default:
				(void) fprintf(stderr,
				    MSG_INTL(MSG_ERR_BADFILE), name);
				break;
			}
		}

		cmd = elf_next(_elf);
		(void) elf_end(_elf);
	}

	return (0);
}