summaryrefslogtreecommitdiff
path: root/scripts/elf-parse.c
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-10-09 21:20:03 +0200
committerMark Brown <broonie@kernel.org>2026-10-09 21:20:03 +0200
commit42e6288df48dbec158b14d7ffaf170bd6febfd31 (patch)
tree5e03b05fdd02126d86df6568e1180a7420aeeb78 /scripts/elf-parse.c
parent7f1e046d644d54d477b0d1dc887e25b39551be18 (diff)
parent20cb500b2dfd87e055b2a494665121d0c7d20f76 (diff)
downloadlinux-next-42e6288df48dbec158b14d7ffaf170bd6febfd31.tar.gz
linux-next-42e6288df48dbec158b14d7ffaf170bd6febfd31.zip
Merge branch 'kbuild-for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git
# Conflicts: # init/Kconfig # scripts/kallsyms.c # scripts/remove-stale-files
Diffstat (limited to 'scripts/elf-parse.c')
-rw-r--r--scripts/elf-parse.c103
1 files changed, 90 insertions, 13 deletions
diff --git a/scripts/elf-parse.c b/scripts/elf-parse.c
index 99869ff91a8c..ce1c2a670244 100644
--- a/scripts/elf-parse.c
+++ b/scripts/elf-parse.c
@@ -17,15 +17,21 @@ struct elf_funcs elf_parser;
* Get the whole file as a programming convenience in order to avoid
* malloc+lseek+read+free of many pieces. If successful, then mmap
* avoids copying unused pieces; else just read the whole file.
- * Open for both read and write.
+ * Open for both read and write if writable is true, otherwise open
+ * read-only.
*/
-static void *map_file(char const *fname, size_t *size)
+static void *map_file(char const *fname, size_t *size, bool writable)
{
- int fd;
+ int fd, prot = PROT_READ, flags = MAP_PRIVATE;
struct stat sb;
void *addr = NULL;
- fd = open(fname, O_RDWR);
+ if (writable) {
+ prot |= PROT_WRITE;
+ flags = MAP_SHARED;
+ }
+
+ fd = open(fname, writable ? O_RDWR : O_RDONLY);
if (fd < 0) {
perror(fname);
return NULL;
@@ -39,7 +45,7 @@ static void *map_file(char const *fname, size_t *size)
goto out;
}
- addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ addr = mmap(0, sb.st_size, prot, flags, fd, 0);
if (addr == MAP_FAILED) {
fprintf(stderr, "Could not mmap file: %s\n", fname);
goto out;
@@ -57,6 +63,12 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
Elf_Ehdr *ehdr = addr;
uint16_t type;
+ if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
+ ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
+ fprintf(stderr, "unrecognized ELF file %s\n", fname);
+ return -1;
+ }
+
switch (ehdr->e32.e_ident[EI_DATA]) {
case ELFDATA2LSB:
elf_parser.r = rle;
@@ -78,12 +90,6 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
return -1;
}
- if (memcmp(ELFMAG, ehdr->e32.e_ident, SELFMAG) != 0 ||
- ehdr->e32.e_ident[EI_VERSION] != EV_CURRENT) {
- fprintf(stderr, "unrecognized ELF file %s\n", fname);
- return -1;
- }
-
type = elf_parser.r2(&ehdr->e32.e_type);
if (!((1 << type) & types)) {
fprintf(stderr, "Invalid ELF type file %s\n", fname);
@@ -103,7 +109,9 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
elf_parser.shdr_name = shdr32_name;
elf_parser.shdr_type = shdr32_type;
elf_parser.shdr_entsize = shdr32_entsize;
+ elf_parser.shdr_flags = shdr32_flags;
elf_parser.sym_type = sym32_type;
+ elf_parser.sym_bind = sym32_bind;
elf_parser.sym_name = sym32_name;
elf_parser.sym_value = sym32_value;
elf_parser.sym_shndx = sym32_shndx;
@@ -133,7 +141,9 @@ static int elf_parse(const char *fname, void *addr, uint32_t types)
elf_parser.shdr_name = shdr64_name;
elf_parser.shdr_type = shdr64_type;
elf_parser.shdr_entsize = shdr64_entsize;
+ elf_parser.shdr_flags = shdr64_flags;
elf_parser.sym_type = sym64_type;
+ elf_parser.sym_bind = sym64_bind;
elf_parser.sym_name = sym64_name;
elf_parser.sym_value = sym64_value;
elf_parser.sym_shndx = sym64_shndx;
@@ -174,12 +184,13 @@ int elf_map_long_size(void *addr)
return ehdr->e32.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
}
-void *elf_map(char const *fname, size_t *size, uint32_t types)
+static void *__elf_map(char const *fname, size_t *size, uint32_t types,
+ bool writable)
{
void *addr;
int ret;
- addr = map_file(fname, size);
+ addr = map_file(fname, size, writable);
if (!addr)
return NULL;
@@ -192,7 +203,73 @@ void *elf_map(char const *fname, size_t *size, uint32_t types)
return addr;
}
+void *elf_map(char const *fname, size_t *size, uint32_t types)
+{
+ return __elf_map(fname, size, types, true);
+}
+
+/* For tools that only read the file. */
+void *elf_map_ro(char const *fname, size_t *size, uint32_t types)
+{
+ return __elf_map(fname, size, types, false);
+}
+
void elf_unmap(void *addr, size_t size)
{
munmap(addr, size);
}
+
+/*
+ * Open an ELF file and map it read-only, locating its section headers, section
+ * names and symbol table which are populated in the elf out parameter.
+ *
+ * Returns 0 on success, otherwise -1.
+ */
+int elf_open_ro(char const *fname, uint32_t types, struct elf_file *elf)
+{
+ Elf_Ehdr *ehdr;
+ Elf_Shdr *first;
+ unsigned int shstrndx, i;
+
+ memset(elf, 0, sizeof(*elf));
+ elf->base = elf_map_ro(fname, &elf->size, types);
+ if (!elf->base)
+ return -1;
+
+ ehdr = elf->base;
+ elf->shdrs = (const char *)elf->base + ehdr_shoff(ehdr);
+ elf->shentsize = ehdr_shentsize(ehdr);
+ first = elf_section(elf, 0);
+
+ /* A count or index too large for the header lives in section 0. */
+ elf->shnum = ehdr_shnum(ehdr);
+ if (elf->shnum == SHN_UNDEF)
+ elf->shnum = shdr_size(first);
+ shstrndx = ehdr_shstrndx(ehdr);
+ if (shstrndx == SHN_XINDEX)
+ shstrndx = shdr_link(first);
+ elf->shstrtab = (const char *)elf->base +
+ shdr_offset(elf_section(elf, shstrndx));
+
+ for (i = 0; i < elf->shnum && !elf->symtab; i++)
+ if (shdr_type(elf_section(elf, i)) == SHT_SYMTAB)
+ elf->symtab = elf_section(elf, i);
+
+ if (!elf->symtab) {
+ fprintf(stderr, "%s: no symbol table\n", fname);
+ elf_close(elf);
+ return -1;
+ }
+
+ elf->strtab = (const char *)elf->base +
+ shdr_offset(elf_section(elf, shdr_link(elf->symtab)));
+ elf->nr_syms = shdr_size(elf->symtab) / shdr_entsize(elf->symtab);
+
+ return 0;
+}
+
+void elf_close(struct elf_file *elf)
+{
+ elf_unmap(elf->base, elf->size);
+ elf->base = NULL;
+}