The branch stable/13 has been updated by jhb:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=21dec6c48f089ce55ec32fa04a8962ea52b3d9ef

commit 21dec6c48f089ce55ec32fa04a8962ea52b3d9ef
Author:     John Baldwin <[email protected]>
AuthorDate: 2023-12-22 15:49:18 +0000
Commit:     John Baldwin <[email protected]>
CommitDate: 2024-01-18 21:31:32 +0000

    kldxref: Simplify handling of ELF object files
    
    Unlike the backend for ELF DSOs, the object file backend allocated an
    aligned chunk of memory and read all of the in-memory sections from
    the file into this memory even though most of the file contents were
    never used.  Instead, just track a set of virtual addresses (based at
    0) that each loaded section would be loaded at and only read the
    necessary bits from the backing file when needed.
    
    Reviewed by:    imp
    Sponsored by:   DARPA
    Differential Revision:  https://reviews.freebsd.org/D43126
    
    (cherry picked from commit 0d557cdf6f0e94e909acea065f3de2a28437ae74)
---
 usr.sbin/kldxref/ef_obj.c | 146 +++++++++++++++++++++-------------------------
 1 file changed, 65 insertions(+), 81 deletions(-)

diff --git a/usr.sbin/kldxref/ef_obj.c b/usr.sbin/kldxref/ef_obj.c
index 36c0dce432b6..1274a14c10af 100644
--- a/usr.sbin/kldxref/ef_obj.c
+++ b/usr.sbin/kldxref/ef_obj.c
@@ -46,7 +46,8 @@
 #include "ef.h"
 
 typedef struct {
-       char            *addr;
+       GElf_Addr       addr;
+       GElf_Off        offset;
        GElf_Off        size;
        int             flags;
        int             sec;    /* Original section */
@@ -69,9 +70,6 @@ struct ef_file {
        char            *ef_name;
        struct elf_file *ef_efile;
 
-       char            *address;
-       GElf_Off        size;
-
        Elf_progent     *progtab;
        int             nprogtab;
 
@@ -113,6 +111,22 @@ static struct elf_file_ops ef_obj_file_ops = {
        .lookup_set             = ef_obj_lookup_set,
 };
 
+static GElf_Off
+ef_obj_get_offset(elf_file_t ef, GElf_Addr addr)
+{
+       Elf_progent *pt;
+       int i;
+
+       for (i = 0; i < ef->nprogtab; i++) {
+               pt = &ef->progtab[i];
+               if (pt->offset == (GElf_Off)-1)
+                       continue;
+               if (addr >= pt->addr && addr < pt->addr + pt->size)
+                       return (pt->offset + (addr - pt->addr));
+       }
+       return (0);
+}
+
 static int
 ef_obj_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym)
 {
@@ -139,9 +153,8 @@ ef_obj_lookup_set(elf_file_t ef, const char *name, 
GElf_Addr *startp,
        for (i = 0; i < ef->nprogtab; i++) {
                if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) &&
                    strcmp(ef->progtab[i].name + 4, name) == 0) {
-                       *startp = ef->progtab[i].addr - ef->address;
-                       *stopp = ef->progtab[i].addr + ef->progtab[i].size -
-                           ef->address;
+                       *startp = ef->progtab[i].addr;
+                       *stopp = ef->progtab[i].addr + ef->progtab[i].size;
                        *countp = (*stopp - *startp) /
                            elf_pointer_size(ef->ef_efile);
                        return (0);
@@ -160,46 +173,50 @@ ef_obj_symaddr(elf_file_t ef, GElf_Size symidx)
        sym = ef->ddbsymtab + symidx;
 
        if (sym->st_shndx != SHN_UNDEF)
-               return (sym->st_value - (GElf_Addr)ef->address);
+               return (sym->st_value);
        return (0);
 }
 
 static int
 ef_obj_seg_read_rel(elf_file_t ef, GElf_Addr address, size_t len, void *dest)
 {
-       char *memaddr;
+       GElf_Off secofs;
        GElf_Rel *r;
        GElf_Rela *a;
        GElf_Addr secbase, dataoff;
        int error, i, sec;
 
-       if (address + len > ef->size) {
-               if (ef->ef_verbose)
-                       warnx("ef_obj_seg_read_rel(%s): bad offset/len 
(%lx:%ld)",
-                           ef->ef_name, (long)address, (long)len);
-               return (EFAULT);
-       }
-       bcopy(ef->address + address, dest, len);
-
        /* Find out which section contains the data. */
-       memaddr = ef->address + address;
        sec = -1;
-       secbase = dataoff = 0;
        for (i = 0; i < ef->nprogtab; i++) {
-               if (ef->progtab[i].addr == NULL)
+               if (address < ef->progtab[i].addr)
                        continue;
-               if (memaddr < (char *)ef->progtab[i].addr || memaddr + len >
-                    (char *)ef->progtab[i].addr + ef->progtab[i].size)
+
+               dataoff = address - ef->progtab[i].addr;
+               if (dataoff + len > ef->progtab[i].size)
                        continue;
+
                sec = ef->progtab[i].sec;
-               /* We relocate to address 0. */
-               secbase = (char *)ef->progtab[i].addr - ef->address;
-               dataoff = memaddr - ef->address;
+               secbase = ef->progtab[i].addr;
+               secofs = ef->progtab[i].offset;
                break;
        }
 
-       if (sec == -1)
+       if (sec == -1) {
+               if (ef->ef_verbose)
+                       warnx("ef_obj_seg_read_rel(%s): bad address (%jx)",
+                           ef->ef_name, (uintmax_t)address);
                return (EFAULT);
+       }
+
+       if (secofs == (GElf_Off)-1) {
+               memset(dest, 0, len);
+       } else {
+               error = elf_read_raw_data(ef->ef_efile, secofs + dataoff, dest,
+                   len);
+               if (error != 0)
+                       return (error);
+       }
 
        /* Now do the relocations. */
        for (i = 0; i < ef->nrel; i++) {
@@ -208,7 +225,7 @@ ef_obj_seg_read_rel(elf_file_t ef, GElf_Addr address, 
size_t len, void *dest)
                for (r = ef->reltab[i].rel;
                     r < &ef->reltab[i].rel[ef->reltab[i].nrel]; r++) {
                        error = elf_reloc(ef->ef_efile, r, ELF_T_REL, secbase,
-                           dataoff, len, dest);
+                           address, len, dest);
                        if (error != 0)
                                return (error);
                }
@@ -219,7 +236,7 @@ ef_obj_seg_read_rel(elf_file_t ef, GElf_Addr address, 
size_t len, void *dest)
                for (a = ef->relatab[i].rela;
                     a < &ef->relatab[i].rela[ef->relatab[i].nrela]; a++) {
                        error = elf_reloc(ef->ef_efile, a, ELF_T_RELA, secbase,
-                           dataoff, len, dest);
+                           address, len, dest);
                        if (error != 0)
                                return (error);
                }
@@ -230,21 +247,23 @@ ef_obj_seg_read_rel(elf_file_t ef, GElf_Addr address, 
size_t len, void *dest)
 static int
 ef_obj_seg_read_string(elf_file_t ef, GElf_Addr address, size_t len, char 
*dest)
 {
+       GElf_Off ofs;
+       int error;
 
-       if (address >= ef->size) {
+       ofs = ef_obj_get_offset(ef, address);
+       if (ofs == 0) {
                if (ef->ef_verbose)
-                       warnx("ef_obj_seg_read_string(%s): bad address (%lx)",
-                           ef->ef_name, (long)address);
+                       warnx("ef_obj_seg_read_string(%s): bad address (%jx)",
+                           ef->ef_name, (uintmax_t)address);
                return (EFAULT);
        }
 
-       if (ef->size - address < len)
-               len = ef->size - address;
-
-       if (strnlen(ef->address + address, len) == len)
+       error = elf_read_raw_data(ef->ef_efile, ofs, dest, len);
+       if (error != 0)
+               return (error);
+       if (strnlen(dest, len) == len)
                return (EFAULT);
 
-       memcpy(dest, ef->address + address, len);
        return (0);
 }
 
@@ -255,8 +274,8 @@ ef_obj_open(struct elf_file *efile, int verbose)
        GElf_Ehdr *hdr;
        GElf_Shdr *shdr;
        GElf_Sym *es;
-       char *mapbase;
-       size_t i, mapsize, alignmask, max_addralign, nshdr;
+       GElf_Addr mapbase;
+       size_t i, nshdr;
        int error, pb, ra, rl;
        int j, nsym, symstrindex, symtabindex;
 
@@ -359,59 +378,26 @@ ef_obj_open(struct elf_file *efile, int verbose)
                }
        }
 
-       /* Size up code/data(progbits) and bss(nobits). */
-       alignmask = 0;
-       max_addralign = 0;
-       mapsize = 0;
-       for (i = 0; i < nshdr; i++) {
-               switch (shdr[i].sh_type) {
-               case SHT_PROGBITS:
-               case SHT_NOBITS:
-                       alignmask = shdr[i].sh_addralign - 1;
-                       if (shdr[i].sh_addralign > max_addralign)
-                               max_addralign = shdr[i].sh_addralign;
-                       mapsize += alignmask;
-                       mapsize &= ~alignmask;
-                       mapsize += shdr[i].sh_size;
-                       break;
-               }
-       }
-
-       /* We know how much space we need for the text/data/bss/etc. */
-       ef->size = mapsize;
-       if (posix_memalign((void **)&ef->address, max_addralign, mapsize)) {
-               printf("posix_memalign failed\n");
-               goto out;
-       }
-       mapbase = ef->address;
-
        /*
-        * Now load code/data(progbits), zero bss(nobits), allocate
-        * space for and load relocs
+        * Now allocate address space for code/data(progbits) and
+        * bss(nobits) and allocate space for and load relocs.
         */
        pb = 0;
        rl = 0;
        ra = 0;
-       alignmask = 0;
+       mapbase = 0;
        for (i = 0; i < nshdr; i++) {
                switch (shdr[i].sh_type) {
                case SHT_PROGBITS:
                case SHT_NOBITS:
-                       alignmask = shdr[i].sh_addralign - 1;
-                       mapbase += alignmask;
-                       mapbase = (char *)((uintptr_t)mapbase & ~alignmask);
-                       ef->progtab[pb].addr = (void *)(uintptr_t)mapbase;
+                       mapbase = roundup2(mapbase, shdr[i].sh_addralign);
+                       ef->progtab[pb].addr = mapbase;
                        if (shdr[i].sh_type == SHT_PROGBITS) {
                                ef->progtab[pb].name = "<<PROGBITS>>";
-                               if (elf_read_raw_data(efile,
-                                   shdr[i].sh_offset, ef->progtab[pb].addr,
-                                   shdr[i].sh_size) != 0) {
-                                       printf("failed to read progbits\n");
-                                       goto out;
-                               }
+                               ef->progtab[pb].offset = shdr[i].sh_offset;
                        } else {
                                ef->progtab[pb].name = "<<NOBITS>>";
-                               bzero(ef->progtab[pb].addr, shdr[i].sh_size);
+                               ef->progtab[pb].offset = (GElf_Off)-1;
                        }
                        ef->progtab[pb].size = shdr[i].sh_size;
                        ef->progtab[pb].sec = i;
@@ -424,7 +410,7 @@ ef_obj_open(struct elf_file *efile, int verbose)
                                es = &ef->ddbsymtab[j];
                                if (es->st_shndx != i)
                                        continue;
-                               es->st_value += (GElf_Addr)ef->progtab[pb].addr;
+                               es->st_value += ef->progtab[pb].addr;
                        }
                        mapbase += shdr[i].sh_size;
                        pb++;
@@ -464,8 +450,6 @@ ef_obj_close(elf_file_t ef)
 
        if (ef->ef_name)
                free(ef->ef_name);
-       if (ef->size != 0)
-               free(ef->address);
        if (ef->nprogtab != 0)
                free(ef->progtab);
        if (ef->nrel != 0) {

Reply via email to