In preparation for the objtool klp diff subcommand, broaden the
elf_create_symbol() interface to give callers more control and reduce
duplication of some subtle setup logic.

While at it, make elf_create_symbol() and elf_create_section_symbol()
public so sections can be created by the upcoming klp diff code.

Signed-off-by: Josh Poimboeuf <jpoim...@kernel.org>
---
 tools/objtool/elf.c                 | 111 +++++++++++++++-------------
 tools/objtool/include/objtool/elf.h |  11 ++-
 2 files changed, 69 insertions(+), 53 deletions(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 859d677e172c..38bf9ae86c89 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -761,24 +761,60 @@ static int elf_update_symbol(struct elf *elf, struct 
section *symtab,
        return 0;
 }
 
-static struct symbol *
-__elf_create_symbol(struct elf *elf, struct symbol *sym)
+static int elf_add_string(struct elf *elf, struct section *strtab, const char 
*str);
+
+struct symbol *elf_create_symbol(struct elf *elf, const char *name,
+                                struct section *sec, unsigned int bind,
+                                unsigned int type, unsigned long offset,
+                                size_t size)
 {
        struct section *symtab, *symtab_shndx;
        Elf32_Word first_non_local, new_idx;
-       struct symbol *old;
+       struct symbol *old, *sym;
+
+       sym = calloc(1, sizeof(*sym));
+       if (!sym) {
+               ERROR_GLIBC("calloc");
+               return NULL;
+       }
+
+       sym->name = strdup(name);
+       if (!sym->name) {
+               ERROR_GLIBC("strdup");
+               return NULL;
+       }
+
+       if (type != STT_SECTION) {
+               sym->sym.st_name = elf_add_string(elf, NULL, sym->name);
+               if (sym->sym.st_name == -1)
+                       return NULL;
+       }
+
+       if (sec) {
+               sym->sec = sec;
+       } else {
+               sym->sec = find_section_by_index(elf, 0);
+               if (!sym->sec) {
+                       ERROR("no NULL section");
+                       return NULL;
+               }
+       }
+
+       sym->sym.st_info  = GELF_ST_INFO(bind, type);
+       sym->sym.st_value = offset;
+       sym->sym.st_size  = size;
 
        symtab = find_section_by_name(elf, ".symtab");
-       if (symtab) {
-               symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
-       } else {
+       if (!symtab) {
                ERROR("no .symtab");
                return NULL;
        }
 
+       symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
+
        new_idx = sec_num_entries(symtab);
 
-       if (GELF_ST_BIND(sym->sym.st_info) != STB_LOCAL)
+       if (bind != STB_LOCAL)
                goto non_local;
 
        /*
@@ -816,10 +852,8 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym)
 
 non_local:
        sym->idx = new_idx;
-       if (elf_update_symbol(elf, symtab, symtab_shndx, sym)) {
-               ERROR("elf_update_symbol");
+       if (sym->idx && elf_update_symbol(elf, symtab, symtab_shndx, sym))
                return NULL;
-       }
 
        symtab->sh.sh_size += symtab->sh.sh_entsize;
        mark_sec_changed(elf, symtab, true);
@@ -829,64 +863,39 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym)
                mark_sec_changed(elf, symtab_shndx, true);
        }
 
+       elf_add_symbol(elf, sym);
+
        return sym;
 }
 
-static struct symbol *
-elf_create_section_symbol(struct elf *elf, struct section *sec)
+struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec)
 {
        struct symbol *sym = calloc(1, sizeof(*sym));
 
-       if (!sym) {
-               ERROR_GLIBC("malloc");
+       sym = elf_create_symbol(elf, sec->name, sec, STB_LOCAL, STT_SECTION, 0, 
0);
+       if (!sym)
                return NULL;
-       }
 
-       sym->name = sec->name;
-       sym->sec = sec;
-
-       // st_name 0
-       sym->sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION);
-       // st_other 0
-       // st_value 0
-       // st_size 0
-
-       sym = __elf_create_symbol(elf, sym);
-       if (sym)
-               elf_add_symbol(elf, sym);
+       sec->sym = sym;
 
        return sym;
 }
 
-static int elf_add_string(struct elf *elf, struct section *strtab, const char 
*str);
-
 struct symbol *
-elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size)
+elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, size_t size)
 {
-       struct symbol *sym = calloc(1, sizeof(*sym));
        size_t namelen = strlen(orig->name) + sizeof("__pfx_");
-       char *name = malloc(namelen);
-
-       if (!sym || !name) {
-               ERROR_GLIBC("malloc");
-               return NULL;
-       }
+       char name[SYM_NAME_LEN];
+       unsigned long offset;
 
        snprintf(name, namelen, "__pfx_%s", orig->name);
 
-       sym->name = name;
-       sym->sec = orig->sec;
+       offset = orig->sym.st_value - size;
 
-       sym->sym.st_name = elf_add_string(elf, NULL, name);
-       sym->sym.st_info = orig->sym.st_info;
-       sym->sym.st_value = orig->sym.st_value - size;
-       sym->sym.st_size = size;
-
-       sym = __elf_create_symbol(elf, sym);
-       if (sym)
-               elf_add_symbol(elf, sym);
-
-       return sym;
+       return elf_create_symbol(elf, name, orig->sec,
+                                GELF_ST_BIND(orig->sym.st_info),
+                                GELF_ST_TYPE(orig->sym.st_info),
+                                offset, size);
 }
 
 static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
@@ -932,7 +941,7 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, 
struct section *sec,
                                      unsigned long insn_off)
 {
        struct symbol *sym = insn_sec->sym;
-       int addend = insn_off;
+       s64 addend = insn_off;
 
        if (!is_text_sec(insn_sec)) {
                ERROR("bad call to %s() for data symbol %s", __func__, 
sym->name);
@@ -949,8 +958,6 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, 
struct section *sec,
                sym = elf_create_section_symbol(elf, insn_sec);
                if (!sym)
                        return NULL;
-
-               insn_sec->sym = sym;
        }
 
        return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend,
diff --git a/tools/objtool/include/objtool/elf.h 
b/tools/objtool/include/objtool/elf.h
index 74c7b84b5310..ffdf9ec3882e 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -15,6 +15,8 @@
 #include <linux/jhash.h>
 #include <arch/elf.h>
 
+#define SYM_NAME_LEN           512
+
 #ifdef LIBELF_USE_DEPRECATED
 # define elf_getshdrnum    elf_getshnum
 # define elf_getshdrstrndx elf_getshstrndx
@@ -119,7 +121,14 @@ struct section *elf_create_section_pair(struct elf *elf, 
const char *name,
                                        size_t entsize, unsigned int nr,
                                        unsigned int reloc_nr);
 
-struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, 
long size);
+struct symbol *elf_create_symbol(struct elf *elf, const char *name,
+                                struct section *sec, unsigned int bind,
+                                unsigned int type, unsigned long offset,
+                                size_t size);
+struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec);
+struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig,
+                                       size_t size);
+
 
 struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
                                      unsigned long offset,
-- 
2.49.0


Reply via email to