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

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

Signed-off-by: Josh Poimboeuf <jpoim...@kernel.org>
---
 tools/objtool/elf.c                 | 118 ++++++++++++++++------------
 tools/objtool/include/objtool/elf.h |   7 +-
 tools/objtool/orc_gen.c             |   6 +-
 3 files changed, 77 insertions(+), 54 deletions(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 38bf9ae86c89..c38b109f441f 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -1136,51 +1136,53 @@ static int elf_add_string(struct elf *elf, struct 
section *strtab, const char *s
 }
 
 struct section *elf_create_section(struct elf *elf, const char *name,
-                                  size_t entsize, unsigned int nr)
+                                  size_t size, size_t entsize,
+                                  unsigned int type, unsigned int align,
+                                  unsigned int flags)
 {
        struct section *sec, *shstrtab;
-       size_t size = entsize * nr;
        Elf_Scn *s;
 
-       sec = malloc(sizeof(*sec));
-       if (!sec) {
-               ERROR_GLIBC("malloc");
+       if (name && find_section_by_name(elf, name)) {
+               ERROR("section '%s' already exists", name);
+               return NULL;
+       }
+
+       sec = calloc(1, sizeof(*sec));
+       if (!sec) {
+               ERROR_GLIBC("calloc");
                return NULL;
        }
-       memset(sec, 0, sizeof(*sec));
 
        INIT_LIST_HEAD(&sec->symbol_list);
 
+       /* don't actually create the section, just the data structures */
+       if (type == SHT_NULL)
+               goto add;
+
        s = elf_newscn(elf->elf);
        if (!s) {
                ERROR_ELF("elf_newscn");
                return NULL;
        }
 
-       sec->name = strdup(name);
-       if (!sec->name) {
-               ERROR_GLIBC("strdup");
-               return NULL;
-       }
-
        sec->idx = elf_ndxscn(s);
 
-       sec->data = elf_newdata(s);
-       if (!sec->data) {
-               ERROR_ELF("elf_newdata");
-               return NULL;
-       }
-
-       sec->data->d_size = size;
-       sec->data->d_align = 1;
-
        if (size) {
-               sec->data->d_buf = malloc(size);
-               if (!sec->data->d_buf) {
-                       ERROR_GLIBC("malloc");
+               sec->data = elf_newdata(s);
+               if (!sec->data) {
+                       ERROR_ELF("elf_newdata");
+                       return NULL;
+               }
+
+               sec->data->d_size = size;
+               sec->data->d_align = 1;
+
+               sec->data->d_buf = calloc(1, size);
+               if (!sec->data->d_buf) {
+                       ERROR_GLIBC("calloc");
                        return NULL;
                }
-               memset(sec->data->d_buf, 0, size);
        }
 
        if (!gelf_getshdr(s, &sec->sh)) {
@@ -1190,34 +1192,44 @@ struct section *elf_create_section(struct elf *elf, 
const char *name,
 
        sec->sh.sh_size = size;
        sec->sh.sh_entsize = entsize;
-       sec->sh.sh_type = SHT_PROGBITS;
-       sec->sh.sh_addralign = 1;
-       sec->sh.sh_flags = SHF_ALLOC;
+       sec->sh.sh_type = type;
+       sec->sh.sh_addralign = align;
+       sec->sh.sh_flags = flags;
 
-       /* Add section name to .shstrtab (or .strtab for Clang) */
-       shstrtab = find_section_by_name(elf, ".shstrtab");
-       if (!shstrtab)
-               shstrtab = find_section_by_name(elf, ".strtab");
-       if (!shstrtab) {
-               ERROR("can't find .shstrtab or .strtab section");
-               return NULL;
+       if (name) {
+               sec->name = strdup(name);
+               if (!sec->name) {
+                       ERROR("strdup");
+                       return NULL;
+               }
+
+               /* Add section name to .shstrtab (or .strtab for Clang) */
+               shstrtab = find_section_by_name(elf, ".shstrtab");
+               if (!shstrtab) {
+                       shstrtab = find_section_by_name(elf, ".strtab");
+                       if (!shstrtab) {
+                               ERROR("can't find .shstrtab or .strtab");
+                               return NULL;
+                       }
+               }
+               sec->sh.sh_name = elf_add_string(elf, shstrtab, sec->name);
+               if (sec->sh.sh_name == -1)
+                       return NULL;
+
+               elf_hash_add(section_name, &sec->name_hash, 
str_hash(sec->name));
        }
-       sec->sh.sh_name = elf_add_string(elf, shstrtab, sec->name);
-       if (sec->sh.sh_name == -1)
-               return NULL;
 
+add:
        list_add_tail(&sec->list, &elf->sections);
        elf_hash_add(section, &sec->hash, sec->idx);
-       elf_hash_add(section_name, &sec->name_hash, str_hash(sec->name));
 
        mark_sec_changed(elf, sec, true);
 
        return sec;
 }
 
-static struct section *elf_create_rela_section(struct elf *elf,
-                                              struct section *sec,
-                                              unsigned int reloc_nr)
+struct section *elf_create_rela_section(struct elf *elf, struct section *sec,
+                                       unsigned int reloc_nr)
 {
        struct section *rsec;
        char *rsec_name;
@@ -1230,22 +1242,23 @@ static struct section *elf_create_rela_section(struct 
elf *elf,
        strcpy(rsec_name, ".rela");
        strcat(rsec_name, sec->name);
 
-       rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), reloc_nr);
+       rsec = elf_create_section(elf, rsec_name, reloc_nr * elf_rela_size(elf),
+                                 elf_rela_size(elf), SHT_RELA, 
elf_addr_size(elf),
+                                 SHF_INFO_LINK);
        free(rsec_name);
        if (!rsec)
                return NULL;
 
-       rsec->data->d_type = ELF_T_RELA;
-       rsec->sh.sh_type = SHT_RELA;
-       rsec->sh.sh_addralign = elf_addr_size(elf);
        rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
        rsec->sh.sh_info = sec->idx;
-       rsec->sh.sh_flags = SHF_INFO_LINK;
 
-       rsec->relocs = calloc(sec_num_entries(rsec), sizeof(struct reloc));
-       if (!rsec->relocs) {
-               ERROR_GLIBC("calloc");
-               return NULL;
+       if (reloc_nr) {
+               rsec->data->d_type = ELF_T_RELA;
+               rsec->relocs = calloc(sec_num_entries(rsec), sizeof(struct 
reloc));
+               if (!rsec->relocs) {
+                       ERROR_GLIBC("calloc");
+                       return NULL;
+               }
        }
 
        sec->rsec = rsec;
@@ -1260,7 +1273,8 @@ struct section *elf_create_section_pair(struct elf *elf, 
const char *name,
 {
        struct section *sec;
 
-       sec = elf_create_section(elf, name, entsize, nr);
+       sec = elf_create_section(elf, name, nr * entsize, entsize,
+                                SHT_PROGBITS, 1, SHF_ALLOC);
        if (!sec)
                return NULL;
 
diff --git a/tools/objtool/include/objtool/elf.h 
b/tools/objtool/include/objtool/elf.h
index ffdf9ec3882e..b366516b119d 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -116,11 +116,16 @@ struct elf {
 struct elf *elf_open_read(const char *name, int flags);
 
 struct section *elf_create_section(struct elf *elf, const char *name,
-                                  size_t entsize, unsigned int nr);
+                                  size_t size, size_t entsize,
+                                  unsigned int type, unsigned int align,
+                                  unsigned int flags);
 struct section *elf_create_section_pair(struct elf *elf, const char *name,
                                        size_t entsize, unsigned int nr,
                                        unsigned int reloc_nr);
 
+struct section *elf_create_rela_section(struct elf *elf, struct section *sec,
+                                       unsigned int reloc_nr);
+
 struct symbol *elf_create_symbol(struct elf *elf, const char *name,
                                 struct section *sec, unsigned int bind,
                                 unsigned int type, unsigned long offset,
diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c
index 6eff3d6a125c..9d380abc2ed3 100644
--- a/tools/objtool/orc_gen.c
+++ b/tools/objtool/orc_gen.c
@@ -127,7 +127,11 @@ int orc_create(struct objtool_file *file)
                return -1;
        }
        orc_sec = elf_create_section(file->elf, ".orc_unwind",
-                                    sizeof(struct orc_entry), nr);
+                                    nr * sizeof(struct orc_entry),
+                                    sizeof(struct orc_entry),
+                                    SHT_PROGBITS,
+                                    1,
+                                    SHF_ALLOC);
        if (!orc_sec)
                return -1;
 
-- 
2.49.0


Reply via email to