コード例 #1
0
ファイル: elfd.c プロジェクト: schischi/my_ltrace
static void handle_dynamic_section(elf_info_s *elf, Elf_Scn *scn, GElf_Shdr shdr)
{
    Elf_Data *data;
    GElf_Addr replt_addr;
    size_t replt_count;

    /* get data of .dynamic */
    data = elf_getdata(scn, NULL);

    /* iterate through .dynamic */
    for (size_t i = 0; i < shdr.sh_size / shdr.sh_entsize; ++i) {
        GElf_Dyn dyn;

        // get entries i
        gelf_getdyn(data, i, &dyn);
        // if replt
        if (dyn.d_tag == DT_JMPREL)
            replt_addr = dyn.d_un.d_ptr;
        // if replt_size
        if (dyn.d_tag == DT_PLTRELSZ)
            replt_count = dyn.d_un.d_val;
    }
    LOG(INFO, "Section relplt at 0x%lx (%zu)", replt_addr, replt_count);
    for (size_t i = 1; i < elf->hdr.e_shnum; ++i) {
        Elf_Scn *scn;
        GElf_Shdr shdr;
        scn = elf_getscn(elf->elf, i);
        gelf_getshdr(scn, &shdr);
        if (shdr.sh_addr == replt_addr && shdr.sh_size == replt_count) {
            elf->replt = elf_getdata(scn, NULL);
            elf->replt_count = shdr.sh_size / shdr.sh_entsize;
            break;
        }
    }
}
コード例 #2
0
ファイル: elftree.c プロジェクト: 0omega/platform_development
static int dump_dynamic(struct file_state *f, Elf_Scn *scn, GElf_Shdr *shdr)
{
	struct dyn_state d;
	GElf_Dyn needed_dyn;
	char *needed_name;
	int i;

	d.f = f;
	d.dyn_data = elf_getdata(scn, NULL);
	if (!d.dyn_data) {
		elf_err("elf_getdata failed");
		return -1;
	}
	d.count = shdr->sh_size / shdr->sh_entsize;

	for (i = 0; i < d.count; i++) {
		if (!gelf_getdyn(d.dyn_data, i, &needed_dyn))
			continue;

		if (needed_dyn.d_tag != DT_NEEDED)
			continue;

		needed_name = (char *)f->strtab_data->d_buf
			      + needed_dyn.d_un.d_val;

		dump_needed(f->t, needed_name);
	}

	return 0;
}
コード例 #3
0
ファイル: setdynflag.c プロジェクト: andreiw/polaris
static void
set_flag(char *ifile, ulong_t flval)
{
	Elf *elf;
	Elf_Scn *scn;
	Elf_Data *data;
	GElf_Shdr shdr;
	GElf_Dyn dyn;
	int fd, secidx, nent, i;

	(void) elf_version(EV_CURRENT);

	if ((fd = open(ifile, O_RDWR)) < 0)
		die("Can't open %s", ifile);

	if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL)
		elfdie("Can't start ELF for %s", ifile);

	if ((secidx = findelfsecidx(elf, ".dynamic")) == -1)
		die("Can't find .dynamic section in %s\n", ifile);

	if ((scn = elf_getscn(elf, secidx)) == NULL)
		elfdie("elf_getscn (%d)", secidx);

	if (gelf_getshdr(scn, &shdr) == NULL)
		elfdie("gelf_shdr");

	if ((data = elf_getdata(scn, NULL)) == NULL)
		elfdie("elf_getdata");

	nent = shdr.sh_size / shdr.sh_entsize;
	for (i = 0; i < nent; i++) {
		if (gelf_getdyn(data, i, &dyn) == NULL)
			elfdie("gelf_getdyn");

		if (dyn.d_tag == DT_FLAGS_1) {
			dyn.d_un.d_val |= (Elf64_Xword)flval;

			if (gelf_update_dyn(data, i, &dyn) == 0)
				elfdie("gelf_update_dyn");

			break;
		}
	}

	if (i == nent) {
		die("%s's .dynamic section doesn't have a DT_FLAGS_1 "
		    "field\n", ifile);
	}

	if (elf_update(elf, ELF_C_WRITE) == -1)
		elfdie("Couldn't update %s with changes", ifile);

	(void) elf_end(elf);
	(void) close(fd);
}
コード例 #4
0
ファイル: rpath.c プロジェクト: dilos/dilos-userland
/*
 * Delete the existing runpath from the object.
 *
 * entry:
 *	dynsec - Dynamic section
 *	numdyn - # of elements in dynamic array
 *
 * exit:
 *	Returns True (1) if the dynamic section was modified, and
 *	False (0) otherwise.
 *
 * note:
 *	The way this works is that we look at each item in the
 *	dynamic section and simply remove any DT_RPATH or
 *	DT_RUNPATH entries, copying up anything following in order
 *	to fill the hole. This is all that is needed to completely
 *	remove a runpath from an object. Note that the string is left
 *	in the string table. There is no safe way to remove it, since
 *	we cannot know that it is not used by any other item in the file,
 *	and no way to track or reuse the space if we did remove it.
 *	On the plus side, this means we can always restore the old
 *	runpath without having to add a new string.
 */
static int
remove_runpath(Cache *dynsec, GElf_Word numdyn)
{
	GElf_Dyn	dyn;
	GElf_Word	ndx, cpndx;
	int		changed = 0;

	for (ndx = cpndx = 0; ndx < numdyn; ndx++) {
		if (gelf_getdyn(dynsec->c_data, ndx, &dyn) == NULL)
			msg_elf("gelf_getdyn");

		/* Skip over any runpath element */
		if ((dyn.d_tag == DT_RPATH) || (dyn.d_tag == DT_RUNPATH)) {
			msg_debug("[%d]%s[%d]: skip runpath\n",
			    dynsec->c_ndx, dynsec->c_name, ndx);
			continue;
		}

		/*
		 * If cpndx and ndx differ, it means that we
		 * have skipped over a runpath in an earlier
		 * iteration. In this case, we need to copy
		 * the item in dynamic[ndx] back to dynamic[cpndx].
		 */
		if (ndx != cpndx) {
			msg_debug("[%d]%s[%d]: copy from [%d]\n",
			    dynsec->c_ndx, dynsec->c_name, cpndx, ndx);
			if (gelf_update_dyn(dynsec->c_data, cpndx, &dyn) == 0)
				msg_elf("gelf_update_dyn");
			changed = 1;
		}

		/* Advance copy index to receive next item */
		cpndx++;
	}

	/*
	 * If we removed a runpath element, then we should zero
	 * the slots left at the end. This is not strictly
	 * necessary, since the linker should not look past the
	 * first DT_NULL, but it is good to not leave garbage
	 * lying around.
	 */
	bzero(&dyn, sizeof (dyn));	/* Note: DT_NULL is 0 */
	for (; cpndx < numdyn; cpndx++) {
		msg_debug("[%d]%s[%d]: Set to DT_NULL\n",
		    dynsec->c_ndx, dynsec->c_name, cpndx);
		if (gelf_update_dyn(dynsec->c_data, cpndx, &dyn) == 0)
			msg_elf("gelf_update_dyn");
		changed = 1;
	}

	return (changed);
}
コード例 #5
0
ファイル: ld_dynamic.c プロジェクト: Scarletts/LiteBSD
void
ld_dynamic_load_dso_dynamic(struct ld *ld, struct ld_input *li, Elf *e,
    Elf_Scn *scn, size_t strndx)
{
	GElf_Shdr shdr;
	GElf_Dyn dyn;
	Elf_Data *d;
	int elferr, i, len;
	const char *name;

	if (strndx == SHN_UNDEF)
		return;

	if (gelf_getshdr(scn, &shdr) != &shdr) {
		ld_warn(ld, "%s: gelf_getshdr failed: %s", li->li_name,
		    elf_errmsg(-1));
		return;
	}

	(void) elf_errno();
	if ((d = elf_getdata(scn, NULL)) == NULL) {
		elferr = elf_errno();
		if (elferr != 0)
			ld_warn(ld, "%s: elf_getdata failed: %s", li->li_name,
			    elf_errmsg(elferr));
		return;
	}

	len = d->d_size / shdr.sh_entsize;
	for (i = 0; i < len; i++) {
		if (gelf_getdyn(d, i, &dyn) != &dyn) {
			ld_warn(ld, "%s: gelf_getdyn failed: %s", li->li_name,
			    elf_errmsg(-1));
			continue;
		}
		switch (dyn.d_tag) {
		case DT_SONAME:
			name = elf_strptr(e, strndx, dyn.d_un.d_ptr);
			if (name != NULL &&
			    (li->li_soname = strdup(name)) == NULL)
				ld_fatal_std(ld, "strdup");
			break;
		case DT_NEEDED:
			name = elf_strptr(e, strndx, dyn.d_un.d_ptr);
			if (name != NULL)
				ld_path_search_dso_needed(ld, li->li_file,
				    name);
			break;
		default:
			break;
		}
	}
}
コード例 #6
0
static int find_got(Elf_Data *dyn_data, size_t nr_dyn, unsigned long offset)
{
	size_t i;
	struct sigaction sa, old_sa;

	for (i = 0; i < nr_dyn; i++) {
		GElf_Dyn dyn;

		if (gelf_getdyn(dyn_data, i, &dyn) == NULL)
			return -1;

		if (dyn.d_tag != DT_PLTGOT)
			continue;

		got_addr = (unsigned long)dyn.d_un.d_val + offset;
		plthook_got_ptr = (void *)got_addr;
		plthook_resolver_addr = plthook_got_ptr[2];

		/*
		 * The GOT region is write-protected on some systems.
		 * In that case, we need to use mprotect() to overwrite
		 * the address of resolver function.  So install signal
		 * handler to catch such cases.
		 */
		sa.sa_sigaction = segv_handler;
		sa.sa_flags = SA_SIGINFO;
		sigfillset(&sa.sa_mask);
		if (sigaction(SIGSEGV, &sa, &old_sa) < 0) {
			pr_dbg("error during install sig handler\n");
			return -1;
		}

		plthook_got_ptr[2] = (unsigned long)plt_hooker;

		if (sigaction(SIGSEGV, &old_sa, NULL) < 0) {
			pr_dbg("error during recover sig handler\n");
			return -1;
		}

		if (segv_handled) {
			mprotect((void *)(got_addr & ~0xFFF), sizeof(long)*3,
				 PROT_READ);
			segv_handled = false;
		}

		pr_dbg2("found GOT at %p (PLT resolver: %#lx)\n",
			plthook_got_ptr, plthook_resolver_addr);

		break;
	}
	return 0;
}
コード例 #7
0
ファイル: elftree.c プロジェクト: 0omega/platform_development
static int find_dyn(struct dyn_state *d, GElf_Sxword tag, GElf_Dyn *dyn_out)
{
	int i;

	for (i = 0; i < d->count; i++) {
		if (!gelf_getdyn(d->dyn_data, i, dyn_out))
			continue;

		if (dyn_out->d_tag == tag)
			return 0;
	}

	return -1;
}
コード例 #8
0
ファイル: plt.c プロジェクト: pombredanne/mithrandir
/**
  MIPS ABI Supplement:

  DT_PLTGOT This member holds the address of the .got section.

  DT_MIPS_SYMTABNO This member holds the number of entries in the
  .dynsym section.

  DT_MIPS_LOCAL_GOTNO This member holds the number of local global
  offset table entries.

  DT_MIPS_GOTSYM This member holds the index of the first dyamic
  symbol table entry that corresponds to an entry in the gobal offset
  table.

 */
