git: 72e15f76a1b3 - main - libkldelf: add see_local parameter to elf_lookup_symbol

From: Ka Ho Ng <khng_at_FreeBSD.org>
Date: Fri, 25 Oct 2024 16:20:18 UTC
The branch main has been updated by khng:

URL: https://cgit.FreeBSD.org/src/commit/?id=72e15f76a1b3e7bddb5fa1b0429e41d07950af65

commit 72e15f76a1b3e7bddb5fa1b0429e41d07950af65
Author:     Ka Ho Ng <khng@FreeBSD.org>
AuthorDate: 2024-10-25 16:19:57 +0000
Commit:     Ka Ho Ng <khng@FreeBSD.org>
CommitDate: 2024-10-25 16:20:16 +0000

    libkldelf: add see_local parameter to elf_lookup_symbol
    
    This gives the function the ability to return only global symbols.
    
    Sponsored by:   Juniper Networks, Inc.
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D47206
---
 lib/libkldelf/ef.c     | 15 +++++++++------
 lib/libkldelf/ef_obj.c | 12 ++++++++----
 lib/libkldelf/elf.c    |  5 +++--
 lib/libkldelf/kldelf.h | 11 +++++------
 4 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/lib/libkldelf/ef.c b/lib/libkldelf/ef.c
index dcd87fe2bf83..28576df99bf2 100644
--- a/lib/libkldelf/ef.c
+++ b/lib/libkldelf/ef.c
@@ -81,7 +81,7 @@ static GElf_Addr ef_symaddr(elf_file_t ef, GElf_Size symidx);
 static int	ef_lookup_set(elf_file_t ef, const char *name,
 		    GElf_Addr *startp, GElf_Addr *stopp, long *countp);
 static int	ef_lookup_symbol(elf_file_t ef, const char *name,
-		    GElf_Sym **sym);
+		    GElf_Sym **sym, bool see_local);
 
 static struct elf_file_ops ef_file_ops = {
 	.close			= ef_close,
@@ -126,7 +126,7 @@ ef_get_offset(elf_file_t ef, GElf_Addr addr)
  * next two functions copied from link_elf.c
  */
 static int
-ef_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym)
+ef_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym, bool see_local)
 {
 	unsigned long hash, symnum;
 	GElf_Sym *symp;
@@ -156,8 +156,11 @@ ef_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym)
 			if (symp->st_shndx != SHN_UNDEF ||
 			    (symp->st_value != 0 &&
 				GELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
-				*sym = symp;
-				return (0);
+				if (see_local ||
+				    GELF_ST_BIND(symp->st_info) != STB_LOCAL) {
+					*sym = symp;
+					return (0);
+				}
 			} else
 				return (ENOENT);
 		}
@@ -183,14 +186,14 @@ ef_lookup_set(elf_file_t ef, const char *name, GElf_Addr *startp,
 
 	/* get address of first entry */
 	snprintf(setsym, len, "%s%s", "__start_set_", name);
-	error = ef_lookup_symbol(ef, setsym, &sym);
+	error = ef_lookup_symbol(ef, setsym, &sym, true);
 	if (error != 0)
 		goto out;
 	*startp = sym->st_value;
 
 	/* get address of last entry */
 	snprintf(setsym, len, "%s%s", "__stop_set_", name);
-	error = ef_lookup_symbol(ef, setsym, &sym);
+	error = ef_lookup_symbol(ef, setsym, &sym, true);
 	if (error != 0)
 		goto out;
 	*stopp = sym->st_value;
diff --git a/lib/libkldelf/ef_obj.c b/lib/libkldelf/ef_obj.c
index 30e0d7886995..151bac74b17d 100644
--- a/lib/libkldelf/ef_obj.c
+++ b/lib/libkldelf/ef_obj.c
@@ -101,7 +101,7 @@ static GElf_Addr ef_obj_symaddr(elf_file_t ef, GElf_Size symidx);
 static int	ef_obj_lookup_set(elf_file_t ef, const char *name,
 		    GElf_Addr *startp, GElf_Addr *stopp, long *countp);
 static int	ef_obj_lookup_symbol(elf_file_t ef, const char *name,
-		    GElf_Sym **sym);
+		    GElf_Sym **sym, bool see_local);
 
 static struct elf_file_ops ef_obj_file_ops = {
 	.close			= ef_obj_close,
@@ -129,7 +129,8 @@ ef_obj_get_offset(elf_file_t ef, GElf_Addr addr)
 }
 
 static int
