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]; }
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; }
/* * 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); }
/* * 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); }
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); }