int
arch_elf_init(struct ltelf *lte, struct library *lib)
{
	Elf_Scn *scn;
	GElf_Shdr shdr;

	/* FIXME: for CPIC we should really scan both GOT tables
	 * to pick up relocations to external functions.  Right now
	 * function pointers from the main binary to external functions
	 * can't be traced in CPIC mode.  */
	if (mips_elf_is_cpic(lte->ehdr.e_flags)) {
		return 0; /* We are already done.  */
	}

	if (elf_get_section_type(lte, SHT_DYNAMIC, &scn, &shdr) < 0
	    || scn == NULL) {
	fail:
		error(0, 0, "Couldn't get SHT_DYNAMIC: %s",
		      elf_errmsg(-1));
		return -1;
	}

	Elf_Data *data = elf_loaddata(scn, &shdr);
	if (data == NULL)
		goto fail;

	size_t j;
	for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
		GElf_Dyn dyn;
		if (gelf_getdyn(data, j, &dyn) == NULL)
			goto fail;

		if(dyn.d_tag == DT_PLTGOT) {
			lte->arch.pltgot_addr = dyn.d_un.d_ptr;
		}
		if(dyn.d_tag == DT_MIPS_LOCAL_GOTNO){
			lte->arch.mips_local_gotno = dyn.d_un.d_val;
		}
		if(dyn.d_tag == DT_MIPS_GOTSYM){
			lte->arch.mips_gotsym = dyn.d_un.d_val;
		}
	}

	/* Tell the generic code how many dynamic trace:able symbols
	 * we've got.  */
	lte->relplt_count = lte->dynsym_count - lte->arch.mips_gotsym;
	return 0;
}
コード例 #9
0
ファイル: PatchEntry.cpp プロジェクト: yurizhykin/selfrando
static ElfDynamicInfo* FindDynamicInit(Elf *e) {
    auto dyn_scn = FindSectionByType(e, SHT_DYNAMIC);
    Elf_Data *dyn_data = nullptr;
    GElf_Dyn dyn;
    for (;;) {
        dyn_data = elf_getdata(dyn_scn.first, dyn_data);
        if (dyn_data == nullptr)
            break;
        for (size_t i = 0;; i++) {
            gelf_getdyn(dyn_data, i, &dyn);
            if (dyn.d_tag == DT_INIT)
                return new ElfDynamicInfo(dyn_scn, dyn_data, i, dyn);
            if (dyn.d_tag == DT_NULL)
                break;
        }
    }
    return nullptr;
}
コード例 #10
0
ファイル: elfp.c プロジェクト: nwnk/elflets
static int
has_dt_debug(Elf *elf, GElf_Ehdr *ehdr)
{
    int i;

    for (i = 0; i < ehdr->e_phnum; i++) {
	GElf_Phdr phdr;
	GElf_Shdr shdr;
	Elf_Scn *scn;
	Elf_Data *data;
	unsigned int j;

	if (gelf_getphdr(elf, i, &phdr) == NULL)
	    continue;

	if (phdr.p_type != PT_DYNAMIC)
	    continue;

	scn = gelf_offscn(elf, phdr.p_offset);

	if (gelf_getshdr(scn, &shdr) == NULL)
	    continue;

	if (shdr.sh_type != SHT_DYNAMIC)
	    continue;

	if ((data = elf_getdata(scn, NULL)) == NULL)
	    continue;

	for (j = 0;
	     j < shdr.sh_size / gelf_fsize(elf, ELF_T_DYN, 1, EV_CURRENT);
	     j++) {
	    GElf_Dyn dyn;
	    if (gelf_getdyn(data, j, &dyn)) {
		if (dyn.d_tag == DT_DEBUG)
		    return 1;
	    }
	}
    }

    return 0;
}
コード例 #11
0
ファイル: elfcreator.c プロジェクト: acmel/dwarves
static void remove_dyn(ElfCreator *ctor, size_t idx)
{
	size_t cnt;

	for (cnt = idx; cnt < ctor->dynshdr->sh_size/ctor->dynshdr->sh_entsize;
			cnt++) {
		GElf_Dyn *dyn, dyn_mem;

		if (cnt+1 == ctor->dynshdr->sh_size/ctor->dynshdr->sh_entsize) {
			memset(&dyn_mem, '\0', sizeof(dyn_mem));
			gelf_update_dyn(ctor->dyndata, cnt, &dyn_mem);
			break;
		}

		dyn = gelf_getdyn(ctor->dyndata, cnt+1, &dyn_mem);
		gelf_update_dyn(ctor->dyndata, cnt, dyn);
	}
	ctor->dynshdr->sh_size--;
	gelf_update_shdr(ctor->dynscn, ctor->dynshdr);
	update_dyn_cache(ctor);
}
コード例 #12
0
ファイル: rpmfileutil.c プロジェクト: Tojaj/rpm
static int is_prelinked(int fdno)
{
    int prelinked = 0;
#if HAVE_GELF_H && HAVE_LIBELF
    Elf *elf = NULL;
    Elf_Scn *scn = NULL;
    Elf_Data *data = NULL;
    GElf_Ehdr ehdr;
    GElf_Shdr shdr;
    GElf_Dyn dyn;

    (void) elf_version(EV_CURRENT);

    if ((elf = elf_begin (fdno, ELF_C_READ, NULL)) == NULL ||
	       elf_kind(elf) != ELF_K_ELF || gelf_getehdr(elf, &ehdr) == NULL ||
	       !(ehdr.e_type == ET_DYN || ehdr.e_type == ET_EXEC))
	goto exit;

    while (!prelinked && (scn = elf_nextscn(elf, scn)) != NULL) {
	(void) gelf_getshdr(scn, &shdr);
	if (shdr.sh_type != SHT_DYNAMIC)
	    continue;
	while (!prelinked && (data = elf_getdata (scn, data)) != NULL) {
	    int maxndx = data->d_size / shdr.sh_entsize;

            for (int ndx = 0; ndx < maxndx; ++ndx) {
		(void) gelf_getdyn (data, ndx, &dyn);
		if (!(dyn.d_tag == DT_GNU_PRELINKED || dyn.d_tag == DT_GNU_LIBLIST))
		    continue;
		prelinked = 1;
		break;
	    }
	}
    }

exit:
    if (elf) (void) elf_end(elf);
#endif
    return prelinked;
}
コード例 #13
0
ファイル: elfcreator.c プロジェクト: acmel/dwarves
static GElf_Dyn *get_dyn_by_tag(ElfCreator *ctor, Elf64_Sxword d_tag,
				GElf_Dyn *mem, size_t *idx)
{
	size_t cnt;

	if (!ctor->dyndata)
		return NULL;

	for (cnt = 1; cnt < ctor->dynshdr->sh_size / ctor->dynshdr->sh_entsize;
			cnt++) {
		GElf_Dyn *dyn;

		if ((dyn = gelf_getdyn(ctor->dyndata, cnt, mem)) == NULL)
			break;

		if (dyn->d_tag == d_tag) {
			*idx = cnt;
			return dyn;
		}
	}
	return NULL;
}
コード例 #14
0
ファイル: elfdeps.c プロジェクト: Distrotech/rpm
static void processDynamic(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
{
    Elf_Data *data = NULL;
    while ((data = elf_getdata(scn, data)) != NULL) {
	for (int i = 0; i < (shdr->sh_size / shdr->sh_entsize); i++) {
	    const char *s = NULL;
	    GElf_Dyn dyn_mem, *dyn;

	    dyn = gelf_getdyn (data, i, &dyn_mem);
	    if (dyn == NULL)
		break;

	    switch (dyn->d_tag) {
	    case DT_HASH:
		ei->gotHASH = 1;
		break;
	    case DT_GNU_HASH:
		ei->gotGNUHASH = 1;
		break;
	    case DT_DEBUG:
		ei->gotDEBUG = 1;
		break;
	    case DT_SONAME:
		s = elf_strptr(ei->elf, shdr->sh_link, dyn->d_un.d_val);
		if (s)
		    ei->soname = rstrdup(s);
		break;
	    case DT_NEEDED:
		if (ei->isExec) {
		    s = elf_strptr(ei->elf, shdr->sh_link, dyn->d_un.d_val);
		    if (s)
			addDep(&ei->requires, s, NULL, ei->marker);
		}
		break;
	    }
	}
    }
}
コード例 #15
0
ファイル: elf.cpp プロジェクト: geomsaek/CSCI212_Ass2
int main(int argc, char **argv){
	Elf *elf;
	Elf_Scn *scn = NULL;
	GElf_Shdr shdr;
	Elf_Data *data;
	int fd, ii, count;
	GElf_Dyn sym;
	char* custcustname = NULL;
	char curLib[1000];
	int lib_count = 0, z = 0;

	// do arguement checking

	if (argc != 2){
		cerr << "Usage is: elf filecustname " << endl;
		exit(1);
	}

	// open the file in argv[1] and produce the elf descriptor
	elf_version(EV_CURRENT);

	if ((fd = open(argv[1], O_RDONLY)) == -1){
		cerr << "Could not open file: " << argv[1] << endl;
		exit(1);
	}

	elf = elf_begin(fd, ELF_C_READ, NULL);
	
	// scan through the sections in the file

	while ((scn = elf_nextscn(elf, scn)) != NULL) 
	{
		// get the section header and check to see if the it the
		// .dynamic section
		gelf_getshdr(scn, &shdr);
        if (shdr.sh_type == SHT_DYNAMIC) 
		{
			data = elf_getdata(scn, NULL);
			ii=0;
			do
			{	
				gelf_getdyn(data, ii++, &sym);
				if (sym.d_tag == DT_NEEDED){
					// if we find a element in the section
					// that is a curLib we pull it out
					custname = elf_strptr(elf,shdr.sh_link,sym.d_un.d_ptr);
					if (custname != NULL){
						strcat(curLib,custname); //curLib custnames are added separated by ":"
						strcat(curLib,":");
						lib_count++; //count the number of libraries read
					} 
				}

				if (sym.d_tag == DT_RPATH) {
					custname = elf_strptr(elf,shdr.sh_link,sym.d_un.d_ptr);
					if (custname != NULL){
						char complete_list[5000];
						char lib[100];
						int count = 0;
						//for each curLib, resolve its address
						
						for(int i = 0; i < lib_count; i++) {
							int counter = 0;
							while(curLib[count] != ':'){
								lib[counter++] = curLib[count++];
							}
							lib[counter] = '\0';
							count++;
							
							//if by any chance a curLib cannot be found, exit program
							if(get_replace(complete_list,lib,custname) == false){
								cerr << "Error some of the libraries not found!" << endl;
								exit(1);
							}
						}
						cout<< endl << complete_list << endl; //output all the libraries with their absolute paths
					} 

				}
         	} while (sym.d_tag != DT_NULL);
		}
	}
	elf_end(elf);
	return 0;
}
コード例 #16
0
ファイル: clear-dt-path.c プロジェクト: gentoo/elfix
int main( int argc, char *argv[])
{
	int fd, cmd;
	size_t i, n;
	char *p; 

	Elf *arf, *elf;
	GElf_Ehdr ehdr;
	Elf_Scn *scn;
	GElf_Shdr shdr;
	Elf_Data *data;
	GElf_Dyn dyn;

	if(elf_version(EV_CURRENT) == EV_NONE)
		error(EXIT_FAILURE, 0, "Library out of date.");

	if(argc != 2)
		error(EXIT_FAILURE, 0, "Usage: %s <filename>", argv[0]);

	if((fd = open(argv[1], O_RDONLY)) == -1)
		error(EXIT_FAILURE, 0, "Failed open file.");


	cmd = ELF_C_READ;

	if((arf = elf_begin(fd, cmd, (Elf *)0)) == NULL)
		error(EXIT_FAILURE, 0, "Failed open elf: %s", elf_errmsg ( -1));
		

	while((elf = elf_begin(fd, cmd, arf)) != NULL)
	{
		if(gelf_getehdr(elf,&ehdr) != NULL)
		{
			scn = NULL;
			while((scn = elf_nextscn(elf, scn)) != NULL)
			{
				gelf_getshdr(scn, &shdr);

				if(shdr.sh_type != SHT_DYNAMIC)
					continue;

				printf("Section name: %s\n", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));

				data = NULL;
				while((data = elf_getdata(scn, data)) != NULL)
				{
					if(data != NULL)
						for( i=0; gelf_getdyn(data, i, &dyn) != NULL; i++)
						{
							if(dyn.d_tag == DT_RPATH)
								printf("DT_RPATH found\n");
							if(dyn.d_tag == DT_RUNPATH)
								printf("DT_RUNPATH found\n");
						}
				}
			}
		}

		cmd = elf_next(elf);
		elf_end(elf);

	}

	elf_end(arf);

	close(fd);
}
コード例 #17
0
ファイル: elf.hpp プロジェクト: BonnieTang/mesos
  // Extract the strings associated with the provided `DynamicTag`
  // from the DYNAMIC section of the ELF binary.
  Try<std::vector<std::string>> GetDynamicStrings(DynamicTag tag) const
  {
    if (sections.count(SectionType::DYNAMIC) == 0) {
      return Error("No DYNAMIC sections found in ELF");
    }

    if (sections.count(SectionType::DYNAMIC) != 1) {
      return Error("Multiple DYNAMIC sections found in ELF");
    }

    Elf_Scn* dynamic_section = sections.at(SectionType::DYNAMIC)[0];

    // Walk through the entries in the dynamic section and look for
    // entries with the provided tag. These entries contain offsets to
    // strings in the dynamic section's string table. Consequently, we
    // also have to look for an entry containing a pointer to the
    // dynamic section's string table so we can resolve the strings
    // associated with the provided tag later on.
    Elf_Data* dynamic_data = elf_getdata(dynamic_section, NULL);
    if (dynamic_data == NULL) {
      return Error("elf_getdata() failed: " + stringify(elf_errmsg(-1)));
    }

    Option<uintptr_t> strtab_pointer = None();
    std::vector<uintptr_t> strtab_offsets;

    for (size_t i = 0; i < dynamic_data->d_size / sizeof(GElf_Dyn); i++) {
      GElf_Dyn entry;
      if (gelf_getdyn(dynamic_data, i, &entry) == NULL) {
          return Error("gelf_getdyn() failed: " + stringify(elf_errmsg(-1)));
      }

      if ((DynamicTag)entry.d_tag == DynamicTag::STRTAB) {
        strtab_pointer = entry.d_un.d_ptr;
      }

      if ((DynamicTag)entry.d_tag == tag) {
        strtab_offsets.push_back(entry.d_un.d_ptr);
      }
    }

    if (strtab_offsets.empty()) {
      return std::vector<std::string>();
    }

    if (strtab_pointer.isNone()) {
      return Error("Failed to find string table");
    }

    // Get a reference to the actual string table so we can index into it.
    Elf_Scn* string_table_section = gelf_offscn(elf, strtab_pointer.get());
    if (string_table_section == NULL) {
      return Error("gelf_offscn() failed: " + stringify(elf_errmsg(-1)));
    }

    size_t strtab_index = elf_ndxscn(string_table_section);
    if (strtab_index == SHN_UNDEF) {
      return Error("elf_ndxscn() failed: " + stringify(elf_errmsg(-1)));
    }

    // Find the strings in the string table from their offsets and return them.
    std::vector<std::string> strings;
    foreach (uintptr_t offset, strtab_offsets) {
      char* string = elf_strptr(elf, strtab_index, offset);
      if (string == NULL) {
        return Error("elf_strptr() failed: " + stringify(elf_errmsg(-1)));
      }

      strings.push_back(string);
    }
コード例 #18
0
ファイル: pkg_elf.c プロジェクト: flz/pkgng
static int
analyse_elf(struct pkgdb *db, struct pkg *pkg, const char *fpath)
{
	struct pkg **deps;
	struct pkg *p = NULL;
	struct pkgdb_it *it = NULL;
	Elf *e;
	Elf_Scn *scn = NULL;
	GElf_Shdr shdr;
	Elf_Data *data;
	GElf_Dyn *dyn, dyn_mem;
	size_t numdyn;
	size_t dynidx;
	void *handle;
	Link_map *map;
	char *name;
	bool found=false;

	int fd, i;

	if ((fd = open(fpath, O_RDONLY, 0)) < 0)
		return (EPKG_FATAL);

	if (( e = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
		return (EPKG_FATAL);

	if (elf_kind(e) != ELF_K_ELF)
		return (EPKG_FATAL);

	while (( scn = elf_nextscn(e, scn)) != NULL) {
		if (gelf_getshdr(scn, &shdr) != &shdr)
			return (EPKG_FATAL);

		if (shdr.sh_type == SHT_DYNAMIC)
			break;
	}

	data = elf_getdata(scn, NULL);
	numdyn = shdr.sh_size / shdr.sh_entsize;

	for (dynidx = 0; dynidx < numdyn; dynidx++) {
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL)
			return (EPKG_FATAL);

		if (dyn->d_tag != DT_NEEDED)
			continue;

		name = elf_strptr(e, shdr.sh_link, dyn->d_un.d_val);
		handle = dlopen(name, RTLD_LAZY);

		if (handle != NULL) {
			dlinfo(handle, RTLD_DI_LINKMAP, &map);
			if ((it = pkgdb_query_which(db, map->l_name)) == NULL)
				return (EPKG_FATAL);

			if (pkgdb_it_next(it, &p, PKG_LOAD_BASIC) == EPKG_OK) {
				found = false;
				if (( deps = pkg_deps(pkg) ) != NULL) {
					for (i = 0; deps[i]; i++) {
						if (strcmp(pkg_get(deps[i], PKG_ORIGIN), pkg_get(p, PKG_ORIGIN)) == 0)
							found = true;
					}
				}
				if (!found) {
					warnx("adding forgotten depends (%s): %s-%s", map->l_name, pkg_get(p, PKG_NAME), pkg_get(p, PKG_VERSION));
					pkg_adddep(pkg, pkg_get(p, PKG_NAME), pkg_get(p, PKG_ORIGIN), pkg_get(p, PKG_VERSION));
				}
			}
			dlclose(handle);
		}
		pkgdb_it_free(it);
	}
	pkg_free(p);
	close(fd);

	return (EPKG_OK);

}
コード例 #19
0
ファイル: ltrace-elf.c プロジェクト: KapJlcoH/ltrace
int
do_init_elf(struct ltelf *lte, const char *filename) {
	int i;
	GElf_Addr relplt_addr = 0;
	size_t relplt_size = 0;

	debug(DEBUG_FUNCTION, "do_init_elf(filename=%s)", filename);
	debug(1, "Reading ELF from %s...", filename);

	if (open_elf(lte, filename) < 0)
		return -1;

	Elf_Data *plt_data = NULL;
	GElf_Addr ppcgot = 0;

	for (i = 1; i < lte->ehdr.e_shnum; ++i) {
		Elf_Scn *scn;
		GElf_Shdr shdr;
		const char *name;

		scn = elf_getscn(lte->elf, i);
		if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
			error(EXIT_FAILURE, 0,
			      "Couldn't get section header from \"%s\"",
			      filename);

		name = elf_strptr(lte->elf, lte->ehdr.e_shstrndx, shdr.sh_name);
		if (name == NULL)
			error(EXIT_FAILURE, 0,
			      "Couldn't get section header from \"%s\"",
			      filename);

		if (shdr.sh_type == SHT_SYMTAB) {
			Elf_Data *data;

			lte->symtab = elf_getdata(scn, NULL);
			lte->symtab_count = shdr.sh_size / shdr.sh_entsize;
			if ((lte->symtab == NULL
			     || elf_getdata(scn, lte->symtab) != NULL)
			    && opt_x != NULL)
				error(EXIT_FAILURE, 0,
				      "Couldn't get .symtab data from \"%s\"",
				      filename);

			scn = elf_getscn(lte->elf, shdr.sh_link);
			if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
				error(EXIT_FAILURE, 0,
				      "Couldn't get section header from \"%s\"",
				      filename);

			data = elf_getdata(scn, NULL);
			if (data == NULL || elf_getdata(scn, data) != NULL
			    || shdr.sh_size != data->d_size || data->d_off)
				error(EXIT_FAILURE, 0,
				      "Couldn't get .strtab data from \"%s\"",
				      filename);

			lte->strtab = data->d_buf;
		} else if (shdr.sh_type == SHT_DYNSYM) {
			Elf_Data *data;

			lte->dynsym = elf_getdata(scn, NULL);
			lte->dynsym_count = shdr.sh_size / shdr.sh_entsize;
			if (lte->dynsym == NULL
			    || elf_getdata(scn, lte->dynsym) != NULL)
				error(EXIT_FAILURE, 0,
				      "Couldn't get .dynsym data from \"%s\"",
				      filename);

			scn = elf_getscn(lte->elf, shdr.sh_link);
			if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
				error(EXIT_FAILURE, 0,
				      "Couldn't get section header from \"%s\"",
				      filename);

			data = elf_getdata(scn, NULL);
			if (data == NULL || elf_getdata(scn, data) != NULL
			    || shdr.sh_size != data->d_size || data->d_off)
				error(EXIT_FAILURE, 0,
				      "Couldn't get .dynstr data from \"%s\"",
				      filename);

			lte->dynstr = data->d_buf;
		} else if (shdr.sh_type == SHT_DYNAMIC) {
			Elf_Data *data;
			size_t j;

			lte->dyn_addr = shdr.sh_addr;
			lte->dyn_sz = shdr.sh_size;

			data = elf_getdata(scn, NULL);
			if (data == NULL || elf_getdata(scn, data) != NULL)
				error(EXIT_FAILURE, 0,
				      "Couldn't get .dynamic data from \"%s\"",
				      filename);

			for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
				GElf_Dyn dyn;

				if (gelf_getdyn(data, j, &dyn) == NULL)
					error(EXIT_FAILURE, 0,
					      "Couldn't get .dynamic data from \"%s\"",
					      filename);
#ifdef __mips__
/**
  MIPS ABI Supplement:

  DT_PLTGOT This member holds the address of the .got section.

  DT_MIPS_SYMTABNO This member holds the number of entries in the
  .dynsym section.

  DT_MIPS_LOCAL_GOTNO This member holds the number of local global
  offset table entries.

  DT_MIPS_GOTSYM This member holds the index of the first dyamic
  symbol table entry that corresponds to an entry in the gobal offset
  table.

 */
				if(dyn.d_tag==DT_PLTGOT){
					lte->pltgot_addr=dyn.d_un.d_ptr;
				}
				if(dyn.d_tag==DT_MIPS_LOCAL_GOTNO){
					lte->mips_local_gotno=dyn.d_un.d_val;
				}
				if(dyn.d_tag==DT_MIPS_GOTSYM){
					lte->mips_gotsym=dyn.d_un.d_val;
				}
#endif // __mips__
				if (dyn.d_tag == DT_JMPREL)
					relplt_addr = dyn.d_un.d_ptr;
				else if (dyn.d_tag == DT_PLTRELSZ)
					relplt_size = dyn.d_un.d_val;
				else if (dyn.d_tag == DT_PPC_GOT) {
					ppcgot = dyn.d_un.d_val;
					debug(1, "ppcgot %#" PRIx64, ppcgot);
				}
			}
		} else if (shdr.sh_type == SHT_HASH) {
			Elf_Data *data;
			size_t j;

			lte->hash_type = SHT_HASH;

			data = elf_getdata(scn, NULL);
			if (data == NULL || elf_getdata(scn, data) != NULL
			    || data->d_off || data->d_size != shdr.sh_size)
				error(EXIT_FAILURE, 0,
				      "Couldn't get .hash data from \"%s\"",
				      filename);

			if (shdr.sh_entsize == 4) {
				/* Standard conforming ELF.  */
				if (data->d_type != ELF_T_WORD)
					error(EXIT_FAILURE, 0,
					      "Couldn't get .hash data from \"%s\"",
					      filename);
				lte->hash = (Elf32_Word *) data->d_buf;
			} else if (shdr.sh_entsize == 8) {
				/* Alpha or s390x.  */
				Elf32_Word *dst, *src;
				size_t hash_count = data->d_size / 8;

				lte->hash = (Elf32_Word *)
				    malloc(hash_count * sizeof(Elf32_Word));
				if (lte->hash == NULL)
					error(EXIT_FAILURE, 0,
					      "Couldn't convert .hash section from \"%s\"",
					      filename);
				lte->lte_flags |= LTE_HASH_MALLOCED;
				dst = lte->hash;
				src = (Elf32_Word *) data->d_buf;
				if ((data->d_type == ELF_T_WORD
				     && __BYTE_ORDER == __BIG_ENDIAN)
				    || (data->d_type == ELF_T_XWORD
					&& lte->ehdr.e_ident[EI_DATA] ==
					ELFDATA2MSB))
					++src;
				for (j = 0; j < hash_count; ++j, src += 2)
					*dst++ = *src;
			} else
				error(EXIT_FAILURE, 0,
				      "Unknown .hash sh_entsize in \"%s\"",
				      filename);
		} else if (shdr.sh_type == SHT_GNU_HASH
			   && lte->hash == NULL) {
			Elf_Data *data;

			lte->hash_type = SHT_GNU_HASH;

			if (shdr.sh_entsize != 0
			    && shdr.sh_entsize != 4) {
				error(EXIT_FAILURE, 0,
				      ".gnu.hash sh_entsize in \"%s\" "
					"should be 4, but is %#" PRIx64,
					filename, shdr.sh_entsize);
			}

			data = loaddata(scn, &shdr);
			if (data == NULL)
				error(EXIT_FAILURE, 0,
				      "Couldn't get .gnu.hash data from \"%s\"",
				      filename);

			lte->hash = (Elf32_Word *) data->d_buf;
		} else if (shdr.sh_type == SHT_PROGBITS
			   || shdr.sh_type == SHT_NOBITS) {
			if (strcmp(name, ".plt") == 0) {
				lte->plt_addr = shdr.sh_addr;
				lte->plt_size = shdr.sh_size;
				if (shdr.sh_flags & SHF_EXECINSTR) {
					lte->lte_flags |= LTE_PLT_EXECUTABLE;
				}
				if (lte->ehdr.e_machine == EM_PPC) {
					plt_data = loaddata(scn, &shdr);
					if (plt_data == NULL)
						fprintf(stderr,
							"Can't load .plt data\n");
				}
			}
#ifdef ARCH_SUPPORTS_OPD
			else if (strcmp(name, ".opd") == 0) {
				lte->opd_addr = (GElf_Addr *) (long) shdr.sh_addr;
				lte->opd_size = shdr.sh_size;
				lte->opd = elf_rawdata(scn, NULL);
			}
#endif
		}
	}

	if (lte->dynsym == NULL || lte->dynstr == NULL)
		error(EXIT_FAILURE, 0,
		      "Couldn't find .dynsym or .dynstr in \"%s\"", filename);

	if (!relplt_addr || !lte->plt_addr) {
		debug(1, "%s has no PLT relocations", filename);
		lte->relplt = NULL;
		lte->relplt_count = 0;
	} else if (relplt_size == 0) {
		debug(1, "%s has unknown PLT size", filename);
		lte->relplt = NULL;
		lte->relplt_count = 0;
	} else {
		if (lte->ehdr.e_machine == EM_PPC) {
			GElf_Addr glink_vma
				= get_glink_vma(lte, ppcgot, plt_data);

			assert (relplt_size % 12 == 0);
			size_t count = relplt_size / 12; // size of RELA entry
			lte->plt_stub_vma = glink_vma
				- (GElf_Addr)count * PPC_PLT_STUB_SIZE;
			debug(1, "stub_vma is %#" PRIx64, lte->plt_stub_vma);
		}

		for (i = 1; i < lte->ehdr.e_shnum; ++i) {
			Elf_Scn *scn;
			GElf_Shdr shdr;

			scn = elf_getscn(lte->elf, i);
			if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
				error(EXIT_FAILURE, 0,
				      "Couldn't get section header from \"%s\"",
				      filename);
			if (shdr.sh_addr == relplt_addr
			    && shdr.sh_size == relplt_size) {
				lte->relplt = elf_getdata(scn, NULL);
				lte->relplt_count =
				    shdr.sh_size / shdr.sh_entsize;
				if (lte->relplt == NULL
				    || elf_getdata(scn, lte->relplt) != NULL)
					error(EXIT_FAILURE, 0,
					      "Couldn't get .rel*.plt data from \"%s\"",
					      filename);
				break;
			}
		}

		if (i == lte->ehdr.e_shnum)
			error(EXIT_FAILURE, 0,
			      "Couldn't find .rel*.plt section in \"%s\"",
			      filename);

		debug(1, "%s %zd PLT relocations", filename, lte->relplt_count);
	}
	return 0;
}
コード例 #20
0
ファイル: mtelf.c プロジェクト: sstefani/mtrace
static int elf_read(struct mt_elf *mte, struct task *task, const char *filename)
{
	unsigned long loadsize = 0;
	unsigned long loadbase = ~0;
	unsigned long align;
	unsigned long vstart;
	unsigned int loadsegs = 0;

	debug(DEBUG_FUNCTION, "filename=%s", filename);

	if (open_elf(mte, task, filename) < 0)
		return -1;

	GElf_Phdr phdr;
	int i;

	memset(&mte->txt_hdr, 0, sizeof(mte->txt_hdr));
	memset(&mte->eh_hdr, 0, sizeof(mte->eh_hdr));
	memset(&mte->exidx_hdr, 0, sizeof(mte->exidx_hdr));

	for (i = 0; gelf_getphdr(mte->elf, i, &phdr) != NULL; ++i) {
		switch (phdr.p_type) {
		case PT_LOAD:
			loadsegs++;

			align = phdr.p_align;
			if (align)
				align -= 1;

			vstart = phdr.p_vaddr & ~align;

			if (mte->vstart > vstart)
				mte->vstart = vstart;

			if (loadbase > phdr.p_offset)
				loadbase = phdr.p_offset;

			if (loadsize < phdr.p_offset + phdr.p_filesz)
				loadsize = phdr.p_offset + phdr.p_filesz;

			if ((phdr.p_flags & (PF_X | PF_W)) == PF_X)
				mte->txt_hdr = phdr;

			break;
		case PT_GNU_EH_FRAME:
			mte->eh_hdr = phdr;
			break;
#ifdef __arm__
		case PT_ARM_EXIDX:
			mte->exidx_hdr = phdr;
			break;
#endif
		case PT_INTERP:
			mte->interp = phdr.p_vaddr;
			break;
		case PT_DYNAMIC:
			mte->dyn = phdr.p_vaddr;
			break;
		default:
			break;
		}
	}

	if (!loadsegs) {
		fprintf(stderr, "No loadable segemnts in %s\n", filename);
		return -1;
	}

	mte->loadbase = loadbase & ~PAGEALIGN;
	mte->loadsize = (loadsize + (loadbase - mte->loadbase) + PAGEALIGN) & ~PAGEALIGN;

	debug(DEBUG_FUNCTION, "filename=`%s' text offset=%#llx addr=%#llx size=%#llx",
			filename,
			(unsigned long long)mte->txt_hdr.p_offset,
			(unsigned long long)mte->txt_hdr.p_vaddr,
			(unsigned long long)mte->txt_hdr.p_filesz);

	for (i = 1; i < mte->ehdr.e_shnum; ++i) {
		Elf_Scn *scn;
		GElf_Shdr shdr;
		const char *name;

		scn = elf_getscn(mte->elf, i);
		if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL) {
			fprintf(stderr, "Couldn't get section #%d from" " \"%s\": %s\n", i, filename, elf_errmsg(-1));
			return -1;
		}

		name = elf_strptr(mte->elf, mte->ehdr.e_shstrndx, shdr.sh_name);
		if (name == NULL) {
			fprintf(stderr, "Couldn't get name of section #%d from \"%s\": %s\n", i, filename, elf_errmsg(-1));
			return -1;
		}

		if (shdr.sh_type == SHT_SYMTAB) {
			read_symbol_table(mte, filename, scn, &shdr, name, &mte->symtab, &mte->symtab_count, &mte->strtab);
		} else if (shdr.sh_type == SHT_DYNSYM) {
			read_symbol_table(mte, filename, scn, &shdr, name, &mte->dynsym, &mte->dynsym_count, &mte->dynstr);
		} else if (shdr.sh_type == SHT_DYNAMIC) {
			Elf_Data *data;
			GElf_Dyn dyn;
			int idx;

			data = elf_getdata(scn, NULL);
			if (data == NULL) {
				fprintf(stderr, "Couldn't get .dynamic data from \"%s\": %s\n", filename, strerror(errno));
				return -1;
			}

			for(idx = 0; gelf_getdyn(data, idx, &dyn); ++idx) {
				if (dyn.d_tag == DT_PLTGOT)  {
					mte->pltgot = dyn.d_un.d_ptr;
					break;
				}
			}
		}
	}

	if (!mte->dynsym || !mte->dynstr) {
		fprintf(stderr, "Couldn't find .dynsym or .dynstr in \"%s\"\n", filename);
		return -1;
	}

	return 0;
}
コード例 #21
0
ファイル: pkg_elf.c プロジェクト: dschossig/pkg
static int
analyse_elf(struct pkg *pkg, const char *fpath,
	int (action)(void *, struct pkg *, const char *, const char *, bool),
	void *actdata)
{
	Elf *e = NULL;
	GElf_Ehdr elfhdr;
	Elf_Scn *scn = NULL;
	Elf_Scn *note = NULL;
	Elf_Scn *dynamic = NULL;
	GElf_Shdr shdr;
	Elf_Data *data;
	GElf_Dyn *dyn, dyn_mem;
	struct stat sb;
	int ret = EPKG_OK;

	size_t numdyn = 0;
	size_t sh_link = 0;
	size_t dynidx;
	const char *osname;
	const char *shlib;

	bool developer = false;
	bool is_shlib = false;

	pkg_config_bool(PKG_CONFIG_DEVELOPER_MODE, &developer);

	int fd;

	if (lstat(fpath, &sb) != 0)
		pkg_emit_errno("fstat() failed for", fpath);
	/* ignore empty files and non regular files */
	if (sb.st_size == 0 || !S_ISREG(sb.st_mode))
		return (EPKG_END); /* Empty file or sym-link: no results */

	if ((fd = open(fpath, O_RDONLY, 0)) < 0) {
		return (EPKG_FATAL);
	}

	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
		ret = EPKG_FATAL;
		pkg_emit_error("elf_begin() for %s failed: %s", fpath,
		    elf_errmsg(-1));
		goto cleanup;
	}

	if (elf_kind(e) != ELF_K_ELF) {
		/* Not an elf file: no results */
		ret = EPKG_END;
		goto cleanup;
	}

	if (developer)
		pkg->flags |= PKG_CONTAINS_ELF_OBJECTS;

	if (gelf_getehdr(e, &elfhdr) == NULL) {
		ret = EPKG_FATAL;
		pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1));
		goto cleanup;
	}

	while ((scn = elf_nextscn(e, scn)) != NULL) {
		if (gelf_getshdr(scn, &shdr) != &shdr) {
			ret = EPKG_FATAL;
			pkg_emit_error("getshdr() for %s failed: %s", fpath,
			    elf_errmsg(-1));
			goto cleanup;
		}
		switch (shdr.sh_type) {
		case SHT_NOTE:
			note = scn;
			break;
		case SHT_DYNAMIC:
			dynamic = scn;
			sh_link = shdr.sh_link;
			numdyn = shdr.sh_size / shdr.sh_entsize;
			break;
		}

		if (note != NULL && dynamic != NULL)
			break;
	}

	/*
	 * note == NULL usually means a shared object for use with dlopen(3)
	 * dynamic == NULL means not a dynamically linked elf
	 */
	if (dynamic == NULL) {
		ret = EPKG_END;
		goto cleanup; /* not a dynamically linked elf: no results */
	}

	if (note != NULL) {
		if ((data = elf_getdata(note, NULL)) == NULL) {
			ret = EPKG_END; /* Some error occurred, ignore this file */
			goto cleanup;
		}
		if (data->d_buf == NULL) {
			ret = EPKG_END; /* No osname available */
			goto cleanup;
		}
		osname = (const char *) data->d_buf + sizeof(Elf_Note);
		if (strncasecmp(osname, "freebsd", sizeof("freebsd")) != 0 &&
		    strncasecmp(osname, "dragonfly", sizeof("dragonfly")) != 0) {
			ret = EPKG_END;	/* Foreign (probably linux) ELF object */
			goto cleanup;
		}
	} else {
		if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_FREEBSD) {
			ret = EPKG_END;
			goto cleanup;
		}
	}

	if ((data = elf_getdata(dynamic, NULL)) == NULL) {
		ret = EPKG_END; /* Some error occurred, ignore this file */
		goto cleanup;
	}

	/* First, scan through the data from the .dynamic section to
	   find any RPATH or RUNPATH settings.  These are colon
	   separated paths to prepend to the ld.so search paths from
	   the ELF hints file.  These always seem to come right after
	   the NEEDED shared library entries.

	   NEEDED entries should resolve to a filename for installed
	   executables, but need not resolve for installed shared
	   libraries -- additional info from the apps that link
	   against them would be required.  Shared libraries are
	   distinguished by a DT_SONAME tag */

	rpath_list_init();
	for (dynidx = 0; dynidx < numdyn; dynidx++) {
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
			ret = EPKG_FATAL;
			pkg_emit_error("getdyn() failed for %s: %s", fpath,
			    elf_errmsg(-1));
			goto cleanup;
		}

		if (dyn->d_tag == DT_SONAME) {
			is_shlib = true;

			/* The file being scanned is a shared library
			   *provided* by the package. Record this if
			   appropriate */

			pkg_addshlib_provided(pkg, basename(fpath));
		}

		if (dyn->d_tag != DT_RPATH && dyn->d_tag != DT_RUNPATH)
			continue;
		
		shlib_list_from_rpath(elf_strptr(e, sh_link, dyn->d_un.d_val), 
				      dirname(fpath));
		break;
	}

	/* Now find all of the NEEDED shared libraries. */

	for (dynidx = 0; dynidx < numdyn; dynidx++) {
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
			ret = EPKG_FATAL;
			pkg_emit_error("getdyn() failed for %s: %s", fpath,
			    elf_errmsg(-1));
			goto cleanup;
		}

		if (dyn->d_tag != DT_NEEDED)
			continue;

		shlib = elf_strptr(e, sh_link, dyn->d_un.d_val);

		action(actdata, pkg, fpath, shlib, is_shlib);
	}

