From patchwork Wed Dec 11 16:40:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alastair Robertson X-Patchwork-Id: 13903873 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mx0b-00082601.pphosted.com (mx0b-00082601.pphosted.com [67.231.153.30]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2E9301DDC28 for ; Wed, 11 Dec 2024 16:40:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.153.30 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733935254; cv=none; b=MBkXCNYUJ8YxbHuA8lBtHTh7CC3XHqu5reLPc8jDJvzN5WygEFR2BO7WGuJS9Ihz+ikveRgDW1l4j85Ww6vU/AIV5/dqHee1XSJ4Vh7fSOLs9Kbfxhr1xZAwAfxCG9WuGtCDbsRju2Mm+lGDAETs08yPSmiKyZonxFLAs31FwSM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733935254; c=relaxed/simple; bh=UGqooN44QP0yvvkU4awbg/Jj59nn91kEbkUTd45bC84=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ttQJ5mJjyhPsNFNZpGWnyYCO+U3jRcIYBuWwKE1GOj4a5MCxOjSh2MQJU+cKAcG8gnOIdCweQLRk3rrD6zR669wKYWwt9Z9DuyJmjATiNfyU96gQWqwkATacEabqASDfPVw8YdJEiKopT6/YDP7F3daMfFv2NXnVI5Mqe/DXF28= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=meta.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=meta.com header.i=@meta.com header.b=KkEJCqSw; arc=none smtp.client-ip=67.231.153.30 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=meta.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=meta.com header.i=@meta.com header.b="KkEJCqSw" Received: from pps.filterd (m0109332.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4BBFIXWm018110 for ; Wed, 11 Dec 2024 08:40:51 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=meta.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2021-q4; bh=FPQF7Blv516U2c3K8sanMxY+nhDtcUr4bdRsbNq78BQ=; b=KkEJCqSwPfq/ UfJ2nn7URqULqHvfi1sCbUV+qdt7sv1NJu461OGPz15uICOG66x4D95ahXQGG4Dy Hwp16yRmTVqRWMVP4a4KoUfFdMPe8rcX1eD5ts1XBPRPAWKLnfZo0olfRBaa3xU1 bbfaBiVY75zMa045uQH/us+h/e83YMsCvxgoAGQWQxpIH4DYu43k9CEaCgxsdatX ucZ/CzNGDwMtoZ0CnqTHK3ioUZXeISzlVnELsGM/Cpzpl2zlQCt4c+LFnKSfelY/ dagV26AzTNC9p6115kVdyeudqFo/1/fFxNWcpTsS1+/QuzR9YSY9h6tZoR2xFibR XH2yYPiTpQ== Received: from mail.thefacebook.com ([163.114.134.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 43fcews3u0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Wed, 11 Dec 2024 08:40:50 -0800 (PST) Received: from twshared7122.08.ash9.facebook.com (2620:10d:c085:208::7cb7) by mail.thefacebook.com (2620:10d:c08b:78::2ac9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.1544.11; Wed, 11 Dec 2024 16:40:46 +0000 Received: by devbig020.cln3.facebook.com (Postfix, from userid 546475) id 6F950D41CD37; Wed, 11 Dec 2024 08:40:36 -0800 (PST) From: Alastair Robertson To: , CC: Alastair Robertson Subject: [PATCH bpf-next v3 1/2] libbpf: Pull file-opening logic up to top-level functions Date: Wed, 11 Dec 2024 08:40:29 -0800 Message-ID: <20241211164030.573042-2-ajor@meta.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20241211164030.573042-1-ajor@meta.com> References: <20241211164030.573042-1-ajor@meta.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-FB-Internal: Safe X-Proofpoint-GUID: zMu9xxXD3TducOHdBBVO4KvjX6iSRcuk X-Proofpoint-ORIG-GUID: zMu9xxXD3TducOHdBBVO4KvjX6iSRcuk X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1051,Hydra:6.0.680,FMLib:17.12.62.30 definitions=2024-10-05_03,2024-10-04_01,2024-09-30_01 X-Patchwork-Delegate: bpf@iogearbox.net 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 --- tools/lib/bpf/linker.c | 83 +++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c index e56ba6e67451..eb2ac7afce01 100644 --- a/tools/lib/bpf/linker.c +++ b/tools/lib/bpf/linker.c @@ -157,10 +157,9 @@ struct bpf_linker { #define pr_warn_elf(fmt, ...) \ 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, - const struct bpf_linker_file_opts *opts, +static int linker_load_obj_file(struct bpf_linker *linker, 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); @@ -233,9 +232,20 @@ struct bpf_linker *bpf_linker__new(const char *filename, struct bpf_linker_opts if (!linker) return errno = ENOMEM, NULL; - linker->fd = -1; + linker->filename = strdup(filename); + if (!linker->filename) { + err = -ENOMEM; + goto err_out; + } + + 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, filename); + err = init_output_elf(linker); if (err) goto err_out; @@ -294,23 +304,12 @@ static Elf64_Sym *add_new_sym(struct bpf_linker *linker, size_t *sym_idx) 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; Elf64_Sym *init_sym; 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); if (!linker->elf) { 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) { struct src_obj obj = {}; - int err = 0; + int err = 0, fd; if (!OPTS_VALID(opts, bpf_linker_file_opts)) return libbpf_err(-EINVAL); @@ -448,7 +447,16 @@ int bpf_linker__add_file(struct bpf_linker *linker, const char *filename, if (!linker->elf) return libbpf_err(-EINVAL); - err = err ?: linker_load_obj_file(linker, filename, opts, &obj); + fd = open(filename, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + pr_warn("failed to open file '%s': %s\n", filename, errstr(errno)); + return -errno; + } + + 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_elf_syms(linker, &obj); err = err ?: linker_append_elf_relos(linker, &obj); @@ -534,8 +542,7 @@ static struct src_sec *add_src_sec(struct src_obj *obj, const char *sec_name) return sec; } -static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, - const struct bpf_linker_file_opts *opts, +static int linker_load_obj_file(struct bpf_linker *linker, struct src_obj *obj) { int err = 0; @@ -554,26 +561,18 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, #error "Unknown __BYTE_ORDER__" #endif - pr_debug("linker: adding object file '%s'...\n", filename); - - obj->filename = filename; + pr_debug("linker: adding object file '%s'...\n", obj->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); 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; } /* Sanity check ELF file high-level properties */ ehdr = elf64_getehdr(obj->elf); 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; } @@ -581,7 +580,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, obj_byteorder = ehdr->e_ident[EI_DATA]; if (obj_byteorder != ELFDATA2LSB && obj_byteorder != ELFDATA2MSB) { 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; } if (link_byteorder == ELFDATANONE) { @@ -591,7 +590,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, obj_byteorder == ELFDATA2MSB ? "big" : "little"); } else if (link_byteorder != obj_byteorder) { 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; } @@ -599,12 +598,12 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, || ehdr->e_machine != EM_BPF || ehdr->e_ident[EI_CLASS] != ELFCLASS64) { 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; } 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; } @@ -616,21 +615,21 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, shdr = elf64_getshdr(scn); if (!shdr) { pr_warn_elf("failed to get section #%zu header for %s", - sec_idx, filename); + sec_idx, obj->filename); return -EINVAL; } sec_name = elf_strptr(obj->elf, obj->shstrs_sec_idx, shdr->sh_name); if (!sec_name) { pr_warn_elf("failed to get section #%zu name for %s", - sec_idx, filename); + sec_idx, obj->filename); return -EINVAL; } data = elf_getdata(scn, 0); if (!data) { 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; } @@ -666,7 +665,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, err = libbpf_get_error(obj->btf); if (err) { pr_warn("failed to parse .BTF from %s: %s\n", - filename, errstr(err)); + obj->filename, errstr(err)); return err; } sec->skipped = true; @@ -677,7 +676,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, err = libbpf_get_error(obj->btf_ext); if (err) { pr_warn("failed to parse .BTF.ext from '%s': %s\n", - filename, errstr(err)); + obj->filename, errstr(err)); return err; } sec->skipped = true; @@ -694,7 +693,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, break; default: pr_warn("unrecognized section #%zu (%s) in %s\n", - sec_idx, sec_name, filename); + sec_idx, sec_name, obj->filename); err = -EINVAL; return err; } From patchwork Wed Dec 11 16:40:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alastair Robertson X-Patchwork-Id: 13903872 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mx0a-00082601.pphosted.com (mx0a-00082601.pphosted.com [67.231.145.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D99231DDA3C for ; Wed, 11 Dec 2024 16:40:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=67.231.145.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733935251; cv=none; b=rtPdCr4EaMZMUnXqjT+OKgk3qWlPlBWcj6oSFPss6IRFEVrGQoK6FgjcJB+6A9KybDlrsAVm5Do2CQY2ROh/8k8jawn/cSduDNW7xuyYPccHFNl6Ka/eEzx28zgQgRoZJQ6gksCtzVRnJwFaK1XGYhKV6tYp9BUeW1omJ8+gkZ4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733935251; c=relaxed/simple; bh=rC4zj3vKjA3T+/EjqKFl0/tv6GDcOBHnvtIcqIZbCDo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ncQvFKrXvUgQmbK9XDXMU8hadj8BlnrRkNIyOs/v/v9oGghHruwT3WloGj0FHfD5K9oVgK6oysHesZ3lFQlsgyiwd9a9CYH7EFxiK5bxqaCOf5Oo7lYfv7vY4+YL59qlS01uPYAJL11U3dU3PpBe4HJ5ZvZsI1fW9Ijj8/V9htA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=meta.com; spf=pass smtp.mailfrom=meta.com; dkim=pass (2048-bit key) header.d=meta.com header.i=@meta.com header.b=BfpQYlfe; arc=none smtp.client-ip=67.231.145.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=meta.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=meta.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=meta.com header.i=@meta.com header.b="BfpQYlfe" Received: from pps.filterd (m0044010.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4BBFHmAK020765 for ; Wed, 11 Dec 2024 08:40:49 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=meta.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=s2048-2021-q4; bh=xbiln5nukbNSyX4ieHJty83yMy3mz8c3CgwYDlIEeno=; b=BfpQYlfemsal XIEBs8f73Px8Zy6qPcKtVwAI5hw8Xx7vr3SM3Hr6uXYDgWPriowOXIVlBWB4Q4Wp VtWZhhHzo0dq9uP8WaXkGhWb48jQGN6cI6zDgUEeMQMHu3A+cb35b6JJj8d3YDAB RwdehkUEo+Y8duKruHcqMA7t5DFkNxKxjNtMqGIxUr9+xrqX5wXYCEicS5uVqyJT fiKgzRhVkTnSYpHsyhPy4pN4ojqU/uZaxASZjOqDKcxs4uY+UdoP3DNnL0XAwFEI kPAsFQ6kvYUiWblZA/R0La4s3gCBJuZjk2UtuQWWT7hUfkNtZ0HbFwV+bAcbHjOk 9cd4ZY/Tgw== Received: from mail.thefacebook.com ([163.114.134.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 43fbt59cma-5 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Wed, 11 Dec 2024 08:40:48 -0800 (PST) Received: from twshared11082.06.ash8.facebook.com (2620:10d:c085:208::7cb7) by mail.thefacebook.com (2620:10d:c08b:78::c78f) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.1544.11; Wed, 11 Dec 2024 16:40:46 +0000 Received: by devbig020.cln3.facebook.com (Postfix, from userid 546475) id 1878BD41CD3D; Wed, 11 Dec 2024 08:40:37 -0800 (PST) From: Alastair Robertson To: , CC: Alastair Robertson Subject: [PATCH bpf-next v3 2/2] libbpf: Extend linker API to support in-memory ELF files Date: Wed, 11 Dec 2024 08:40:30 -0800 Message-ID: <20241211164030.573042-3-ajor@meta.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20241211164030.573042-1-ajor@meta.com> References: <20241211164030.573042-1-ajor@meta.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-FB-Internal: Safe X-Proofpoint-GUID: LSm3aWiBd4VVbyVj4vYbRsrxgN-zwP6T X-Proofpoint-ORIG-GUID: LSm3aWiBd4VVbyVj4vYbRsrxgN-zwP6T X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1051,Hydra:6.0.680,FMLib:17.12.62.30 definitions=2024-10-05_03,2024-10-04_01,2024-09-30_01 X-Patchwork-Delegate: bpf@iogearbox.net The new_fd and add_fd functions correspond to the original new and add_file functions, but accept an FD instead of a file name. This gives API consumers the option of using anonymous files/memfds to avoid writing ELFs to disk. This new API will be useful for performing linking as part of bpftrace's JIT compilation. The add_buf function is a convenience wrapper that does the work of creating a memfd for the caller. Signed-off-by: Alastair Robertson --- tools/lib/bpf/libbpf.h | 5 ++ tools/lib/bpf/libbpf.map | 4 + tools/lib/bpf/linker.c | 163 ++++++++++++++++++++++++++++++++++----- 3 files changed, 152 insertions(+), 20 deletions(-) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index b2ce3a72b11d..d45807103565 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -1796,9 +1796,14 @@ struct bpf_linker_file_opts { struct bpf_linker; LIBBPF_API struct bpf_linker *bpf_linker__new(const char *filename, struct bpf_linker_opts *opts); +LIBBPF_API struct bpf_linker *bpf_linker__new_fd(int fd, struct bpf_linker_opts *opts); LIBBPF_API int bpf_linker__add_file(struct bpf_linker *linker, const char *filename, const struct bpf_linker_file_opts *opts); +LIBBPF_API int bpf_linker__add_fd(struct bpf_linker *linker, int fd, + const struct bpf_linker_file_opts *opts); +LIBBPF_API int bpf_linker__add_buf(struct bpf_linker *linker, void *buf, size_t buf_sz, + const struct bpf_linker_file_opts *opts); LIBBPF_API int bpf_linker__finalize(struct bpf_linker *linker); LIBBPF_API void bpf_linker__free(struct bpf_linker *linker); diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 54b6f312cfa8..a8b2936a1646 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -432,4 +432,8 @@ LIBBPF_1.5.0 { } LIBBPF_1.4.0; LIBBPF_1.6.0 { + global: + bpf_linker__add_buf; + bpf_linker__add_fd; + bpf_linker__new_fd; } LIBBPF_1.5.0; diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c index eb2ac7afce01..6b3b86d98f6c 100644 --- a/tools/lib/bpf/linker.c +++ b/tools/lib/bpf/linker.c @@ -4,6 +4,10 @@ * * Copyright (c) 2021 Facebook */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #include #include #include @@ -16,6 +20,7 @@ #include #include #include +#include #include "libbpf.h" #include "btf.h" #include "libbpf_internal.h" @@ -152,6 +157,8 @@ struct bpf_linker { /* global (including extern) ELF symbols */ int glob_sym_cnt; struct glob_sym *glob_syms; + + bool fd_is_owned; }; #define pr_warn_elf(fmt, ...) \ @@ -159,6 +166,9 @@ struct bpf_linker { static int init_output_elf(struct bpf_linker *linker); +static int bpf_linker_add_file(struct bpf_linker *linker, int fd, + const char *filename); + static int linker_load_obj_file(struct bpf_linker *linker, struct src_obj *obj); static int linker_sanity_check_elf(struct src_obj *obj); @@ -190,7 +200,7 @@ void bpf_linker__free(struct bpf_linker *linker) if (linker->elf) elf_end(linker->elf); - if (linker->fd >= 0) + if (linker->fd >= 0 && linker->fd_is_owned) close(linker->fd); strset__free(linker->strtab_strs); @@ -244,6 +254,49 @@ struct bpf_linker *bpf_linker__new(const char *filename, struct bpf_linker_opts pr_warn("failed to create '%s': %d\n", filename, err); goto err_out; } + linker->fd_is_owned = true; + + err = init_output_elf(linker); + if (err) + goto err_out; + + return linker; + +err_out: + bpf_linker__free(linker); + return errno = -err, NULL; +} + +struct bpf_linker *bpf_linker__new_fd(int fd, struct bpf_linker_opts *opts) +{ + struct bpf_linker *linker; + char filename[32]; + int err; + + if (fd < 0) + return errno = EINVAL, NULL; + + if (!OPTS_VALID(opts, bpf_linker_opts)) + return errno = EINVAL, NULL; + + if (elf_version(EV_CURRENT) == EV_NONE) { + pr_warn_elf("libelf initialization failed"); + return errno = EINVAL, NULL; + } + + linker = calloc(1, sizeof(*linker)); + if (!linker) + return errno = ENOMEM, NULL; + + snprintf(filename, sizeof(filename), "fd:%d", fd); + linker->filename = strdup(filename); + if (!linker->filename) { + err = -ENOMEM; + goto err_out; + } + + linker->fd = fd; + linker->fd_is_owned = false; err = init_output_elf(linker); if (err) @@ -435,23 +488,11 @@ static int init_output_elf(struct bpf_linker *linker) return 0; } -int bpf_linker__add_file(struct bpf_linker *linker, const char *filename, - const struct bpf_linker_file_opts *opts) +static int bpf_linker_add_file(struct bpf_linker *linker, int fd, + const char *filename) { struct src_obj obj = {}; - int err = 0, fd; - - if (!OPTS_VALID(opts, bpf_linker_file_opts)) - return libbpf_err(-EINVAL); - - if (!linker->elf) - return libbpf_err(-EINVAL); - - fd = open(filename, O_RDONLY | O_CLOEXEC); - if (fd < 0) { - pr_warn("failed to open file '%s': %s\n", filename, errstr(errno)); - return -errno; - } + int err = 0; obj.filename = filename; obj.fd = fd; @@ -471,12 +512,93 @@ int bpf_linker__add_file(struct bpf_linker *linker, const char *filename, free(obj.sym_map); if (obj.elf) elf_end(obj.elf); - if (obj.fd >= 0) - close(obj.fd); return libbpf_err(err); } +int bpf_linker__add_file(struct bpf_linker *linker, const char *filename, + const struct bpf_linker_file_opts *opts) +{ + int fd, ret; + + if (!OPTS_VALID(opts, bpf_linker_file_opts)) + return libbpf_err(-EINVAL); + + if (!linker->elf) + return libbpf_err(-EINVAL); + + fd = open(filename, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + pr_warn("failed to open file '%s': %s\n", filename, errstr(errno)); + return -errno; + } + + ret = bpf_linker_add_file(linker, fd, filename); + + close(fd); + + return ret; +} + +int bpf_linker__add_fd(struct bpf_linker *linker, int fd, + const struct bpf_linker_file_opts *opts) +{ + char filename[32]; + int ret; + + if (!OPTS_VALID(opts, bpf_linker_file_opts)) + return libbpf_err(-EINVAL); + + if (!linker->elf) + return libbpf_err(-EINVAL); + + if (fd < 0) + return libbpf_err(-EINVAL); + + snprintf(filename, sizeof(filename), "fd:%d", fd); + + ret = bpf_linker_add_file(linker, fd, filename); + + return ret; +} + +int bpf_linker__add_buf(struct bpf_linker *linker, void *buf, size_t buf_sz, + const struct bpf_linker_file_opts *opts) +{ + char filename[32]; + int fd, written, ret; + + if (!OPTS_VALID(opts, bpf_linker_file_opts)) + return libbpf_err(-EINVAL); + + if (!linker->elf) + return libbpf_err(-EINVAL); + + snprintf(filename, sizeof(filename), "mem:%p+%zu", buf, buf_sz); + + fd = memfd_create(filename, 0); + if (fd < 0) { + pr_warn("failed to create memfd '%s': %s\n", filename, errstr(errno)); + return -errno; + } + + written = 0; + while (written < buf_sz) { + ret = write(fd, buf, buf_sz); + if (ret < 0) { + pr_warn("failed to write '%s': %s\n", filename, errstr(errno)); + return -errno; + } + written += ret; + } + + ret = bpf_linker_add_file(linker, fd, filename); + + close(fd); + + return ret; +} + static bool is_dwarf_sec_name(const char *name) { /* approximation, but the actual list is too long */ @@ -2686,9 +2808,10 @@ int bpf_linker__finalize(struct bpf_linker *linker) } elf_end(linker->elf); - close(linker->fd); - linker->elf = NULL; + + if (linker->fd_is_owned) + close(linker->fd); linker->fd = -1; return 0;