libbpf: Pull file-opening logic up to top-level functions

Move the filename arguments and file-descriptor handling from
init_output_elf() and linker_load_obj_file() and instead handle them
at the top-level in bpf_linker__new() and bpf_linker__add_file().

This will allow the inner functions to be shared with a new,
non-filename-based, API in the next commit.

Signed-off-by: Alastair Robertson <ajor@meta.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20241211164030.573042-2-ajor@meta.com
This commit is contained in:
Alastair Robertson
2024-12-11 08:40:29 -08:00
committed by Andrii Nakryiko
parent 984dcc97ae
commit f00fad0951

View File

@@ -157,10 +157,9 @@ struct bpf_linker {
#define pr_warn_elf(fmt, ...) \ #define pr_warn_elf(fmt, ...) \
libbpf_print(LIBBPF_WARN, "libbpf: " fmt ": %s\n", ##__VA_ARGS__, elf_errmsg(-1)) libbpf_print(LIBBPF_WARN, "libbpf: " fmt ": %s\n", ##__VA_ARGS__, elf_errmsg(-1))
static int init_output_elf(struct bpf_linker *linker, const char *file); static int init_output_elf(struct bpf_linker *linker);
static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, static int linker_load_obj_file(struct bpf_linker *linker,
const struct bpf_linker_file_opts *opts,
struct src_obj *obj); struct src_obj *obj);
static int linker_sanity_check_elf(struct src_obj *obj); static int linker_sanity_check_elf(struct src_obj *obj);
static int linker_sanity_check_elf_symtab(struct src_obj *obj, struct src_sec *sec); static int linker_sanity_check_elf_symtab(struct src_obj *obj, struct src_sec *sec);
@@ -233,9 +232,20 @@ struct bpf_linker *bpf_linker__new(const char *filename, struct bpf_linker_opts
if (!linker) if (!linker)
return errno = ENOMEM, NULL; return errno = ENOMEM, NULL;
linker->fd = -1; linker->filename = strdup(filename);
if (!linker->filename) {
err = -ENOMEM;
goto err_out;
}
err = init_output_elf(linker, filename); linker->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (linker->fd < 0) {
err = -errno;
pr_warn("failed to create '%s': %d\n", filename, err);
goto err_out;
}
err = init_output_elf(linker);
if (err) if (err)
goto err_out; goto err_out;
@@ -294,23 +304,12 @@ static Elf64_Sym *add_new_sym(struct bpf_linker *linker, size_t *sym_idx)
return sym; return sym;
} }
static int init_output_elf(struct bpf_linker *linker, const char *file) static int init_output_elf(struct bpf_linker *linker)
{ {
int err, str_off; int err, str_off;
Elf64_Sym *init_sym; Elf64_Sym *init_sym;
struct dst_sec *sec; struct dst_sec *sec;
linker->filename = strdup(file);
if (!linker->filename)
return -ENOMEM;
linker->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (linker->fd < 0) {
err = -errno;
pr_warn("failed to create '%s': %s\n", file, errstr(err));
return err;
}
linker->elf = elf_begin(linker->fd, ELF_C_WRITE, NULL); linker->elf = elf_begin(linker->fd, ELF_C_WRITE, NULL);
if (!linker->elf) { if (!linker->elf) {
pr_warn_elf("failed to create ELF object"); pr_warn_elf("failed to create ELF object");
@@ -440,7 +439,7 @@ int bpf_linker__add_file(struct bpf_linker *linker, const char *filename,
const struct bpf_linker_file_opts *opts) const struct bpf_linker_file_opts *opts)
{ {
struct src_obj obj = {}; struct src_obj obj = {};
int err = 0; int err = 0, fd;
if (!OPTS_VALID(opts, bpf_linker_file_opts)) if (!OPTS_VALID(opts, bpf_linker_file_opts))
return libbpf_err(-EINVAL); return libbpf_err(-EINVAL);
@@ -448,7 +447,17 @@ int bpf_linker__add_file(struct bpf_linker *linker, const char *filename,
if (!linker->elf) if (!linker->elf)
return libbpf_err(-EINVAL); return libbpf_err(-EINVAL);
err = err ?: linker_load_obj_file(linker, filename, opts, &obj); fd = open(filename, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
err = -errno;
pr_warn("failed to open file '%s': %s\n", filename, errstr(err));
return libbpf_err(err);
}
obj.filename = filename;
obj.fd = fd;
err = err ?: linker_load_obj_file(linker, &obj);
err = err ?: linker_append_sec_data(linker, &obj); err = err ?: linker_append_sec_data(linker, &obj);
err = err ?: linker_append_elf_syms(linker, &obj); err = err ?: linker_append_elf_syms(linker, &obj);
err = err ?: linker_append_elf_relos(linker, &obj); err = err ?: linker_append_elf_relos(linker, &obj);
@@ -534,8 +543,7 @@ static struct src_sec *add_src_sec(struct src_obj *obj, const char *sec_name)
return sec; return sec;
} }
static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, static int linker_load_obj_file(struct bpf_linker *linker,
const struct bpf_linker_file_opts *opts,
struct src_obj *obj) struct src_obj *obj)
{ {
int err = 0; int err = 0;
@@ -554,26 +562,18 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
#error "Unknown __BYTE_ORDER__" #error "Unknown __BYTE_ORDER__"
#endif #endif
pr_debug("linker: adding object file '%s'...\n", filename); pr_debug("linker: adding object file '%s'...\n", obj->filename);
obj->filename = filename;
obj->fd = open(filename, O_RDONLY | O_CLOEXEC);
if (obj->fd < 0) {
err = -errno;
pr_warn("failed to open file '%s': %s\n", filename, errstr(err));
return err;
}
obj->elf = elf_begin(obj->fd, ELF_C_READ_MMAP, NULL); obj->elf = elf_begin(obj->fd, ELF_C_READ_MMAP, NULL);
if (!obj->elf) { if (!obj->elf) {
pr_warn_elf("failed to parse ELF file '%s'", filename); pr_warn_elf("failed to parse ELF file '%s'", obj->filename);
return -EINVAL; return -EINVAL;
} }
/* Sanity check ELF file high-level properties */ /* Sanity check ELF file high-level properties */
ehdr = elf64_getehdr(obj->elf); ehdr = elf64_getehdr(obj->elf);
if (!ehdr) { if (!ehdr) {
pr_warn_elf("failed to get ELF header for %s", filename); pr_warn_elf("failed to get ELF header for %s", obj->filename);
return -EINVAL; return -EINVAL;
} }
@@ -581,7 +581,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
obj_byteorder = ehdr->e_ident[EI_DATA]; obj_byteorder = ehdr->e_ident[EI_DATA];
if (obj_byteorder != ELFDATA2LSB && obj_byteorder != ELFDATA2MSB) { if (obj_byteorder != ELFDATA2LSB && obj_byteorder != ELFDATA2MSB) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
pr_warn("unknown byte order of ELF file %s\n", filename); pr_warn("unknown byte order of ELF file %s\n", obj->filename);
return err; return err;
} }
if (link_byteorder == ELFDATANONE) { if (link_byteorder == ELFDATANONE) {
@@ -591,7 +591,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
obj_byteorder == ELFDATA2MSB ? "big" : "little"); obj_byteorder == ELFDATA2MSB ? "big" : "little");
} else if (link_byteorder != obj_byteorder) { } else if (link_byteorder != obj_byteorder) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
pr_warn("byte order mismatch with ELF file %s\n", filename); pr_warn("byte order mismatch with ELF file %s\n", obj->filename);
return err; return err;
} }
@@ -599,12 +599,12 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
|| ehdr->e_machine != EM_BPF || ehdr->e_machine != EM_BPF
|| ehdr->e_ident[EI_CLASS] != ELFCLASS64) { || ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
pr_warn_elf("unsupported kind of ELF file %s", filename); pr_warn_elf("unsupported kind of ELF file %s", obj->filename);
return err; return err;
} }
if (elf_getshdrstrndx(obj->elf, &obj->shstrs_sec_idx)) { if (elf_getshdrstrndx(obj->elf, &obj->shstrs_sec_idx)) {
pr_warn_elf("failed to get SHSTRTAB section index for %s", filename); pr_warn_elf("failed to get SHSTRTAB section index for %s", obj->filename);
return -EINVAL; return -EINVAL;
} }
@@ -616,21 +616,21 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
shdr = elf64_getshdr(scn); shdr = elf64_getshdr(scn);
if (!shdr) { if (!shdr) {
pr_warn_elf("failed to get section #%zu header for %s", pr_warn_elf("failed to get section #%zu header for %s",
sec_idx, filename); sec_idx, obj->filename);
return -EINVAL; return -EINVAL;
} }
sec_name = elf_strptr(obj->elf, obj->shstrs_sec_idx, shdr->sh_name); sec_name = elf_strptr(obj->elf, obj->shstrs_sec_idx, shdr->sh_name);
if (!sec_name) { if (!sec_name) {
pr_warn_elf("failed to get section #%zu name for %s", pr_warn_elf("failed to get section #%zu name for %s",
sec_idx, filename); sec_idx, obj->filename);
return -EINVAL; return -EINVAL;
} }
data = elf_getdata(scn, 0); data = elf_getdata(scn, 0);
if (!data) { if (!data) {
pr_warn_elf("failed to get section #%zu (%s) data from %s", pr_warn_elf("failed to get section #%zu (%s) data from %s",
sec_idx, sec_name, filename); sec_idx, sec_name, obj->filename);
return -EINVAL; return -EINVAL;
} }
@@ -666,7 +666,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
err = libbpf_get_error(obj->btf); err = libbpf_get_error(obj->btf);
if (err) { if (err) {
pr_warn("failed to parse .BTF from %s: %s\n", pr_warn("failed to parse .BTF from %s: %s\n",
filename, errstr(err)); obj->filename, errstr(err));
return err; return err;
} }
sec->skipped = true; sec->skipped = true;
@@ -677,7 +677,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
err = libbpf_get_error(obj->btf_ext); err = libbpf_get_error(obj->btf_ext);
if (err) { if (err) {
pr_warn("failed to parse .BTF.ext from '%s': %s\n", pr_warn("failed to parse .BTF.ext from '%s': %s\n",
filename, errstr(err)); obj->filename, errstr(err));
return err; return err;
} }
sec->skipped = true; sec->skipped = true;
@@ -694,7 +694,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
break; break;
default: default:
pr_warn("unrecognized section #%zu (%s) in %s\n", pr_warn("unrecognized section #%zu (%s) in %s\n",
sec_idx, sec_name, filename); sec_idx, sec_name, obj->filename);
err = -EINVAL; err = -EINVAL;
return err; return err;
} }