cleanup:
	rpath_list_free();

	if (e != NULL)
		elf_end(e);
	close(fd);

	return (ret);
}
コード例 #22
0
ファイル: rpath.c プロジェクト: dilos/dilos-userland
int
main(int argc, char **argv)
{
	int		c, ndx;
	int		readonly;
	int		fd;
	const char	*file;
	const char	*runpath;
	Elf		*elf;
	GElf_Ehdr	ehdr;
	size_t		shstrndx, shnum;
	Elf_Scn		*scn;
	Elf_Data	*data;
	char		*shnames = NULL;
	Cache		*cache, *_cache;
	Cache		*dynsec, *strsec;
	GElf_Word	numdyn;
	dyn_elt_t	rpath_elt;
	dyn_elt_t	runpath_elt;
	dyn_elt_t	strpad_elt;
	dyn_elt_t	flags_1_elt;
	dyn_elt_t	null_elt;
	int		changed = 0;


	opterr = 0;
	while ((c = getopt(argc, argv, "dr")) != EOF) {
		switch (c) {
		case 'd':
			d_flg = 1;
			break;

		case 'r':
			r_flg = 1;
			break;

		case '?':
			msg_usage();
		}
	}

	/*
	 * The first plain argument is the file name, and is required.
	 * The second plain argument is the runpath, and is optional.
	 * If no runpath is given, we print the current runpath to stdout
	 * and exit. If it is present, we modify the ELF file to use it.
	 */
	argc = argc - optind;
	argv += optind;
	if ((argc < 1) || (argc > 2))
		msg_usage();
	if ((argc == 2) && r_flg)
		msg_usage();

	readonly = (argc == 1) && !r_flg;
	file = argv[0];
	if (!readonly)
		runpath = argv[1];

	if ((fd = open(file, readonly ? O_RDONLY : O_RDWR)) == -1)
		msg_fatal("unable to open file: %s: %s\n",
		    file, strerror(errno));

	(void) elf_version(EV_CURRENT);
	elf = elf_begin(fd, readonly ? ELF_C_READ : ELF_C_RDWR, NULL);
	if (elf == NULL)
		msg_elf("elf_begin");

	/* We only handle standalone ELF files */
	switch (elf_kind(elf)) {
	case ELF_K_AR:
		msg_fatal("unable to edit ELF archive: %s\n", file);
		break;
	case ELF_K_ELF:
		break;
	default:
		msg_fatal("unable to edit non-ELF file: %s\n", file);
		break;
	}

	if (gelf_getehdr(elf, &ehdr) == NULL)
		msg_elf("gelf_getehdr");

	if (elf_getshnum(elf, &shnum) == 0)
		msg_elf("elf_getshnum");

	if (elf_getshstrndx(elf, &shstrndx) == 0)
		msg_elf("elf_getshstrndx");

	/*
	 * Obtain the .shstrtab data buffer to provide the required section
	 * name strings.
	 */
	if ((scn = elf_getscn(elf, shstrndx)) == NULL)
		msg_elf("elf_getscn");
	if ((data = elf_getdata(scn, NULL)) == NULL)
		msg_elf("elf_getdata");
	shnames = data->d_buf;

	/*
	 * Allocate a cache to maintain a descriptor for each section.
	 */
	if ((cache = malloc(shnum * sizeof (Cache))) == NULL)
		msg_fatal("unable to allocate section cache: %s\n",
		    strerror(errno));
	bzero(cache, sizeof (cache[0]));
	cache->c_name = "";
	_cache = cache + 1;

	/*
	 * Fill in cache with information for each section, and
	 * locate the dynamic section.
	 */
	dynsec = strsec = NULL;
	for (ndx = 1, scn = NULL; scn = elf_nextscn(elf, scn);
	    ndx++, _cache++) {
		_cache->c_ndx = ndx;
		if (gelf_getshdr(scn, &_cache->c_shdr) == NULL)
			msg_elf("gelf_getshdr");
		_cache->c_data = elf_getdata(scn, NULL);
		_cache->c_name = shnames + _cache->c_shdr.sh_name;
		if (_cache->c_shdr.sh_type == SHT_DYNAMIC) {
			dynsec = _cache;
			numdyn = dynsec->c_shdr.sh_size /
			    dynsec->c_shdr.sh_entsize;
			msg_debug("[%d]%s: dynamic section\n",
			    ndx, _cache->c_name);
		}
	}

	/*
	 * If we got a dynamic section, locate the string table.
	 * If not, we can't continue.
	 */
	if (dynsec == NULL)
		msg_fatal("file lacks a dynamic section: %s\n", file);
	strsec = &cache[dynsec->c_shdr.sh_link];
	msg_debug("[%d]%s: dynamic string table section\n",
	    strsec->c_ndx, strsec->c_name);

	/*
	 * History Lesson And Strategy:
	 *
	 * This routine handles both DT_RPATH and DT_RUNPATH entries, altering
	 * either or both if they are present.
	 *
	 * The original SYSV ABI only had DT_RPATH, and the runtime loader used
	 * it to search for things in the following order:
	 *
	 *	DT_RPATH, LD_LIBRARY_PATH, defaults
	 *
	 * Solaris did not follow this rule. Environment variables should
	 * supersede everything else, so we have always deviated from the
	 * ABI and and instead search in the order
	 *
	 *	LD_LIBRARY_PATH, DT_RPATH, defaults
	 *
	 * Other Unix variants initially followed the ABI, but in recent years
	 * realized that it was a mistake. Hence, DT_RUNPATH was invented,
	 * with the search order:
	 *
	 *	LD_LIBRARY_PATH, DT_RUNPATH, defaults
	 *
	 * So for Solaris, DT_RPATH and DT_RUNPATH mean the same thing. If both
	 * are present (which does happen), we set them both to the new
	 * value. If either one is present, we set that one. If neither is
	 * present, and we have a spare DT_NULL slot, we create a DT_RUNPATH.
	 */

	/*
	 * Examine the dynamic section to determine the index for
	 *	- DT_RPATH
	 *	- DT_RUNPATH
	 *	- DT_SUNW_STRPAD
	 *	- DT_NULL, and whether there are any extra DT_NULL slots
	 */
	dyn_elt_init(&rpath_elt);
	dyn_elt_init(&runpath_elt);
	dyn_elt_init(&strpad_elt);
	dyn_elt_init(&flags_1_elt);
	dyn_elt_init(&null_elt);
	for (ndx = 0; ndx < numdyn; ndx++) {
		GElf_Dyn	dyn;

		if (gelf_getdyn(dynsec->c_data, ndx, &dyn) == NULL)
			msg_elf("gelf_getdyn");

		switch (dyn.d_tag) {
		case DT_NULL:
			/*
			 * Remember the state of the first DT_NULL. If there
			 * are more than one (i.e. the first one is not
			 * in the final spot), and there is no runpath, then
			 * we will turn the first one into a DT_RUNPATH.
			 */
			if (!null_elt.seen) {
				dyn_elt_save(&null_elt, ndx, &dyn);
				msg_debug("[%d]%s[%d]: DT_NULL\n",
				    dynsec->c_ndx, dynsec->c_name, ndx);
			}
			break;

		case DT_RPATH:
			dyn_elt_save(&rpath_elt, ndx, &dyn);
			msg_debug("[%d]%s[%d]: DT_RPATH: %s\n",
			    dynsec->c_ndx, dynsec->c_name, ndx,
			    DYN_ELT_STRING(&rpath_elt, strsec));
			break;

		case DT_RUNPATH:
			dyn_elt_save(&runpath_elt, ndx, &dyn);
			msg_debug("[%d]%s[%d]: DT_RUNPATH: %s\n",
			    dynsec->c_ndx, dynsec->c_name, ndx,
			    DYN_ELT_STRING(&runpath_elt, strsec));
			break;

		case DT_SUNW_STRPAD:
			dyn_elt_save(&strpad_elt, ndx, &dyn);
			msg_debug("[%d]%s[%d]: DT_STRPAD: %d\n",
			    dynsec->c_ndx, dynsec->c_name, ndx,
			    (int)strpad_elt.dyn.d_un.d_val);
			break;

		case DT_FLAGS_1:
			dyn_elt_save(&flags_1_elt, ndx, &dyn);
			break;
		}
	}

	/*
	 * If this is a readonly session, then print the existing
	 * runpath and exit. DT_RPATH and DT_RUNPATH should have
	 * the same value, so we arbitrarily favor DT_RUNPATH.
	 */
	if (readonly) {
		if (runpath_elt.seen)
			(void) printf("%s\n",
			    DYN_ELT_STRING(&runpath_elt, strsec));
		else if (rpath_elt.seen)
			(void) printf("%s\n",
			    DYN_ELT_STRING(&rpath_elt, strsec));
		else
			msg_debug("ELF file does not have a runpath: %s\n",
			    file);
		return (0);
	}


	/* Edit the file, either to remove the runpath or to add/modify it */
	if (r_flg) {
		if (!(runpath_elt.seen || rpath_elt.seen))
			msg_debug("[%d]%s: no runpath found\n",
			    dynsec->c_ndx, dynsec->c_name);
		else
			changed = remove_runpath(dynsec, numdyn);
	} else {
		changed = new_runpath(runpath, dynsec, numdyn, strsec,
		    &rpath_elt, &runpath_elt, &strpad_elt, &null_elt);
	}

	if (changed) {
		/*
		 * If possible, set the DF_1_EDITED flag, indicating that
		 * this file has been edited after the fact.
		 */
		if (flags_1_elt.seen) {
			flags_1_elt.dyn.d_un.d_val |= DF_1_EDITED;
		} else if (null_elt.seen && (null_elt.ndx < (numdyn - 1))) {
			msg_debug("[%d]%s: No existing flags_1 entry to "
			    "modify. Will use extra DT_NULL in slot [%d] \n",
			    dynsec->c_ndx, dynsec->c_name, null_elt.ndx);
			flags_1_elt.seen = 1;
			flags_1_elt.ndx = null_elt.ndx;
			flags_1_elt.dyn.d_tag = DT_FLAGS_1;
			flags_1_elt.dyn.d_un.d_val = DF_1_EDITED;
		}
		if (flags_1_elt.seen) {
			msg_debug("[%d]%s[%d]: Set DF_1_EDITED flag\n",
			    dynsec->c_ndx, dynsec->c_name, flags_1_elt.ndx);
			if (gelf_update_dyn(dynsec->c_data, flags_1_elt.ndx,
			    &flags_1_elt.dyn) == 0)
				msg_elf("gelf_update_dyn");
		}

		/*
		 * Mark the data area as dirty so libelf will flush our
		 * changes to the dynamic section data.
		 */
		(void) elf_flagdata(dynsec->c_data, ELF_C_SET, ELF_F_DIRTY);

		/* Flush the file to disk */
		if (elf_update(elf, ELF_C_WRITE) == -1)
			msg_elf("elf_update");
		(void) close(fd);
		(void) elf_end(elf);
	}
	return (0);
}
コード例 #23
0
/* Try to find a dynamic symbol table via phdrs.  */
static void
find_dynsym (Dwfl_Module *mod)
{
  GElf_Ehdr ehdr_mem;
  GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem);

  for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
    {
      GElf_Phdr phdr_mem;
      GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
      if (phdr == NULL)
	break;

      if (phdr->p_type == PT_DYNAMIC)
	{
	  /* Examine the dynamic section for the pointers we need.  */

	  Elf_Data *data = elf_getdata_rawchunk (mod->main.elf,
						 phdr->p_offset, phdr->p_filesz,
						 ELF_T_DYN);
	  if (data == NULL)
	    continue;

	  enum
	    {
	      i_symtab,
	      i_strtab,
	      i_hash,
	      i_gnu_hash,
	      i_max
	    };
	  GElf_Addr addrs[i_max] = { 0, };
	  GElf_Xword strsz = 0;
	  size_t n = data->d_size / gelf_fsize (mod->main.elf,
						ELF_T_DYN, 1, EV_CURRENT);
	  for (size_t j = 0; j < n; ++j)
	    {
	      GElf_Dyn dyn_mem;
	      GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
	      if (dyn != NULL)
		switch (dyn->d_tag)
		  {
		  case DT_SYMTAB:
		    addrs[i_symtab] = dyn->d_un.d_ptr;
		    continue;

		  case DT_HASH:
		    addrs[i_hash] = dyn->d_un.d_ptr;
		    continue;

		  case DT_GNU_HASH:
		    addrs[i_gnu_hash] = dyn->d_un.d_ptr;
		    continue;

		  case DT_STRTAB:
		    addrs[i_strtab] = dyn->d_un.d_ptr;
		    continue;

		  case DT_STRSZ:
		    strsz = dyn->d_un.d_val;
		    continue;

		  default:
		    continue;

		  case DT_NULL:
		    break;
		  }
	      break;
	    }

	  /* Translate pointers into file offsets.  */
	  GElf_Off offs[i_max] = { 0, };
	  find_offsets (mod->main.elf, ehdr, i_max, addrs, offs);

	  /* Figure out the size of the symbol table.  */
	  if (offs[i_hash] != 0)
	    {
	      /* In the original format, .hash says the size of .dynsym.  */

	      size_t entsz = SH_ENTSIZE_HASH (ehdr);
	      data = elf_getdata_rawchunk (mod->main.elf,
					   offs[i_hash] + entsz, entsz,
					   entsz == 4 ? ELF_T_WORD
					   : ELF_T_XWORD);
	      if (data != NULL)
		mod->syments = (entsz == 4
				? *(const GElf_Word *) data->d_buf
				: *(const GElf_Xword *) data->d_buf);
	    }
	  if (offs[i_gnu_hash] != 0 && mod->syments == 0)
	    {
	      /* In the new format, we can derive it with some work.  */

	      const struct
	      {
		Elf32_Word nbuckets;
		Elf32_Word symndx;
		Elf32_Word maskwords;
		Elf32_Word shift2;
	      } *header;

	      data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash],
					   sizeof *header, ELF_T_WORD);
	      if (data != NULL)
		{
		  header = data->d_buf;
		  Elf32_Word nbuckets = header->nbuckets;
		  Elf32_Word symndx = header->symndx;
		  GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header
					 + (gelf_getclass (mod->main.elf)
					    * sizeof (Elf32_Word)
					    * header->maskwords));

		  data = elf_getdata_rawchunk (mod->main.elf, buckets_at,
					       nbuckets * sizeof (Elf32_Word),
					       ELF_T_WORD);
		  if (data != NULL && symndx < nbuckets)
		    {
		      const Elf32_Word *const buckets = data->d_buf;
		      Elf32_Word maxndx = symndx;
		      for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket)
			if (buckets[bucket] > maxndx)
			  maxndx = buckets[bucket];

		      GElf_Off hasharr_at = (buckets_at
					     + nbuckets * sizeof (Elf32_Word));
		      hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
		      do
			{
			  data = elf_getdata_rawchunk (mod->main.elf,
						       hasharr_at,
						       sizeof (Elf32_Word),
						       ELF_T_WORD);
			  if (data != NULL
			      && (*(const Elf32_Word *) data->d_buf & 1u))
			    {
			      mod->syments = maxndx + 1;
			      break;
			    }
			  ++maxndx;
			  hasharr_at += sizeof (Elf32_Word);
			} while (data != NULL);
		    }
		}
	    }
	  if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0)
	    mod->syments = ((offs[i_strtab] - offs[i_symtab])
			    / gelf_fsize (mod->main.elf,
					  ELF_T_SYM, 1, EV_CURRENT));

	  if (mod->syments > 0)
	    {
	      mod->symdata = elf_getdata_rawchunk (mod->main.elf,
						   offs[i_symtab],
						   gelf_fsize (mod->main.elf,
							       ELF_T_SYM,
							       mod->syments,
							       EV_CURRENT),
						   ELF_T_SYM);
	      if (mod->symdata != NULL)
		{
		  mod->symstrdata = elf_getdata_rawchunk (mod->main.elf,
							  offs[i_strtab],
							  strsz,
							  ELF_T_BYTE);
		  if (mod->symstrdata == NULL)
		    mod->symdata = NULL;
		}
	      if (mod->symdata == NULL)
		mod->symerr = DWFL_E (LIBELF, elf_errno ());
	      else
		{
		  mod->symfile = &mod->main;
		  mod->symerr = DWFL_E_NOERROR;
		}
	      return;
	    }
	}
    }
}
コード例 #24
0
ファイル: pkg_elf.c プロジェクト: smortex/pkgng
static int
analyse_elf(struct pkg *pkg, const char *fpath)
{
	Elf *e = NULL;
	GElf_Ehdr elfhdr;
	Elf_Scn *scn = NULL;
	Elf_Scn *note = NULL;
	Elf_Scn *dynamic = NULL;
	GElf_Shdr shdr;
	Elf_Data *data;
	GElf_Dyn *dyn, dyn_mem;
	struct stat sb;
	int ret = EPKG_OK;

	size_t numdyn = 0;
	size_t sh_link = 0;
	size_t dynidx;
	const char *myarch;
	const char *shlib;
	char *rpath = NULL;

	bool is_shlib = false;

	myarch = pkg_object_string(pkg_config_get("ABI"));

	int fd;

	pkg_debug(1, "analysing elf %s", fpath);
	if (lstat(fpath, &sb) != 0)
		pkg_emit_errno("fstat() failed for", fpath);
	/* ignore empty files and non regular files */
	if (sb.st_size == 0 || !S_ISREG(sb.st_mode))
		return (EPKG_END); /* Empty file or sym-link: no results */

	if ((fd = open(fpath, O_RDONLY, 0)) < 0) {
		return (EPKG_FATAL);
	}

	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
		ret = EPKG_FATAL;
		pkg_emit_error("elf_begin() for %s failed: %s", fpath,
		    elf_errmsg(-1));
		goto cleanup;
	}

	if (elf_kind(e) != ELF_K_ELF) {
		/* Not an elf file: no results */
		ret = EPKG_END;
		pkg_debug(1, "not an elf");
		goto cleanup;
	}

	if (ctx.developer_mode)
		pkg->flags |= PKG_CONTAINS_ELF_OBJECTS;

	if (gelf_getehdr(e, &elfhdr) == NULL) {
		ret = EPKG_FATAL;
		pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1));
		goto cleanup;
	}

	if (elfhdr.e_type != ET_DYN && elfhdr.e_type != ET_EXEC &&
	    elfhdr.e_type != ET_REL) {
		pkg_debug(1, "not an elf");
		ret = EPKG_END;
		goto cleanup;
	}

	/* Elf file has sections header */
	while ((scn = elf_nextscn(e, scn)) != NULL) {
		if (gelf_getshdr(scn, &shdr) != &shdr) {
			ret = EPKG_FATAL;
			pkg_emit_error("getshdr() for %s failed: %s", fpath,
					elf_errmsg(-1));
			goto cleanup;
		}
		switch (shdr.sh_type) {
		case SHT_NOTE:
			if ((data = elf_getdata(scn, NULL)) == NULL) {
				ret = EPKG_END; /* Some error occurred, ignore this file */
				goto cleanup;
			}
			else if (data->d_buf != NULL) {
				Elf_Note *en = (Elf_Note *)data->d_buf;
				if (en->n_type == NT_ABI_TAG)
					note = scn;
			}
			break;
		case SHT_DYNAMIC:
			dynamic = scn;
			sh_link = shdr.sh_link;
			if (shdr.sh_entsize == 0) {
				ret = EPKG_END;
				goto cleanup;
			}
			numdyn = shdr.sh_size / shdr.sh_entsize;
			break;
		}

		if (note != NULL && dynamic != NULL)
			break;
	}

	/*
	 * note == NULL usually means a shared object for use with dlopen(3)
	 * dynamic == NULL means not a dynamically linked elf
	 */
	if (dynamic == NULL) {
		ret = EPKG_END;
		goto cleanup; /* not a dynamically linked elf: no results */
	}

	if (!shlib_valid_abi(fpath, &elfhdr, myarch)) {
		ret = EPKG_END;
		goto cleanup; /* Invalid ABI */
	}

