/* * Return the archive member's name. * * entry: * name - Name of archive * arelf - ELF descriptor for archive member. * ofl - output descriptor * * exit: * Returns pointer to archive member name on success, NULL on error. */ static const char * ar_member_name(const char *name, Elf *arelf, Ofl_desc *ofl) { Elf_Arhdr *arhdr; if ((arhdr = elf_getarhdr(arelf)) == NULL) { ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETARHDR), name); return (NULL); } return (arhdr->ar_name); }
static int read_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func, void *arg, int require_ctf) { Elf *melf; Elf_Cmd cmd = ELF_C_READ; Elf_Arhdr *arh; int secnum = 1, found = 0; while ((melf = elf_begin(fd, cmd, elf)) != NULL) { int rc = 0; if ((arh = elf_getarhdr(melf)) == NULL) { elfterminate(file, "Can't get archive header for " "member %d", secnum); } /* skip special sections - their names begin with "/" */ if (*arh->ar_name != '/') { size_t memlen = strlen(file) + 1 + strlen(arh->ar_name) + 1 + 1; char *memname = xmalloc(memlen); snprintf(memname, memlen, "%s(%s)", file, arh->ar_name); switch (elf_kind(melf)) { case ELF_K_AR: rc = read_archive(fd, melf, memname, label, func, arg, require_ctf); break; case ELF_K_ELF: rc = read_file(melf, memname, label, func, arg, require_ctf); break; default: terminate("%s: Unknown elf kind %d\n", memname, elf_kind(melf)); } free(memname); } cmd = elf_next(melf); (void) elf_end(melf); secnum++; if (rc < 0) return (rc); else found += rc; } return (found); }
/* * Process member files of an archive. This function provides * a loop through an archive equivalent the processing of * each_file for individual object files. */ static void print_ar_files(int fd, Elf * elf_file, char *filename) { Elf_Arhdr *p_ar; Elf *arf; Elf_Cmd cmd; Elf_Kind file_type; cmd = ELF_C_READ; archive_name = filename; while ((arf = elf_begin(fd, cmd, elf_file)) != 0) { p_ar = elf_getarhdr(arf); if (p_ar == NULL) { (void) fprintf(stderr, "%s: %s: %s\n", prog_name, filename, elf_errmsg(-1)); return; } if (p_ar->ar_name[0] == '/') { cmd = elf_next(arf); (void) elf_end(arf); continue; } if (!h_flag & !P_flag) { if (p_flag) (void) printf("\n\n%s[%s]:\n", filename, p_ar->ar_name); else { if (A_flag != 0) (void) printf("\n\n%s%s[%s]:\n", A_header, filename, p_ar->ar_name); else (void) printf("\n\n%s[%s]:\n", filename, p_ar->ar_name); } } file_type = elf_kind(arf); if (file_type == ELF_K_ELF) { process(arf, p_ar->ar_name); } else { (void) fprintf(stderr, gettext( "%s: %s: invalid file type\n"), prog_name, p_ar->ar_name); cmd = elf_next(arf); (void) elf_end(arf); errflag++; continue; } cmd = elf_next(arf); (void) elf_end(arf); } /* end while */ }
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; } }
/* * Given an elf object,ar(1) filename, and based on the output style * and radix format the various sections and their length will be printed * or the size of the text, data, bss sections will be printed out. */ static int handle_elf(char const *name) { GElf_Ehdr elfhdr; GElf_Shdr shdr; Elf *elf, *elf1; Elf_Arhdr *arhdr; Elf_Scn *scn; Elf_Cmd elf_cmd; int exit_code, fd; if (name == NULL) return (RETURN_NOINPUT); if ((fd = open(name, O_RDONLY, 0)) < 0) return (RETURN_NOINPUT); elf_cmd = ELF_C_READ; elf1 = elf_begin(fd, elf_cmd, NULL); while ((elf = elf_begin(fd, elf_cmd, elf1)) != NULL) { arhdr = elf_getarhdr(elf); if (elf_kind(elf) == ELF_K_NONE && arhdr == NULL) { (void) elf_end(elf); (void) elf_end(elf1); (void) close(fd); return (RETURN_DATAERR); } if (elf_kind(elf) != ELF_K_ELF || (gelf_getehdr(elf, &elfhdr) == NULL)) { elf_cmd = elf_next(elf); (void) elf_end(elf); warnx("%s: File format not recognized", arhdr->ar_name); continue; } /* Core dumps are handled seperately */ if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) { exit_code = handle_core(name, elf, &elfhdr); (void) elf_end(elf); (void) elf_end(elf1); (void) close(fd); return (exit_code); } else { scn = NULL; if (style == STYLE_BERKELEY) { berkeley_header(); while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != NULL) berkeley_calc(&shdr); } } else { sysv_header(name, arhdr); scn = NULL; while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != NULL) sysv_calc(elf, &elfhdr, &shdr); } } if (style == STYLE_BERKELEY) { if (arhdr != NULL) { berkeley_footer(name, arhdr->ar_name, "ex"); } else { berkeley_footer(name, NULL, "ex"); } } else { sysv_footer(); } } elf_cmd = elf_next(elf); (void) elf_end(elf); } (void) elf_end(elf1); (void) close(fd); return (RETURN_OK); }
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; }
int each_file(char *cur_file, Cmd_Info *cmd_info) { Elf *elf = 0; Elf_Cmd cmd; Elf *arf = 0; Elf_Arhdr *mem_header; char *cur_filenm = NULL; int code = 0; int error = 0, err = 0; int ar_file = 0; int fdartmp; int fd; int oflag; if (cmd_info->flags & MIGHT_CHG) oflag = O_RDWR; else oflag = O_RDONLY; if ((fd = open(cur_file, oflag)) == -1) { error_message(OPEN_ERROR, SYSTEM_ERROR, strerror(errno), prog, cur_file); return (FAILURE); } /* * Note, elf_begin requires ELF_C_READ even if MIGHT_CHK is in effect. * libelf does not allow elf_begin() with ELF_C_RDWR when processing * archive file members. Because we are limited to ELF_C_READ use, any * ELF data modification must be provided by updating a copy of * the data, rather than updating the original file data. */ cmd = ELF_C_READ; if ((arf = elf_begin(fd, cmd, (Elf *)0)) == 0) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog); (void) elf_end(arf); (void) close(fd); /* done processing this file */ return (FAILURE); } if ((elf_kind(arf) == ELF_K_AR)) { ar_file = 1; if (CHK_OPT(cmd_info, MIGHT_CHG)) { artmpfile = tempnam(TMPDIR, "mcs2"); if ((fdartmp = open(artmpfile, O_WRONLY | O_APPEND | O_CREAT, (mode_t)0666)) == NULL) { error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno), prog, artmpfile); (void) elf_end(arf); (void) close(fd); exit(FAILURE); } /* write magic string to artmpfile */ if ((write(fdartmp, ARMAG, SARMAG)) != SARMAG) { error_message(WRITE_ERROR, SYSTEM_ERROR, strerror(errno), prog, artmpfile, cur_file); mcs_exit(FAILURE); } } } else { ar_file = 0; cur_filenm = cur_file; } /* * Holds temporary file; * if archive, holds the current member file if it has an ehdr, * and there were no errors in * processing the object file. */ elftmpfile = tempnam(TMPDIR, "mcs1"); while ((elf = elf_begin(fd, cmd, arf)) != 0) { if (ar_file) /* get header info */ { size_t len; if ((mem_header = elf_getarhdr(elf)) == NULL) { error_message(GETARHDR_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog, cur_file, elf_getbase(elf)); (void) elf_end(elf); (void) elf_end(arf); (void) close(fd); (void) unlink(artmpfile); return (FAILURE); } if (cur_filenm != NULL) free(cur_filenm); len = (strlen(cur_file) + 3 + strlen(mem_header->ar_name)); if ((cur_filenm = malloc(len)) == NULL) { error_message(MALLOC_ERROR, PLAIN_ERROR, (char *)0, prog); mcs_exit(FAILURE); } (void) snprintf(cur_filenm, len, "%s[%s]", cur_file, mem_header->ar_name); } if (elf_kind(elf) == ELF_K_ELF) { if ((code = process_file(elf, cur_filenm, cmd_info)) == FAILURE) { if (!ar_file) { (void) elf_end(arf); (void) elf_end(elf); (void) close(fd); return (FAILURE); } else { copy_non_elf_to_temp_ar( fd, elf, fdartmp, mem_header, cur_file, cmd_info); error++; } } else if (ar_file && CHK_OPT(cmd_info, MIGHT_CHG)) { if (code == DONT_BUILD) copy_non_elf_to_temp_ar( fd, elf, fdartmp, mem_header, cur_file, cmd_info); else copy_elf_file_to_temp_ar_file( fdartmp, mem_header, cur_file); } } else { /* * decide what to do with non-ELF file */ if (!ar_file) { error_message(FILE_TYPE_ERROR, PLAIN_ERROR, (char *)0, prog, cur_filenm); (void) close(fd); return (FAILURE); } else { if (CHK_OPT(cmd_info, MIGHT_CHG)) copy_non_elf_to_temp_ar( fd, elf, fdartmp, mem_header, cur_file, cmd_info); } } cmd = elf_next(elf); (void) elf_end(elf); } err = elf_errno(); if (err != 0) { error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(err), prog); error_message(NOT_MANIPULATED_ERROR, PLAIN_ERROR, (char *)0, prog, cur_file); return (FAILURE); } (void) elf_end(arf); if (ar_file && CHK_OPT(cmd_info, MIGHT_CHG)) { (void) close(fdartmp); /* done writing to ar_temp_file */ /* copy ar_temp_file to FILE */ copy_file(fd, cur_file, artmpfile); } else if (code != DONT_BUILD && CHK_OPT(cmd_info, MIGHT_CHG)) copy_file(fd, cur_file, elftmpfile); (void) close(fd); /* done processing this file */ return (error); }
static int 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); }