LogoopenSUSE Build Service > Projects
Sign Up | Log In

View File extract_from_elf.c of Package petitboot (Project DISCONTINUED:openSUSE:11.1)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <elf.h>

#ifndef __BIG_ENDIAN__
int main(void)
{
	return 123;
}
#else
#ifdef DEBUG
#define dump_member64(struct,member) do {printf(#member":\t %016llx\n",(unsigned long long) struct.member); } while(0)
#define dump_member32(struct,member) do {printf(#member":\t %08lx\n",(unsigned long) struct.member); } while(0)
#else
#define dump_member64(struct,member)
#define dump_member32(struct,member)
#endif
static const char *elf_filename;
static const char *elf_section;
static const char *output_filename;

static void write_section_to_file(const unsigned char const *file, off_t sh_offset, size_t sh_size)
{
	ssize_t ret;
	int fd;
	fd = open(output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
	if (fd < 0) {
		perror(output_filename);
		return;
	}
	ret = write(fd, file + sh_offset, sh_size);
	if (ret < 0)
		perror(output_filename);
	else if (ret < sh_size)
		printf("wrote only %d of %u bytes to %s\n", ret, sh_size, output_filename);
	close(fd);
}

static void read_elf64_sh(const unsigned char const *file, Elf64_Off e_shoff, Elf64_Half e_shentsize, Elf64_Half e_shnum, Elf64_Half e_shstrndx)
{
	Elf64_Shdr sh;
	const char const *name;
	int i;
	name = (const char const *)file + ((Elf64_Shdr *) (file + e_shoff + (e_shstrndx * e_shentsize)))->sh_offset;
	for (i = 0; i < e_shnum; i++) {
		memcpy(&sh, file + e_shoff + (i * e_shentsize), sizeof(sh));
		if (strcmp(name + sh.sh_name, elf_section) == 0) {
#ifdef DEBUG
			printf("sh #%d: '%s'\n", i, name + sh.sh_name);
#endif
			dump_member64(sh, sh_name);
			dump_member64(sh, sh_type);
			dump_member64(sh, sh_flags);
			dump_member64(sh, sh_addr);
			dump_member64(sh, sh_offset);
			dump_member64(sh, sh_size);
			dump_member64(sh, sh_link);
			dump_member64(sh, sh_info);
			dump_member64(sh, sh_addralign);
			dump_member64(sh, sh_entsize);
			write_section_to_file(file, sh.sh_offset, sh.sh_size);
			return;
		}
	}
}
static void read_elf64(const unsigned char const *file)
{
	Elf64_Ehdr e;
	memcpy(&e, file, sizeof(e));
	dump_member64(e, e_type);
	dump_member64(e, e_machine);
	dump_member64(e, e_version);
	dump_member64(e, e_entry);
	dump_member64(e, e_phoff);
	dump_member64(e, e_shoff);
	dump_member64(e, e_flags);
	dump_member64(e, e_ehsize);
	dump_member64(e, e_phentsize);
	dump_member64(e, e_phnum);
	dump_member64(e, e_shentsize);
	dump_member64(e, e_shnum);
	dump_member64(e, e_shstrndx);

	read_elf64_sh(file, e.e_shoff, e.e_shentsize, e.e_shnum, e.e_shstrndx);
}

static void read_elf32_sh(const unsigned char const *file, Elf32_Off e_shoff, Elf32_Half e_shentsize, Elf32_Half e_shnum, Elf32_Half e_shstrndx)
{
	Elf32_Shdr sh;
	const char const *name;
	int i;
	name = (const char const *)file + ((Elf32_Shdr *) (file + e_shoff + (e_shstrndx * e_shentsize)))->sh_offset;
	for (i = 0; i < e_shnum; i++) {
		memcpy(&sh, file + e_shoff + (i * e_shentsize), sizeof(sh));
		if (strcmp(name + sh.sh_name, elf_section) == 0) {
#ifdef DEBUG
			printf("sh #%d: '%s'\n", i, name + sh.sh_name);
#endif
			dump_member32(sh, sh_name);
			dump_member32(sh, sh_type);
			dump_member32(sh, sh_flags);
			dump_member32(sh, sh_addr);
			dump_member32(sh, sh_offset);
			dump_member32(sh, sh_size);
			dump_member32(sh, sh_link);
			dump_member32(sh, sh_info);
			dump_member32(sh, sh_addralign);
			dump_member32(sh, sh_entsize);
			write_section_to_file(file, sh.sh_offset, sh.sh_size);
			return;
		}
	}
}
static void read_elf32(const unsigned char const *file)
{
	Elf32_Ehdr e;
	memcpy(&e, file, sizeof(e));
	dump_member32(e, e_type);
	dump_member32(e, e_machine);
	dump_member32(e, e_version);
	dump_member32(e, e_entry);
	dump_member32(e, e_phoff);
	dump_member32(e, e_shoff);
	dump_member32(e, e_flags);
	dump_member32(e, e_ehsize);
	dump_member32(e, e_phentsize);
	dump_member32(e, e_phnum);
	dump_member32(e, e_shentsize);
	dump_member32(e, e_shnum);
	dump_member32(e, e_shstrndx);

	read_elf32_sh(file, e.e_shoff, e.e_shentsize, e.e_shnum, e.e_shstrndx);
}

static void read_elf_file(const unsigned char const *file)
{
	if (file[EI_DATA] != ELFDATA2MSB)
		return;
	if (file[EI_MAG0] == ELFMAG0 && file[EI_MAG1] == ELFMAG1 && file[EI_MAG2] == ELFMAG2 && file[EI_MAG3] == ELFMAG3) {
		switch (file[EI_CLASS]) {
		case ELFCLASS64:
			read_elf64(file);
			break;
		case ELFCLASS32:
			read_elf32(file);
			break;
		}
	}
}
int main(int argc, char *argv[])
{
	struct stat sb;
	const unsigned char const *file;
	int fd, skip = 0;

	for (fd = 1; fd < argc; fd++) {
		if (skip)
			skip = 0;
		else if (argv[fd][0] == '-' && fd < argc) {
			switch (argv[fd][1]) {
			case 'e':
				elf_section = argv[fd + 1];
				skip = 1;
				break;
			case 'i':
				elf_filename = argv[fd + 1];
				skip = 1;
				break;
			case 'o':
				output_filename = argv[fd + 1];
				skip = 1;
				break;
			}

		}
	}
	if (!(elf_filename && elf_section && output_filename)) {
		printf("Usage: %s -i elf_filename -e elf_section -o output_filename \n", argv[0]);
		return 42;
	}
	fd = open(elf_filename, O_RDONLY);
	if (fd < 0)
		return 1;
	if (fstat(fd, &sb) < 0 || sb.st_size == 0)
		return 2;
	file = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
	if (file == MAP_FAILED)
		return 3;
	read_elf_file(file);
	return 0;
}
#endif