#ifdef __FreeBSD__
	if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_FREEBSD &&
	    !is_old_freebsd_armheader(&elfhdr)) {
		ret = EPKG_END;
		goto cleanup;
	}
#endif

	if ((data = elf_getdata(dynamic, NULL)) == NULL) {
		ret = EPKG_END; /* Some error occurred, ignore this file */
		goto cleanup;
	}

	/* First, scan through the data from the .dynamic section to
	   find any RPATH or RUNPATH settings.  These are colon
	   separated paths to prepend to the ld.so search paths from
	   the ELF hints file.  These always seem to come right after
	   the NEEDED shared library entries.

	   NEEDED entries should resolve to a filename for installed
	   executables, but need not resolve for installed shared
	   libraries -- additional info from the apps that link
	   against them would be required.  Shared libraries are
	   distinguished by a DT_SONAME tag */

	rpath_list_init();
	for (dynidx = 0; dynidx < numdyn; dynidx++) {
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
			ret = EPKG_FATAL;
			pkg_emit_error("getdyn() failed for %s: %s", fpath,
			    elf_errmsg(-1));
			goto cleanup;
		}

		if (dyn->d_tag == DT_SONAME) {
			is_shlib = true;

			/* The file being scanned is a shared library
			   *provided* by the package. Record this if
			   appropriate */
			shlib = elf_strptr(e, sh_link, dyn->d_un.d_val);
			if (shlib != NULL && *shlib != '\0')
				pkg_addshlib_provided(pkg, shlib);
		}

		if ((dyn->d_tag == DT_RPATH || dyn->d_tag == DT_RUNPATH) &&
		    rpath == NULL)
			rpath = elf_strptr(e, sh_link, dyn->d_un.d_val);
	}
	if (rpath != NULL)
		shlib_list_from_rpath(rpath, bsd_dirname(fpath));

	/* Now find all of the NEEDED shared libraries. */

	for (dynidx = 0; dynidx < numdyn; dynidx++) {
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
			ret = EPKG_FATAL;
			pkg_emit_error("getdyn() failed for %s: %s", fpath,
			    elf_errmsg(-1));
			goto cleanup;
		}

		if (dyn->d_tag != DT_NEEDED)
			continue;

		shlib = elf_strptr(e, sh_link, dyn->d_un.d_val);

		add_shlibs_to_pkg(pkg, fpath, shlib, is_shlib);
	}

cleanup:
	rpath_list_free();

	if (e != NULL)
		elf_end(e);
	close(fd);

	return (ret);
}