dwarves.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] Add scncopy - like object copy but tries not to change section content
@ 2010-01-11 20:50 Peter Jones
       [not found] ` <1263243031-19401-1-git-send-email-pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 2+ messages in thread
From: Peter Jones @ 2010-01-11 20:50 UTC (permalink / raw)
  To: acme-H+wXaHxf7aLQT0dZR+AlfA; +Cc: dwarves-u79uwXL29TY76Z2rM5mHXA, Peter Jones

This adds scncopy, which is like objcopy with some differences:
- it doesn't try to update section contents, but does try to
  update program headers and such to correctly reflect the section
  contents.
- it doesn't necessarily try to create a binary eu-elflint will like.
  If you don't copy a required section, it won't make it for you.

TODO:
- Make it possible to copy sections to an already existant binary.
- Make phdrs only copy if they're needed, and/or modify old phdrs to
  point to new sections
- Make sure nothing is missing from fixup_dynamic()
---
 elfcreator.c |  297 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 elfcreator.h |   20 ++++
 scncopy.c    |  125 ++++++++++++++++++++++++
 3 files changed, 442 insertions(+), 0 deletions(-)
 create mode 100644 elfcreator.c
 create mode 100644 elfcreator.h
 create mode 100644 scncopy.c

diff --git a/elfcreator.c b/elfcreator.c
new file mode 100644
index 0000000..c284b52
--- /dev/null
+++ b/elfcreator.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * Author: Peter Jones <pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
+ */
+#include <dlfcn.h>
+#include <gelf.h>
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "elfcreator.h"
+
+struct elf_creator {
+	const char *path;
+	int fd;
+
+	Elf *elf;
+	GElf_Ehdr *ehdr, ehdr_mem;
+
+	Elf *oldelf;
+	/* just because we have to look this up /so/ often... */
+	Elf_Scn *dynscn;
+	GElf_Shdr *dynshdr, dynshdr_mem;
+	Elf_Data *dyndata;
+};
+
+static void clear(ElfCreator *ctor, int do_unlink)
+{
+	if (do_unlink) {
+		if (ctor->elf)
+			elf_end(ctor->elf);
+		if (ctor->fd >= 0)
+			close(ctor->fd);
+		if (ctor->path)
+			unlink(ctor->path);
+	} else {
+		if (ctor->elf) {
+			elf_update(ctor->elf, ELF_C_WRITE_MMAP);
+			elf_end(ctor->elf);
+		}
+		if (ctor->fd >= 0)
+			close(ctor->fd);
+	}
+	memset(ctor, '\0', sizeof(*ctor));
+}
+
+ElfCreator *elfcreator_begin(char *path, Elf *elf) {
+	ElfCreator *ctor = NULL;
+	GElf_Ehdr ehdr_mem, *ehdr;
+	GElf_Half machine;
+
+	if (!(ctor = calloc(1, sizeof(*ctor))))
+		return NULL;
+
+	clear(ctor, 0);
+
+	ctor->path = path;
+	ctor->oldelf = elf;
+
+	ehdr = gelf_getehdr(elf, &ehdr_mem);
+	machine = ehdr->e_machine;
+
+	if ((ctor->fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0755)) < 0) {
+err:
+		clear(ctor, 1);
+		free(ctor);
+		return NULL;
+	}
+
+	if (!(ctor->elf = elf_begin(ctor->fd, ELF_C_WRITE_MMAP, elf)))
+		goto err;
+
+	gelf_newehdr(ctor->elf, gelf_getclass(elf));
+	gelf_update_ehdr(ctor->elf, ehdr);
+
+	if (!(ctor->ehdr = gelf_getehdr(ctor->elf, &ctor->ehdr_mem)))
+		goto err;
+
+	return ctor;
+}
+
+static Elf_Scn *get_scn_by_type(ElfCreator *ctor, Elf64_Word sh_type)
+{
+	Elf_Scn *scn = NULL;
+
+	while ((scn = elf_nextscn(ctor->elf, scn)) != NULL) {
+		GElf_Shdr *shdr, shdr_mem;
+
+		shdr = gelf_getshdr(scn, &shdr_mem);
+		if (shdr->sh_type == sh_type)
+			return scn;
+	}
+	return NULL;
+}
+
+static void update_dyn_cache(ElfCreator *ctor)
+{
+	ctor->dynscn = get_scn_by_type(ctor, SHT_DYNAMIC);
+	if (ctor->dynscn == NULL)
+		return;
+
+	ctor->dynshdr = gelf_getshdr(ctor->dynscn, &ctor->dynshdr_mem);
+	ctor->dyndata = elf_getdata(ctor->dynscn, NULL);
+}
+
+void elfcreator_copy_scn(ElfCreator *ctor, Elf *src, Elf_Scn *scn)
+{
+	Elf_Scn *newscn;
+	Elf_Data *indata, *outdata;
+	GElf_Shdr *oldshdr, oldshdr_mem;
+	GElf_Shdr *newshdr, newshdr_mem;
+
+	newscn = elf_newscn(ctor->elf);
+	newshdr = gelf_getshdr(newscn, &newshdr_mem);
+
+	oldshdr = gelf_getshdr(scn, &oldshdr_mem);
+
+	memmove(newshdr, oldshdr, sizeof(*newshdr));
+	gelf_update_shdr(newscn, newshdr);
+
+	indata = NULL;
+	while ((indata = elf_getdata(scn, indata)) != NULL) {
+		outdata = elf_newdata(newscn);
+		*outdata = *indata;
+	}
+	if (newshdr->sh_type == SHT_DYNAMIC)
+		update_dyn_cache(ctor);
+}
+
+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;
+}
+
+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);
+}
+
+typedef void (*dyn_fixup_fn)(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn);
+
+static void generic_dyn_fixup_fn(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn)
+{
+	GElf_Shdr *shdr, shdr_mem;
+	GElf_Dyn *dyn, dyn_mem;
+	size_t idx;
+
+	dyn = get_dyn_by_tag(ctor, d_tag, &dyn_mem, &idx);
+	shdr = gelf_getshdr(scn, &shdr_mem);
+	if (shdr) {
+		dyn->d_un.d_ptr = shdr->sh_addr;
+		gelf_update_dyn(ctor->dyndata, idx, dyn);
+	} else {
+		remove_dyn(ctor, idx);
+	}
+}
+
+static void rela_dyn_fixup_fn(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn)
+{
+	GElf_Shdr *shdr, shdr_mem;
+	GElf_Dyn *dyn, dyn_mem;
+	size_t idx;
+
+	dyn = get_dyn_by_tag(ctor, d_tag, &dyn_mem, &idx);
+	shdr = gelf_getshdr(scn, &shdr_mem);
+	if (shdr) {
+		dyn->d_un.d_ptr = shdr->sh_addr;
+		gelf_update_dyn(ctor->dyndata, idx, dyn);
+	} else {
+		remove_dyn(ctor, idx);
+		dyn = get_dyn_by_tag(ctor, DT_RELASZ, &dyn_mem, &idx);
+		if (dyn) {
+			dyn->d_un.d_val = 0;
+			gelf_update_dyn(ctor->dyndata, idx, dyn);
+		}
+	}
+}
+
+static void rel_dyn_fixup_fn(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn)
+{
+	GElf_Shdr *shdr, shdr_mem;
+	GElf_Dyn *dyn, dyn_mem;
+	size_t idx;
+
+	dyn = get_dyn_by_tag(ctor, d_tag, &dyn_mem, &idx);
+	shdr = gelf_getshdr(scn, &shdr_mem);
+	if (shdr) {
+		dyn->d_un.d_ptr = shdr->sh_addr;
+		gelf_update_dyn(ctor->dyndata, idx, dyn);
+	} else {
+		remove_dyn(ctor, idx);
+		dyn = get_dyn_by_tag(ctor, DT_RELSZ, &dyn_mem, &idx);
+		if (dyn) {
+			dyn->d_un.d_val = 0;
+			gelf_update_dyn(ctor->dyndata, idx, dyn);
+		}
+	}
+}
+
+static void fixup_dynamic(ElfCreator *ctor)
+{
+	struct {
+		Elf64_Sxword d_tag;
+		Elf64_Word sh_type;
+		dyn_fixup_fn fn;
+	} fixups[] = {
+		{ DT_HASH, SHT_HASH, NULL },
+		{ DT_STRTAB, SHT_STRTAB, NULL },
+		{ DT_SYMTAB, SHT_SYMTAB, NULL },
+		{ DT_RELA, SHT_RELA, rela_dyn_fixup_fn},
+		{ DT_REL, SHT_REL, rel_dyn_fixup_fn},
+		{ DT_GNU_HASH, SHT_GNU_HASH, NULL },
+		{ DT_NULL, SHT_NULL, NULL }
+	};
+	int i;
+
+	for (i = 0; fixups[i].d_tag != DT_NULL; i++) {
+		Elf_Scn *scn;
+
+		scn = get_scn_by_type(ctor, fixups[i].sh_type);
+		if (fixups[i].fn)
+			fixups[i].fn(ctor, fixups[i].d_tag, scn);
+		else
+			generic_dyn_fixup_fn(ctor, fixups[i].d_tag, scn);
+	}
+}
+
+void elfcreator_end(ElfCreator *ctor)
+{
+	GElf_Phdr phdr_mem, *phdr;
+	int m,n;
+
+	for (m = 0; (phdr = gelf_getphdr(ctor->oldelf, m, &phdr_mem)) != NULL; m++)
+		/* XXX this should check if an entry is needed */;
+
+	gelf_newphdr(ctor->elf, m);
+	elf_update(ctor->elf, ELF_C_NULL);
+	update_dyn_cache(ctor);
+
+	for (n = 0; n < m; n++) {
+		/* XXX this should check if an entry is needed */
+		phdr = gelf_getphdr(ctor->oldelf, n, &phdr_mem);
+		if (ctor->dynshdr && phdr->p_type == PT_DYNAMIC)
+			phdr->p_offset = ctor->dynshdr->sh_offset;
+
+		gelf_update_phdr(ctor->elf, n, phdr);
+	}
+
+	fixup_dynamic(ctor);
+
+	clear(ctor, 0);
+	free(ctor);
+}
diff --git a/elfcreator.h b/elfcreator.h
new file mode 100644
index 0000000..7de1a98
--- /dev/null
+++ b/elfcreator.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * Author: Peter Jones <pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
+ */
+#ifndef ELFCREATOR_H
+#define ELFCREATOR_H 1
+
+#include <gelf.h>
+
+typedef struct elf_creator ElfCreator;
+extern ElfCreator *elfcreator_begin(char *path, Elf *elf);
+extern void elfcreator_copy_scn(ElfCreator *ctor, Elf *src, Elf_Scn *scn);
+extern void elfcreator_end(ElfCreator *ctor);
+
+#endif /* ELFCREATOR_H */
diff --git a/scncopy.c b/scncopy.c
new file mode 100644
index 0000000..38aaa9a
--- /dev/null
+++ b/scncopy.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * Author: Peter Jones <pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
+ */
+#include <gelf.h>
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "elfcreator.h"
+#include "dutil.h"
+
+static int should_copy_scn(Elf *elf, GElf_Shdr *shdr, struct strlist *scns)
+{
+	char *name;
+	size_t shstrndx;
+
+	if (elf_getshdrstrndx(elf, &shstrndx) < 0)
+		return 0;
+	name = elf_strptr(elf, shstrndx, shdr->sh_name);
+	if (name == NULL)
+		return 0;
+
+	if (strlist__has_entry(scns, name))
+		return 1;
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int n;
+	struct strlist *sections;
+	char *infile = NULL, *outfile = NULL;
+	int fd;
+	Elf *elf;
+	Elf_Scn *scn;
+	int copy_all_sections = 0;
+	ElfCreator *ctor;
+
+	sections = strlist__new(false);
+	for (n = 1; n < argc; n++) {
+		if (!strcmp(argv[n], "-a")) {
+			copy_all_sections = 1;
+		} else if (!strcmp(argv[n], "-s")) {
+			if (n == argc-1) {
+				fprintf(stderr, "Missing argument to -s\n");
+				return -1;
+			}
+			n++;
+			strlist__add(sections, argv[n]);
+			continue;
+		} else if (!strcmp(argv[n], "-o")) {
+			if (n == argc-1) {
+				fprintf(stderr, "Missing argument to -o\n");
+				return -1;
+			}
+			n++;
+			outfile = argv[n];
+			continue;
+		} else if (!strcmp(argv[n], "-?") || !strcmp(argv[n],"--usage")) {
+			printf("usage: pjoc -s section 0 [[-s section1] ... -s sectionN] -o outfile infile\n");
+			return 0;
+		} else if (n == argc-1) {
+			infile = argv[n];
+		} else {
+			fprintf(stderr, "usage: pjoc -s section 0 [[-s section1] ... -s sectionN] -o outfile infile\n");
+			return 1;
+		}
+	}
+	if (!infile || !outfile) {
+		fprintf(stderr, "usage: pjoc -s section 0 [[-s section1] ... -s sectionN] -o outfile infile\n");
+		return 1;
+	}
+
+	if (!(fd = open(infile, O_RDONLY))) {
+		fprintf(stderr, "Could not open \"%s\" for reading: %m\n", infile);
+		return 1;
+	}
+
+	elf_version(EV_CURRENT);
+
+	if ((elf = elf_begin(fd, ELF_C_READ_MMAP_PRIVATE, NULL)) == NULL) {
+		fprintf(stderr, "cannot get elf descriptor for \"%s\": %s\n",
+				infile, elf_errmsg(-1));
+		close(fd);
+		return 1;
+	}
+
+	if (elf_kind(elf) != ELF_K_ELF) {
+		fprintf(stderr, "\"%s\" is not an ELF file\n", infile);
+err:
+		elf_end(elf);
+		close(fd);
+		return 1;
+	}
+
+	if ((ctor = elfcreator_begin(outfile, elf)) == NULL) {
+		fprintf(stderr, "could not initialize ELF creator\n");
+		goto err;
+	}
+
+	scn = NULL;
+	while ((scn = elf_nextscn(elf, scn)) != NULL) {
+		GElf_Shdr shdr_mem, *shdr;
+
+		shdr = gelf_getshdr(scn, &shdr_mem);
+		if (shdr == NULL)
+			continue;
+
+		if (!should_copy_scn(elf, shdr, sections) && !copy_all_sections)
+			continue;
+
+		elfcreator_copy_scn(ctor, elf, scn);
+	}
+	elfcreator_end(ctor);
+	return 0;
+}
-- 
1.6.5.2

--
To unsubscribe from this list: send the line "unsubscribe dwarves" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH 2/2] Add scncopy to CMakeLists.txt
       [not found] ` <1263243031-19401-1-git-send-email-pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