-ef_obj_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym)
+ef_obj_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym,
+    bool see_local)
 {
 	GElf_Sym *symp;
 	const char *strp;
@@ -138,8 +139,11 @@ ef_obj_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym)
 	for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
 		strp = ef->ddbstrtab + symp->st_name;
 		if (symp->st_shndx != SHN_UNDEF && strcmp(name, strp) == 0) {
-			*sym = symp;
-			return (0);
+			if (see_local ||
+			    GELF_ST_BIND(symp->st_info) != STB_LOCAL) {
+				*sym = symp;
+				return (0);
+			}
 		}
 	}
 	return (ENOENT);
diff --git a/lib/libkldelf/elf.c b/lib/libkldelf/elf.c
index 8af02622de13..cf43d9bfd5fd 100644
--- a/lib/libkldelf/elf.c
+++ b/lib/libkldelf/elf.c
@@ -688,7 +688,8 @@ elf_reloc(struct elf_file *efile, const void *reldata, Elf_Type reltype,
 }
 
 int
-elf_lookup_symbol(struct elf_file *efile, const char *name, GElf_Sym **sym)
+elf_lookup_symbol(struct elf_file *efile, const char *name, GElf_Sym **sym,
+    bool see_local)
 {
-	return (EF_LOOKUP_SYMBOL(efile, name, sym));
+	return (EF_LOOKUP_SYMBOL(efile, name, sym, see_local));
 }
diff --git a/lib/libkldelf/kldelf.h b/lib/libkldelf/kldelf.h
index 71de31a94291..4fb5fcc5f5aa 100644
--- a/lib/libkldelf/kldelf.h
+++ b/lib/libkldelf/kldelf.h
@@ -48,8 +48,8 @@
     (ef)->ef_ops->symaddr((ef)->ef_ef, symidx)
 #define EF_LOOKUP_SET(ef, name, startp, stopp, countp) \
     (ef)->ef_ops->lookup_set((ef)->ef_ef, name, startp, stopp, countp)
-#define EF_LOOKUP_SYMBOL(ef, name, sym) \
-    (ef)->ef_ops->lookup_symbol((ef)->ef_ef, name, sym)
+#define EF_LOOKUP_SYMBOL(ef, name, sym, see_local) \
+    (ef)->ef_ops->lookup_symbol((ef)->ef_ef, name, sym, see_local)
 
 /* XXX, should have a different name. */
 typedef struct ef_file *elf_file_t;
@@ -69,7 +69,8 @@ struct elf_file_ops {
 	GElf_Addr (*symaddr)(elf_file_t ef, GElf_Size symidx);
 	int (*lookup_set)(elf_file_t ef, const char *name, GElf_Addr *startp,
 	    GElf_Addr *stopp, long *countp);
-	int (*lookup_symbol)(elf_file_t ef, const char *name, GElf_Sym **sym);
+	int (*lookup_symbol)(elf_file_t ef, const char *name, GElf_Sym **sym,
+	    bool see_local);
 };
 
 typedef int (elf_reloc_t)(struct elf_file *ef, const void *reldata,
@@ -317,11 +318,9 @@ int	elf_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype,
  * Find the symbol with the specified symbol name 'name' within the given
  * 'efile'. 0 is returned when such a symbol is found, otherwise ENOENT is
  * returned.
- *
- * XXX: This only return the first symbol being found when traversing symtab.
  */
 int	elf_lookup_symbol(struct elf_file *efile, const char *name,
-    GElf_Sym **sym);
+    GElf_Sym **sym, bool see_local);
 
 __END_DECLS