コード例 #1
0
uint8_t *dump_section_data(Elf *elf_object, int *size)
{
	uint8_t *buffer = NULL;
	Elf_Data *data = NULL;
	size_t shdr_num;
	size_t max_saddr = 0;
	GElf_Shdr shdr;
	size_t shstrndx;
	char *name = NULL;

	*size = 0;

	int ret = elf_getshdrnum(elf_object, &shdr_num);
	if (ret) {
		printf("Problem during ELF parsing\n");
		return NULL;
	}

	if (shdr_num == 0)
		return NULL;

	Elf_Scn *cur_section = NULL;
	ret = elf_getshdrstrndx(elf_object, &shstrndx);
	if (ret)
		printf("No string table found\n");

	while ((cur_section = elf_nextscn(elf_object, cur_section)) != NULL ) {
		if (gelf_getshdr(cur_section, &shdr) != &shdr) {
			printf("Problem during ELF parsing\n");
			return NULL;
		}

		if ((shdr.sh_type == SHT_PROGBITS) && (shdr.sh_flags & SHF_ALLOC) && shdr.sh_size != 0) {

			name = elf_strptr(elf_object, shstrndx , shdr.sh_name);
			printf("Loading section %s, size 0x%08X lma 0x%08X\n",
				name ? name : "??", (unsigned int)shdr.sh_size, (unsigned int)shdr.sh_addr);

			if (shdr.sh_addr + shdr.sh_size >= max_saddr) {
				max_saddr = shdr.sh_addr + shdr.sh_size;
				buffer = realloc(buffer, max_saddr);
			}

			data = elf_getdata(cur_section, data);
			if (data != NULL)
				memcpy(buffer + shdr.sh_addr, data->d_buf, data->d_size);
			else {
				printf("Couldn't load section data chunk\n");
				return NULL;
			}
		}
	}

	*size = max_saddr;
	return buffer;
}
コード例 #2
0
static void
elf_foreach_resource_section (Elf             *elf,
                              SectionCallback  callback,
                              gpointer         data)
{
  size_t shstrndx, shnum;
  size_t scnidx;
  Elf_Scn *scn;
  GElf_Shdr *shdr, shdr_mem;
  const gchar *section_name;

  elf_getshdrstrndx (elf, &shstrndx);
  g_assert (shstrndx >= 0);

  elf_getshdrnum (elf, &shnum);
  g_assert (shnum >= 0);

  for (scnidx = 1; scnidx < shnum; scnidx++)
    {
      scn = elf_getscn (elf, scnidx);
      if (scn == NULL)
        continue;

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

      if (shdr->sh_type != SHT_PROGBITS)
        continue;

      section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
      if (section_name == NULL ||
          !g_str_has_prefix (section_name, ".gresource."))
        continue;

      if (!callback (shdr, section_name + strlen (".gresource."), data))
        break;
    }
}
コード例 #3
0
ファイル: check.c プロジェクト: norly/centaur
int elfu_eCheck(Elf *e)
{
  int elfclass;
  GElf_Ehdr ehdr;
  GElf_Phdr *phdrs = NULL;
  GElf_Shdr *shdrs = NULL;
  size_t i, j, numPhdr, numShdr;
  int retval = 0;

  assert(e);

  elfclass = gelf_getclass(e);
  if (elfclass == ELFCLASSNONE) {
    ELFU_WARNELF("getclass");
    goto ERROR;
  }

  if (!gelf_getehdr(e, &ehdr)) {
    ELFU_WARNELF("gelf_getehdr");
    goto ERROR;
  }

  if (ehdr.e_machine != EM_386 && ehdr.e_machine != EM_X86_64) {
    ELFU_WARN("Sorry, only x86-32 and x86-64 ELF files are supported at the moment.\n");
    goto ERROR;
  }

  if (elf_getphdrnum(e, &numPhdr)) {
    ELFU_WARNELF("elf_getphdrnum");
    goto ERROR;
  }

  if (elf_getshdrnum(e, &numShdr)) {
    ELFU_WARNELF("elf_getshdrnum");
    goto ERROR;
  }


  if (numPhdr > 0) {
    phdrs = malloc(numPhdr * sizeof(GElf_Phdr));
    if (!phdrs) {
      ELFU_WARN("elfu_eCheck: malloc() failed for phdrs.\n");
      goto ERROR;
    }

    /* Attempt to load all PHDRs at once to catch any errors early */
    for (i = 0; i < numPhdr; i++) {
      GElf_Phdr phdr;
      if (gelf_getphdr(e, i, &phdr) != &phdr) {
        ELFU_WARN("gelf_getphdr() failed for #%d: %s\n", i, elf_errmsg(-1));
        goto ERROR;
      }

      phdrs[i] = phdr;
    }

    /* Check that LOAD PHDR memory ranges do not overlap, and that others
     * are either fully contained in a LOAD range, or not at all. */
    for (i = 0; i < numPhdr; i++) {
      if (phdrs[i].p_type != PT_LOAD) {
        continue;
      }

      for (j = 0; j < numPhdr; j++) {
        if (j == i || phdrs[j].p_type != PT_LOAD) {
          continue;
        }

        if (OVERLAPPING(phdrs[i].p_vaddr, phdrs[i].p_memsz,
                        phdrs[j].p_vaddr, phdrs[j].p_memsz)) {
          if (phdrs[j].p_type == PT_LOAD) {
            ELFU_WARN("elfu_eCheck: Found LOAD PHDRs that overlap in memory.\n");
            goto ERROR;
          } else if (!FULLY_OVERLAPPING(phdrs[i].p_vaddr, phdrs[i].p_memsz,
                                        phdrs[j].p_vaddr, phdrs[j].p_memsz)) {
            ELFU_WARN("elfu_eCheck: PHDRs %d and %d partially overlap in memory.\n", i, j);
            goto ERROR;
          }
        }
      }
    }
  }


  if (numShdr > 1) {
    /* SHDRs should not overlap with PHDRs. */
    if (OVERLAPPING(ehdr.e_shoff, numShdr * ehdr.e_shentsize,
                    ehdr.e_phoff, numPhdr * ehdr.e_phentsize)) {
      ELFU_WARN("elfu_eCheck: SHDRs overlap with PHDRs.\n");
      goto ERROR;
    }

    shdrs = malloc(numShdr * sizeof(GElf_Shdr));
    if (!shdrs) {
      ELFU_WARN("elfu_eCheck: malloc() failed for shdrs.\n");
      goto ERROR;
    }

    /* Attempt to load all SHDRs at once to catch any errors early */
    for (i = 1; i < numShdr; i++) {
      Elf_Scn *scn;
      GElf_Shdr shdr;

      scn = elf_getscn(e, i);
      if (!scn) {
        ELFU_WARN("elf_getscn() failed for #%d: %s\n", i, elf_errmsg(-1));
      }

      if (gelf_getshdr(scn, &shdr) != &shdr) {
        ELFU_WARNELF("gelf_getshdr");
        goto ERROR;
      }

      shdrs[i] = shdr;
    }


    /* Check that Section memory ranges do not overlap.
     * NB: Section 0 is reserved and thus ignored. */
    for (i = 1; i < numShdr; i++) {
      /* Section should not overlap with EHDR. */
      if (shdrs[i].sh_offset == 0) {
        ELFU_WARN("elfu_eCheck: Section %d overlaps with EHDR.\n", i);
        goto ERROR;
      }

      /* Section should not overlap with PHDRs. */
      if (OVERLAPPING(shdrs[i].sh_offset, SCNFILESIZE(&shdrs[i]),
                      ehdr.e_phoff, numPhdr * ehdr.e_phentsize)) {
        ELFU_WARN("elfu_eCheck: Section %d overlaps with PHDR.\n", i);
        goto ERROR;
      }

      /* Section should not overlap with SHDRs. */
      if (OVERLAPPING(shdrs[i].sh_offset, SCNFILESIZE(&shdrs[i]),
                      ehdr.e_shoff, numShdr * ehdr.e_shentsize)) {
        ELFU_WARN("elfu_eCheck: Section %d overlaps with SHDRs.\n", i);
        goto ERROR;
      }

      for (j = 1; j < numShdr; j++) {
        if (j == i) {
          continue;
        }

        /* Sections must not overlap in memory. */
        if (shdrs[i].sh_addr != 0
            && shdrs[j].sh_addr != 0
            && OVERLAPPING(shdrs[i].sh_addr, shdrs[i].sh_size,
                           shdrs[j].sh_addr, shdrs[j].sh_size)) {
          ELFU_WARN("elfu_eCheck: Sections %d and %d overlap in memory.\n", i, j);
          goto ERROR;
        }

        /* Sections must not overlap in file. */
        if (OVERLAPPING(shdrs[i].sh_offset, SCNFILESIZE(&shdrs[i]),
                        shdrs[j].sh_offset, SCNFILESIZE(&shdrs[j]))) {
          ELFU_WARN("elfu_eCheck: Sections %d and %d overlap in file.\n", i, j);
          goto ERROR;
        }

        /* We may not have more than one symbol table */
        if (shdrs[i].sh_type == SHT_SYMTAB && shdrs[j].sh_type == SHT_SYMTAB) {
          ELFU_WARN("elfu_eCheck: Found more than one SYMTAB section.\n");
          goto ERROR;
        }

        /* We may not have more than one dynamic symbol table */
        if (shdrs[i].sh_type == SHT_DYNSYM && shdrs[j].sh_type == SHT_DYNSYM) {
          ELFU_WARN("elfu_eCheck: Found more than one DYNSYM section.\n");
          goto ERROR;
        }
      }

      /* Section addr/offset should match parent PHDR.
       * Find parent PHDR: */
      for (j = 0; j < numPhdr; j++) {
        if (PHDR_CONTAINS_SCN_IN_MEMORY(&phdrs[j], &shdrs[i])) {
          GElf_Off shoff = phdrs[j].p_offset + (shdrs[i].sh_addr - phdrs[j].p_vaddr);

          if ((shdrs[i].sh_offset != shoff && shdrs[i].sh_type != SHT_NOBITS)
              || !PHDR_CONTAINS_SCN_IN_FILE(&phdrs[j], &shdrs[i])) {
            ELFU_WARN("elfu_eCheck: SHDR %d and PHDR %d report conflicting file/memory regions.\n", i, j);
            goto ERROR;
          }
        }
      }

      /* sh_link members should not point to sections out of range. */
      if (shdrs[i].sh_link >= numShdr) {
        ELFU_WARN("elfu_eCheck: Bogus sh_link in SHDR %d.\n", i);
      }
    }
  }


  DONE:
  if (phdrs) {
    free(phdrs);
  }
  if (shdrs) {
    free(shdrs);
  }
  return retval;

  ERROR:
  ELFU_WARN("elfu_eCheck: Errors found.\n");
  retval = -1;
  goto DONE;
}
コード例 #4
0
ファイル: libelfconn.c プロジェクト: grasshopyx/luaelf
int init(char* fname)
{
	char *id, bytes[5];

	if (elf_version (EV_CURRENT) == EV_NONE) {
		errx (EXIT_FAILURE, " ELF  library   initialization  "
		      " failed : %s", elf_errmsg (-1));
		return -1;
	}

	int fd;
	if ((fd = open (fname, O_RDONLY, 0)) < 0) {
		err (EXIT_FAILURE, " open  \"%s\"  failed ", fname);
		return -1;
	}
	g.fd = fd;

	Elf *e;
	if ((e = elf_begin (fd, ELF_C_READ, NULL)) == NULL) {
		errx (EXIT_FAILURE, " elf_begin ()  failed : %s.",
		      elf_errmsg (-1));
		return -1;
	}

	if (elf_kind (e) != ELF_K_ELF) {
		errx (EXIT_FAILURE, " \"%s\" is  not an  ELF  object .",
		      fname);
		return -1;
	}
	g.e = e;

	GElf_Ehdr ehdr;
	if (gelf_getehdr (e, &ehdr) == NULL) {
		errx (EXIT_FAILURE, " getehdr ()  failed : %s.",
		      elf_errmsg (-1));
		return -1;
	}
	g.ehdr = ehdr;

	int i;
	if ((i = gelf_getclass (e)) == ELFCLASSNONE) {
		errx (EXIT_FAILURE, " getclass ()  failed : %s.",
		      elf_errmsg (-1));
		return -1;
	}

	if ((id = elf_getident (e, NULL)) == NULL) {
		errx (EXIT_FAILURE, " getident ()  failed : %s.",
		      elf_errmsg (-1));
		return -1;
	}

	size_t n;
	if (elf_getshdrnum (e, &n) != 0) {
		errx (EXIT_FAILURE, " getshdrnum ()  failed : %s.",
		      elf_errmsg (-1));
		return -1;
	}
	g.shdrnum = n;

	if (elf_getshdrstrndx (e, &n) != 0) {
		errx (EXIT_FAILURE, " getshdrstrndx ()  failed : %s.",
		      elf_errmsg (-1));
		return -1;
	}
	g.shstrndx = n;

	if (elf_getphdrnum (e, &n) != 0) {
		errx (EXIT_FAILURE, " getphdrnum ()  failed : %s.",
		      elf_errmsg (-1));
		return -1;
	}
	g.phdrnum = n;

	init_scns();
	init_phdrs();

	return 0;
}
コード例 #5
0
static int
ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
{
	GElf_Ehdr sehdr, dehdr;
	Elf_Scn *sscn, *dscn;
	Elf_Data *sdata, *ddata;
	GElf_Shdr shdr;
	int symtab_idx = -1;
	off_t new_offset = 0;
	off_t ctfnameoff = 0;
	int compress = (flags & CTF_ELFWRITE_F_COMPRESS);
	int *secxlate = NULL;
	int srcidx, dstidx, pad, i;
	int curnmoff = 0;
	int changing = 0;
	int ret;
	size_t nshdr, nphdr, strndx;
	void *strdatabuf = NULL, *symdatabuf = NULL;
	size_t strdatasz = 0, symdatasz = 0;

	void *cdata = NULL;
	size_t elfsize, asize;

	if ((flags & ~(CTF_ELFWRITE_F_COMPRESS)) != 0) {
		ret = ctf_set_errno(fp, EINVAL);
		goto out;
	}

	if (gelf_newehdr(dst, gelf_getclass(src)) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (gelf_getehdr(src, &sehdr) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	(void) memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr));
	if (gelf_update_ehdr(dst, &dehdr) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/*
	 * Use libelf to get the number of sections and the string section to
	 * deal with ELF files that may have a large number of sections. We just
	 * always use this to make our live easier.
	 */
	if (elf_getphdrnum(src, &nphdr) != 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (elf_getshdrnum(src, &nshdr) != 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (elf_getshdrstrndx(src, &strndx) != 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/*
	 * Neither the existing debug sections nor the SUNW_ctf sections (new or
	 * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
	 * program headers.  As such, we can just blindly copy the program
	 * headers from the existing file to the new file.
	 */
	if (nphdr != 0) {
		(void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT);
		if (gelf_newphdr(dst, nphdr) == 0) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		for (i = 0; i < nphdr; i++) {
			GElf_Phdr phdr;

			if (gelf_getphdr(src, i, &phdr) == NULL) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
			if (gelf_update_phdr(dst, i, &phdr) == 0) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
		}
	}

	secxlate = ctf_alloc(sizeof (int) * nshdr);
	for (srcidx = dstidx = 0; srcidx < nshdr; srcidx++) {
		Elf_Scn *scn = elf_getscn(src, srcidx);
		GElf_Shdr shdr;
		char *sname;

		if (gelf_getshdr(scn, &shdr) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		sname = elf_strptr(src, strndx, shdr.sh_name);
		if (sname == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
			secxlate[srcidx] = -1;
		} else {
			secxlate[srcidx] = dstidx++;
			curnmoff += strlen(sname) + 1;
		}

		new_offset = (off_t)dehdr.e_phoff;
	}

	for (srcidx = 1; srcidx < nshdr; srcidx++) {
		char *sname;

		sscn = elf_getscn(src, srcidx);
		if (gelf_getshdr(sscn, &shdr) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		if (secxlate[srcidx] == -1) {
			changing = 1;
			continue;
		}

		dscn = elf_newscn(dst);
		if (dscn == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		/*
		 * If this file has program headers, we need to explicitly lay
		 * out sections.  If none of the sections prior to this one have
		 * been removed, then we can just use the existing location.  If
		 * one or more sections have been changed, then we need to
		 * adjust this one to avoid holes.
		 */
		if (changing && nphdr != 0) {
			pad = new_offset % shdr.sh_addralign;

			if (pad != 0)
				new_offset += shdr.sh_addralign - pad;
			shdr.sh_offset = new_offset;
		}

		shdr.sh_link = secxlate[shdr.sh_link];

		if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA)
			shdr.sh_info = secxlate[shdr.sh_info];

		sname = elf_strptr(src, strndx, shdr.sh_name);
		if (sname == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		if ((sdata = elf_getdata(sscn, NULL)) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		if ((ddata = elf_newdata(dscn)) == NULL) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}
		bcopy(sdata, ddata, sizeof (Elf_Data));

		if (srcidx == strndx) {
			char seclen = strlen(CTF_ELF_SCN_NAME);

			strdatasz = ddata->d_size + shdr.sh_size +
			    seclen + 1;
			ddata->d_buf = strdatabuf = ctf_alloc(strdatasz);
			if (ddata->d_buf == NULL) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
			bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
			(void) strcpy((caddr_t)ddata->d_buf + shdr.sh_size,
			    CTF_ELF_SCN_NAME);
			ctfnameoff = (off_t)shdr.sh_size;
			shdr.sh_size += seclen + 1;
			ddata->d_size += seclen + 1;

			if (nphdr != 0)
				changing = 1;
		}

		if (shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) {
			int nsym = shdr.sh_size / shdr.sh_entsize;

			symtab_idx = secxlate[srcidx];

			symdatasz = shdr.sh_size;
			ddata->d_buf = symdatabuf = ctf_alloc(symdatasz);
			if (ddata->d_buf == NULL) {
				ret = ctf_set_errno(fp, ECTF_ELF);
				goto out;
			}
			(void) bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);

			for (i = 0; i < nsym; i++) {
				GElf_Sym sym;
				short newscn;

				(void) gelf_getsym(ddata, i, &sym);

				if (sym.st_shndx >= SHN_LORESERVE)
					continue;

				if ((newscn = secxlate[sym.st_shndx]) !=
				    sym.st_shndx) {
					sym.st_shndx =
					    (newscn == -1 ? 1 : newscn);

					if (gelf_update_sym(ddata, i, &sym) ==
					    0) {
						ret = ctf_set_errno(fp,
						    ECTF_ELF);
						goto out;
					}
				}
			}
		}

		if (gelf_update_shdr(dscn, &shdr) == 0) {
			ret = ctf_set_errno(fp, ECTF_ELF);
			goto out;
		}

		new_offset = (off_t)shdr.sh_offset;
		if (shdr.sh_type != SHT_NOBITS)
			new_offset += shdr.sh_size;
	}

	if (symtab_idx == -1) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/* Add the ctf section */
	if ((dscn = elf_newscn(dst)) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (gelf_getshdr(dscn, &shdr) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	shdr.sh_name = ctfnameoff;
	shdr.sh_type = SHT_PROGBITS;
	shdr.sh_size = fp->ctf_size;
	shdr.sh_link = symtab_idx;
	shdr.sh_addralign = 4;
	if (changing && nphdr != 0) {
		pad = new_offset % shdr.sh_addralign;

		if (pad)
			new_offset += shdr.sh_addralign - pad;

		shdr.sh_offset = new_offset;
		new_offset += shdr.sh_size;
	}

	if ((ddata = elf_newdata(dscn)) == NULL) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	if (compress != 0) {
		int err;

		if (ctf_zopen(&err) == NULL) {
			ret = ctf_set_errno(fp, err);
			goto out;
		}

		if ((err = ctf_compress(fp, &cdata, &asize, &elfsize)) != 0) {
			ret = ctf_set_errno(fp, err);
			goto out;
		}
		ddata->d_buf = cdata;
		ddata->d_size = elfsize;
	} else {
		ddata->d_buf = (void *)fp->ctf_base;
		ddata->d_size = fp->ctf_size;
	}
	ddata->d_align = shdr.sh_addralign;

	if (gelf_update_shdr(dscn, &shdr) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	/* update the section header location */
	if (nphdr != 0) {
		size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT);
		size_t r = new_offset % align;

		if (r)
			new_offset += align - r;

		dehdr.e_shoff = new_offset;
	}

	/* commit to disk */
	if (sehdr.e_shstrndx == SHN_XINDEX)
		dehdr.e_shstrndx = SHN_XINDEX;
	else
		dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx];
	if (gelf_update_ehdr(dst, &dehdr) == 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}
	if (elf_update(dst, ELF_C_WRITE) < 0) {
		ret = ctf_set_errno(fp, ECTF_ELF);
		goto out;
	}

	ret = 0;

out:
	if (strdatabuf != NULL)
		ctf_free(strdatabuf, strdatasz);
	if (symdatabuf != NULL)
		ctf_free(symdatabuf, symdatasz);
	if (cdata != NULL)
		ctf_data_free(cdata, fp->ctf_size);
	if (secxlate != NULL)
		ctf_free(secxlate, sizeof (int) * nshdr);

	return (ret);
}
コード例 #6
0
static const value_t *
elf_get_ehdr(const value_t *this_fn, parser_state_t *state,
             const char *filename, int binfd,
             Elf *e, GElf_Ehdr *ehdr, void *arg)
{
   int eclass = gelf_getclass(e);
   char *id = elf_getident(e, NULL);
   dir_t *einfo = dir_id_new();
   dir_t *edir = dir_id_new();
   size_t n;

   if (eclass == ELFCLASS32)
      dir_string_set(einfo, "class", value_int_new(32));
   else if (eclass == ELFCLASS64)
      dir_string_set(einfo, "class", value_int_new(64));
   else {
      dir_string_set(einfo, "class", &value_null);
      if (eclass != ELFCLASSNONE)
         parser_report(state, "ELF file has unknown class %d - %s\n",
                       eclass, elf_errmsg(-1));
   }

   if (id == NULL)
      parser_report(state, "ELF file has unknown identity - %s\n",
                    elf_errmsg(-1));
   else
      dir_string_set(einfo, "id",
                     value_string_new(id, EI_NIDENT));

   dir_string_set(einfo, "ehdr", dir_value(edir));

   dir_string_set(edir,"type"   , value_int_new(ehdr->e_type));
   dir_string_set(edir,"machine", value_int_new(ehdr->e_machine));
   dir_string_set(edir,"version", value_int_new(ehdr->e_version));
   dir_string_set(edir,"entry"  , value_int_new(ehdr->e_entry));
   dir_string_set(edir,"phoff"  , value_int_new(ehdr->e_phoff));
   dir_string_set(edir,"shoff"  , value_int_new(ehdr->e_shoff));
   dir_string_set(edir,"flags"  , value_int_new(ehdr->e_flags));
   dir_string_set(edir,"ehsize" , value_int_new(ehdr->e_ehsize));
   dir_string_set(edir,"phentsize",
                  value_int_new(ehdr->e_phentsize));
   dir_string_set(edir,"shentsize",
                  value_int_new(ehdr->e_shentsize));

   if (elf_getphdrnum(e, &n) != 0)
      parser_report(state,"ELF file has unknown number of segments - %s\n",
                    elf_errmsg(-1));
   else
      dir_string_set(einfo, "progsects", value_int_new(n));

   if (elf_getshdrnum(e, &n) != 0)
      parser_report(state, "%s: ELF file has unknown number of sections - %s\n",
                    elf_errmsg(-1));
   else
      dir_string_set(einfo, "sections", value_int_new(n));

   if (elf_getshdrstrndx(e, &n) != 0)
      parser_report(state, "%s: ELF file has no section names - %s\n",
                    elf_errmsg(-1));
   else
      dir_string_set(einfo, "shdrstrndx", value_int_new(n));

   return dir_value(einfo);
}