@ 2010-01-11 20:50   ` Peter Jones
  0 siblings, 0 replies; 2+ messages in thread
From: Peter Jones @ 2010-01-11 20:50 UTC (permalink / raw)
  To: acme-H+wXaHxf7aLQT0dZR+AlfA; +Cc: dwarves-u79uwXL29TY76Z2rM5mHXA, Peter Jones

Add scncopy to the build.
---
 CMakeLists.txt         |    6 +++++-
 MANIFEST               |    3 +++
 rpm/SPECS/dwarves.spec |    1 +
 3 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 60e5d1b..3eea4fa 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -83,12 +83,16 @@ set(prefcnt_SRCS prefcnt.c)
 add_executable(prefcnt ${prefcnt_SRCS})
 target_link_libraries(prefcnt dwarves)
 
+set(scncopy_SRCS scncopy.c elfcreator.c)
+add_executable(scncopy ${scncopy_SRCS})
+target_link_libraries(scncopy dwarves)
+
 set(syscse_SRCS syscse.c)
 add_executable(syscse ${syscse_SRCS})
 target_link_libraries(syscse dwarves)
 
 install(TARGETS codiff ctracer dtagnames pahole pdwtags
-		pfunct pglobal prefcnt syscse RUNTIME DESTINATION
+		pfunct pglobal prefcnt scncopy syscse RUNTIME DESTINATION
 		${CMAKE_INSTALL_PREFIX}/bin)
 install(TARGETS dwarves LIBRARY DESTINATION ${LIB_INSTALL_DIR})
 install(TARGETS dwarves dwarves_emit dwarves_reorganize LIBRARY DESTINATION ${LIB_INSTALL_DIR})
diff --git a/MANIFEST b/MANIFEST
index 736c9ff..25037eb 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -15,6 +15,8 @@ CMakeLists.txt
 codiff.c
 ctracer.c
 dtagnames.c
+elfcreator.c
+elfcreator.h
 elf_symtab.c
 elf_symtab.h
 gobuffer.c
@@ -30,6 +32,7 @@ pglobal.c
 prefcnt.c
 rbtree.c
 rbtree.h
+scncopy.c
 syscse.c
 strings.c
 strings.h
diff --git a/rpm/SPECS/dwarves.spec b/rpm/SPECS/dwarves.spec
index 94cc0d6..909abee 100644
--- a/rpm/SPECS/dwarves.spec
+++ b/rpm/SPECS/dwarves.spec
@@ -77,6 +77,7 @@ rm -rf %{buildroot}
 %{_bindir}/pfunct
 %{_bindir}/pglobal
 %{_bindir}/prefcnt
+%{_bindir}/scncopy
 %{_bindir}/syscse
 %{_bindir}/ostra-cg
 %dir %{_datadir}/dwarves/
-- 
1.6.5.2

--
To unsubscribe from this list: send the line "unsubscribe dwarves" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2010-01-11 20:50 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-01-11 20:50 [PATCH 1/2] Add scncopy - like object copy but tries not to change section content Peter Jones
     [not found] ` <1263243031-19401-1-git-send-email-pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2010-01-11 20:50   ` [PATCH 2/2] Add scncopy to CMakeLists.txt Peter Jones

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).