File Index
Files and directories
Sign in
FILE

elf-parse.c

File preview with syntax highlighting.

linux-6.19.14/scripts/elf-parse.c C
  1#include <sys/types.h>
  2#include <sys/mman.h>
  3#include <sys/stat.h>
  4#include <fcntl.h>
  5#include <stdio.h>
  6#include <stdlib.h>
  7#include <stdbool.h>
  8#include <string.h>
  9#include <unistd.h>
 10#include <errno.h>
 11
 12#include "elf-parse.h"
 13
 14struct elf_funcs elf_parser;
 15
 16/*
 17 * Get the whole file as a programming convenience in order to avoid
 18 * malloc+lseek+read+free of many pieces.  If successful, then mmap
 19 * avoids copying unused pieces; else just read the whole file.
 20 * Open for both read and write.
 21 */
 22static void *map_file(char const *fname, size_t *size)
 23{
 24	int fd;
 25	struct stat sb;
 26	void *addr = NULL;
 27
 28	fd = open(fname, O_RDWR);
 29	if (fd < 0) {
 30		perror(fname);
 31		return NULL;
 32	}
 33	if (fstat(fd, &sb) < 0) {
 34		perror(fname);
 35		goto out;
 36	}
 37	if (!S_ISREG(sb.st_mode)) {
 38		fprintf(stderr, "not a regular file: %s\n", fname);
 39		goto out;
 40	}
 41
 42	addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
 43	if (addr == MAP_FAILED) {
 44		fprintf(stderr, "Could not mmap file: %s\n", fname);
 45		goto out;
 46	}
 47
 48	*size = sb.st_size;
 49
 50out:
 51	close(fd);
 52	return addr;
 53}
 54
 55static int elf_parse(const char *fname, void *addr, uint32_t types)
 56{
 57	Elf_Ehdr *ehdr = addr;
 58	uint16_t type;
 59
 60	switch (ehdr->e32.e_ident[EI_DATA]) {
 61	case ELFDATA2LSB:
 62		elf_parser.r	= rle;
 63		elf_parser.r2	= r2le;
 64		elf_parser.r8	= r8le;
 65		elf_parser.w	= wle;
 66		elf_parser.w8	= w8le;
 67		break;
 68	case ELFDATA2MSB:
 69		elf_parser.r	= rbe;
 70		elf_parser.r2	= r2be;
 71		elf_parser.r8	= r8be;
 72		elf_parser.w	= wbe;
 73		elf_parser.w8	= w8be;
 74		break;
 75	default:
 76		fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
 77			ehdr->e32.e_ident[EI_DATA], fname);
 78		return -1;
 79	}
 80
 81	if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
 82	    ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
 83		fprintf(stderr, "unrecognized ELF file %s\n", fname);
 84		return -1;
 85	}
 86
 87	type = elf_parser.r2(&ehdr->e32.e_type);
 88	if (!((1 << type) & types)) {
 89		fprintf(stderr, "Invalid ELF type file %s\n", fname);
 90		return -1;
 91	}
 92
 93	switch (ehdr->e32.e_ident[EI_CLASS]) {
 94	case ELFCLASS32: {
 95		elf_parser.ehdr_shoff		= ehdr32_shoff;
 96		elf_parser.ehdr_shentsize	= ehdr32_shentsize;
 97		elf_parser.ehdr_shstrndx	= ehdr32_shstrndx;
 98		elf_parser.ehdr_shnum		= ehdr32_shnum;
 99		elf_parser.shdr_addr		= shdr32_addr;
100		elf_parser.shdr_offset		= shdr32_offset;
101		elf_parser.shdr_link		= shdr32_link;
102		elf_parser.shdr_size		= shdr32_size;
103		elf_parser.shdr_name		= shdr32_name;
104		elf_parser.shdr_type		= shdr32_type;
105		elf_parser.shdr_entsize		= shdr32_entsize;
106		elf_parser.sym_type		= sym32_type;
107		elf_parser.sym_name		= sym32_name;
108		elf_parser.sym_value		= sym32_value;
109		elf_parser.sym_shndx		= sym32_shndx;
110		elf_parser.rela_offset		= rela32_offset;
111		elf_parser.rela_info		= rela32_info;
112		elf_parser.rela_addend		= rela32_addend;
113		elf_parser.rela_write_addend	= rela32_write_addend;
114
115		if (elf_parser.r2(&ehdr->e32.e_ehsize) != sizeof(Elf32_Ehdr) ||
116		    elf_parser.r2(&ehdr->e32.e_shentsize) != sizeof(Elf32_Shdr)) {
117			fprintf(stderr,
118				"unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
119			return -1;
120		}
121
122		}
123		break;
124	case ELFCLASS64: {
125		elf_parser.ehdr_shoff		= ehdr64_shoff;
126		elf_parser.ehdr_shentsize		= ehdr64_shentsize;
127		elf_parser.ehdr_shstrndx		= ehdr64_shstrndx;
128		elf_parser.ehdr_shnum		= ehdr64_shnum;
129		elf_parser.shdr_addr		= shdr64_addr;
130		elf_parser.shdr_offset		= shdr64_offset;
131		elf_parser.shdr_link		= shdr64_link;
132		elf_parser.shdr_size		= shdr64_size;
133		elf_parser.shdr_name		= shdr64_name;
134		elf_parser.shdr_type		= shdr64_type;
135		elf_parser.shdr_entsize		= shdr64_entsize;
136		elf_parser.sym_type		= sym64_type;
137		elf_parser.sym_name		= sym64_name;
138		elf_parser.sym_value		= sym64_value;
139		elf_parser.sym_shndx		= sym64_shndx;
140		elf_parser.rela_offset		= rela64_offset;
141		elf_parser.rela_info		= rela64_info;
142		elf_parser.rela_addend		= rela64_addend;
143		elf_parser.rela_write_addend	= rela64_write_addend;
144
145		if (elf_parser.r2(&ehdr->e64.e_ehsize) != sizeof(Elf64_Ehdr) ||
146		    elf_parser.r2(&ehdr->e64.e_shentsize) != sizeof(Elf64_Shdr)) {
147			fprintf(stderr,
148				"unrecognized ET_EXEC/ET_DYN file: %s\n",
149				fname);
150			return -1;
151		}
152
153		}
154		break;
155	default:
156		fprintf(stderr, "unrecognized ELF class %d %s\n",
157			ehdr->e32.e_ident[EI_CLASS], fname);
158		return -1;
159	}
160	return 0;
161}
162
163int elf_map_machine(void *addr)
164{
165	Elf_Ehdr *ehdr = addr;
166
167	return elf_parser.r2(&ehdr->e32.e_machine);
168}
169
170int elf_map_long_size(void *addr)
171{
172	Elf_Ehdr *ehdr = addr;
173
174	return ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
175}
176
177void *elf_map(char const *fname, size_t *size, uint32_t types)
178{
179	void *addr;
180	int ret;
181
182	addr = map_file(fname, size);
183	if (!addr)
184		return NULL;
185
186	ret = elf_parse(fname, addr, types);
187	if (ret < 0) {
188		elf_unmap(addr, *size);
189		return NULL;
190	}
191
192	return addr;
193}
194
195void elf_unmap(void *addr, size_t size)
196{
197	munmap(addr, size);
198}
~/ Read-only file preview.