From patchwork Tue Mar 14 23:04:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eduard Zingerman X-Patchwork-Id: 13175114 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 714FEC76195 for ; Tue, 14 Mar 2023 23:04:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230351AbjCNXEg (ORCPT ); Tue, 14 Mar 2023 19:04:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40876 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230425AbjCNXEe (ORCPT ); Tue, 14 Mar 2023 19:04:34 -0400 Received: from mail-lf1-x12d.google.com (mail-lf1-x12d.google.com [IPv6:2a00:1450:4864:20::12d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1AE8623DAC; Tue, 14 Mar 2023 16:04:33 -0700 (PDT) Received: by mail-lf1-x12d.google.com with SMTP id x17so5941066lfu.5; Tue, 14 Mar 2023 16:04:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1678835071; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=UU0Bn7UeA8alALTZ1D0adE9t/Pl+aBM3F1PUcMiWTfw=; b=qRzFS3lUXQaVT/w0Eqgp3xKVhIKbASiJCJX4yuTtPaZaGYIHIXoiqstRPRhIdRDLuw MqviSTMs1ELMWMGQnVMJwCuYNteEHP0PV5jH0ynd88Vn03qrL49wdcVUvwtEs5R84L9N ATIFL6N6AlEK0Ma+Iv5H9Z4xvNI4md86afp2aKvKc+8iHl/Y5DZqpRkYH8DNH73Y1Svr fKLLCRdqA7uDAx8TQ9sRitD5vXm7D06M6W+cunzIIk9m4SwzVo8GNRx+MyMSHyHQjvGh AYCAf/iSmUfYVfYkO2dzt/TWy97XIj/NrkNtysAC/GmvH8uXqXdcxnlpuRYsN13dtW/g P53w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678835071; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=UU0Bn7UeA8alALTZ1D0adE9t/Pl+aBM3F1PUcMiWTfw=; b=tIEhnxfpMDe3y1VVQuIDlaAM6hc5cZYPpeCeK1FivhPm7yrsr6U94dqj+VgaqnvYrD JVj/UeQyqmsg043tBEoPvos9I/+P+UprWD4ieWrjbygTY6OpG6IZH8SyDcc1So8ojhmd T35gWOrb0WgNlQ4upDUYr+BIPomBzmL/Pj50CfbUpCSFh3iMJZOQ8lGemtVlP8VUoSqt qm00ickdN85mP5u6GIpWcIuNG9OWyAbUsLcVAUgyr9grdQb4b3xHYwXhuSVI2sCLQ5Y1 MRCpfekjcrW9A9UN5RBQIH1ctdAx39pR7Is+QaxD7IwCzEb80ueXfKQxYrftOG2Qzg/E nYcA== X-Gm-Message-State: AO0yUKUQQMtJMQo+gzfdGqvfnqvqqrGAfZx6JxnW77JPdnXcxkASvPBp ddHh9JVNnoJ2FX/WLgRPQ0bD+XOc47MLF14S X-Google-Smtp-Source: AK7set9kk4VoEbBxsT7GBEyTmRBp7dIu0/OHwWN7xvjJV2IgxKV7rSro0DOTr4iykJZ211rBhHpwTw== X-Received: by 2002:ac2:48bc:0:b0:4cc:597b:583e with SMTP id u28-20020ac248bc000000b004cc597b583emr1185144lfg.55.1678835071119; Tue, 14 Mar 2023 16:04:31 -0700 (PDT) Received: from bigfoot.. (host-176-36-0-241.b024.la.net.ua. [176.36.0.241]) by smtp.gmail.com with ESMTPSA id b1-20020ac25e81000000b004cc7acfbd2bsm569638lfq.287.2023.03.14.16.04.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Mar 2023 16:04:30 -0700 (PDT) From: Eduard Zingerman To: dwarves@vger.kernel.org, arnaldo.melo@gmail.com Cc: bpf@vger.kernel.org, kernel-team@fb.com, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, yhs@fb.com, jose.marchesi@oracle.com, david.faust@oracle.com, alan.maguire@oracle.com, Eduard Zingerman Subject: [PATCH dwarves v2 1/5] fprintf: Correct names for types with btf_type_tag attribute Date: Wed, 15 Mar 2023 01:04:13 +0200 Message-Id: <20230314230417.1507266-2-eddyz87@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230314230417.1507266-1-eddyz87@gmail.com> References: <20230314230417.1507266-1-eddyz87@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org The following example contains a structure field annotated with btf_type_tag attribute: #define __tag1 __attribute__((btf_type_tag("tag1"))) struct st { int __tag1 *a; } g; It is not printed correctly by `pahole -F dwarf` command: $ clang -g -c test.c -o test.o pahole -F dwarf test.o struct st { tag1 * a; /* 0 8 */ ... }; Note the type for variable `a`: `tag1` is printed instead of `int`. This commit teaches `type__fprintf()` and `__tag_name()` logic to skip `DW_TAG_LLVM_annotation` objects that are used to encode type tags. Signed-off-by: Eduard Zingerman --- dwarves_fprintf.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c index e8399e7..1e6147a 100644 --- a/dwarves_fprintf.c +++ b/dwarves_fprintf.c @@ -572,6 +572,7 @@ static const char *__tag__name(const struct tag *tag, const struct cu *cu, case DW_TAG_restrict_type: case DW_TAG_atomic_type: case DW_TAG_unspecified_type: + case DW_TAG_LLVM_annotation: type = cu__type(cu, tag->type); if (type == NULL && tag->type != 0) tag__id_not_found_snprintf(bf, len, tag->type); @@ -786,6 +787,10 @@ next_type: n = tag__has_type_loop(type, ptype, NULL, 0, fp); if (n) return printed + n; + if (ptype->tag == DW_TAG_LLVM_annotation) { + type = ptype; + goto next_type; + } if (ptype->tag == DW_TAG_subroutine_type) { printed += ftype__fprintf(tag__ftype(ptype), cu, name, 0, 1, @@ -880,6 +885,14 @@ print_modifier: { else printed += enumeration__fprintf(type, &tconf, fp); break; + case DW_TAG_LLVM_annotation: { + struct tag *ttype = cu__type(cu, type->type); + if (ttype) { + type = ttype; + goto next_type; + } + goto out_type_not_found; + } } out: if (type_expanded) From patchwork Tue Mar 14 23:04:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eduard Zingerman X-Patchwork-Id: 13175115 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F142BC7619A for ; Tue, 14 Mar 2023 23:04:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230448AbjCNXEg (ORCPT ); Tue, 14 Mar 2023 19:04:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40888 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230414AbjCNXEf (ORCPT ); Tue, 14 Mar 2023 19:04:35 -0400 Received: from mail-lf1-x12b.google.com (mail-lf1-x12b.google.com [IPv6:2a00:1450:4864:20::12b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A02DFCDD8; Tue, 14 Mar 2023 16:04:34 -0700 (PDT) Received: by mail-lf1-x12b.google.com with SMTP id bp27so11777052lfb.6; Tue, 14 Mar 2023 16:04:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1678835072; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=yP0TRJN4eh00/BpCyREFlXc4OCtxCsau3kExI5Vt0g0=; b=WoeQ+7Z8zCC3rL3DR0NMGMSo3tDy+9Q2XQQldi/iwhnVOD6O1KqrSFqeepVPe81vnB 9EBlN8SAFkzScYECoelfB5Y0vjCA0rdY1zx7JtuBJW0Wf+lWadtkSjfNxPC6mopD9EIq YAU+g/WjCdlpzOs20YPob66MHm2BgUiUvCTvTy7dhU7vGkG/WiFgWe3urx09l6m4rxoX Qst8ImZ3lQhkzmipzEg3YWEvoqOsFYNBxcEH0vzSq3cbCRxHTCOyrh0v/Tfk5yyBWQYa HgPx8/wSxkHiovqD5xnau0V3BPMT8Y3eY+Q572arG3qrkeRsnCRAkXUk8jcJsSajOUh5 3VNQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678835072; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=yP0TRJN4eh00/BpCyREFlXc4OCtxCsau3kExI5Vt0g0=; b=4KVC7XGfWPLdMfNKJV8abNcgIUNG9IPuNsgHlGJ8Kq6D8EfHFMI4/WdFpO4ubBa5I/ OBymlJ4yViqxncj+IiTLD5bC0+eez0GWDTw01oG36TXmASxIfd5kWDPWekcaWVrku04X 3Fdvsa0kZggUsUsxa1kFM1R7hRSZApHlI9wCpimd9ui7WZSWJaFtdD8+pDqCkonw/inq 3o/b/1Cot9eay3hxwJFHKUN3HpxwYvEkFezTq0SAdXnhMWESJmDFDLHd4F0IlB4DZ3QH QYZ+rduljWsSEG9yLlkuF11CQCprfzpJeTqWhkefRUwPQ4MYChi4ndRHRQJ2zXVTk7SL ROPA== X-Gm-Message-State: AO0yUKVbtPFaYQ8zKVGydfIi8R5PQdlVTiBfdY/dWwboGGluPQ+Eisl7 3GFLKCM/W1Sd1HekAapvo4Fu3Ry48bKUPlhT X-Google-Smtp-Source: AK7set9q7qhpQ9EhcJ/EqeAx4H9ba7eqljlKm0kurMs2aWsjrKVpc/OAdW23QDL8Q0U0JGN7lmF75A== X-Received: by 2002:a19:ae01:0:b0:4db:25f2:c116 with SMTP id f1-20020a19ae01000000b004db25f2c116mr1159564lfc.18.1678835072486; Tue, 14 Mar 2023 16:04:32 -0700 (PDT) Received: from bigfoot.. (host-176-36-0-241.b024.la.net.ua. [176.36.0.241]) by smtp.gmail.com with ESMTPSA id b1-20020ac25e81000000b004cc7acfbd2bsm569638lfq.287.2023.03.14.16.04.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Mar 2023 16:04:32 -0700 (PDT) From: Eduard Zingerman To: dwarves@vger.kernel.org, arnaldo.melo@gmail.com Cc: bpf@vger.kernel.org, kernel-team@fb.com, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, yhs@fb.com, jose.marchesi@oracle.com, david.faust@oracle.com, alan.maguire@oracle.com, Eduard Zingerman Subject: [PATCH dwarves v2 2/5] btf_loader: A hack for BTF import of btf_type_tag attributes Date: Wed, 15 Mar 2023 01:04:14 +0200 Message-Id: <20230314230417.1507266-3-eddyz87@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230314230417.1507266-1-eddyz87@gmail.com> References: <20230314230417.1507266-1-eddyz87@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org Pahole does not print type names correctly for the following example, when BTF loader is used: #define __tag1 __attribute__((btf_type_tag("tag1"))) struct st { int __tag1 *a; } g; Here is the pahole output: $ clang -target bpf -g -c test.c -o test.o $ pahole -F btf test.o BTF: idx: 2, Unknown kind 18 struct st { a; /* 0 8 */ ... }; Note the type name for field `a`. This commit adds a workaround for this issue: it creates a tag instance with tag->tag set to `DW_TAG_LLVM_annotation` and `tag->type` pointing to the type wrapped by `BTF_KIND_TYPE_TAG`, `int` for the example above. Note that this is not a complete replication of behavior of DWARF loader. When DWARF is processed type tag instances are added to the annotations list of the parent pointer type. However, this is sufficient to fix the printing issue and helps with `btfdiff` script. Signed-off-by: Eduard Zingerman --- btf_loader.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/btf_loader.c b/btf_loader.c index e579323..3fe07d0 100644 --- a/btf_loader.c +++ b/btf_loader.c @@ -429,10 +429,11 @@ static int create_new_tag(struct cu *cu, int type, const struct btf_type *tp, ui return -ENOMEM; switch (type) { - case BTF_KIND_CONST: tag->tag = DW_TAG_const_type; break; - case BTF_KIND_PTR: tag->tag = DW_TAG_pointer_type; break; - case BTF_KIND_RESTRICT: tag->tag = DW_TAG_restrict_type; break; - case BTF_KIND_VOLATILE: tag->tag = DW_TAG_volatile_type; break; + case BTF_KIND_CONST: tag->tag = DW_TAG_const_type; break; + case BTF_KIND_PTR: tag->tag = DW_TAG_pointer_type; break; + case BTF_KIND_RESTRICT: tag->tag = DW_TAG_restrict_type; break; + case BTF_KIND_VOLATILE: tag->tag = DW_TAG_volatile_type; break; + case BTF_KIND_TYPE_TAG: tag->tag = DW_TAG_LLVM_annotation; break; default: free(tag); printf("%s: Unknown type %d\n\n", __func__, type); @@ -489,6 +490,12 @@ static int btf__load_types(struct btf *btf, struct cu *cu) case BTF_KIND_PTR: case BTF_KIND_CONST: case BTF_KIND_RESTRICT: + /* For type tag it's a bit of a lie. + * In DWARF it is encoded as a child tag of whatever type it + * applies to. Here we load it as a standalone tag with a pointer + * to a next type only to have a valid ID in the types table. + */ + case BTF_KIND_TYPE_TAG: err = create_new_tag(cu, type, type_ptr, type_index); break; case BTF_KIND_UNKN: From patchwork Tue Mar 14 23:04:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eduard Zingerman X-Patchwork-Id: 13175117 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 17C90C761A6 for ; Tue, 14 Mar 2023 23:04:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231218AbjCNXEj (ORCPT ); Tue, 14 Mar 2023 19:04:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40960 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230517AbjCNXEi (ORCPT ); Tue, 14 Mar 2023 19:04:38 -0400 Received: from mail-lf1-x134.google.com (mail-lf1-x134.google.com [IPv6:2a00:1450:4864:20::134]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B7170211E5; Tue, 14 Mar 2023 16:04:35 -0700 (PDT) Received: by mail-lf1-x134.google.com with SMTP id n2so22030180lfb.12; Tue, 14 Mar 2023 16:04:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1678835074; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=T+SscChHQ3Tpz4GDyUcYPHYCKNpT/taHvga7qJQiymo=; b=SZhCcSMVossutuNF/O5ZSOn22MYkb+r7Rm+3qgBMMNFZQ0+jyfvdwKtY33gEtib3VY vLNGu14Lo2oyCzUplkHqzNZqRSoX9YXUW8y7lAr5abSZgG2GlsxM07P2nhIE7oNpHXNj FSdLawPYcH83i4Klb0+M2fbIrrLVVSNHtYep5cJk5xE9cW+7IpWm99wRcuG3ZjpJtkLr I8mga7EC/5/5iN4XFSG9c4MXaOc4WW5Ryd+5tlQ/tjoG2/f9K5PDKHwzPZf7Cht4yonA yviyJnpZnDGHe/5ASWSkVNzURGwKIxO/MZba0IpEX18DRxA8ZdJKlTzwiYg9LTKBE4eZ 6tIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678835074; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=T+SscChHQ3Tpz4GDyUcYPHYCKNpT/taHvga7qJQiymo=; b=xqasPRvNYuS2rAi1n3iIlpggKKsK/k1+G4IXMnl2d91zSf08ibftJzB+kUkOpas0xo T/7aBfUAjdW2c5ekT6jZ7sFIMS5/x3GWaK4RGOSKg87WtXerVt0AZmA4BYn9LRwmJQot PnqrGZVreT0xuv9v9/dVJPDDidNZk2YCO4GVeGJ5Ap9FXcCSIuY90Km4THw/iL4WeQms QOUoORROkR6Id8MYoU9UeGhwa+GczEaXUeDoVDz8H8CKOI1Fjw2y1HrhtfTY8L/LPKe3 5xlRhsVlnelCOdiwSItBOygNTTqrO6Mudr3tARVmNyf9/MRzS3EBPevoFefhJ90at+iy w+7Q== X-Gm-Message-State: AO0yUKWiryFbJMBn9lFqsvNzxSshVs/3tdtMFrYWw1SabC5TzEHZItot Bs5MIPpsm/FpD63Xg/f4Tu8OmN3HWOFYxwdE X-Google-Smtp-Source: AK7set/DaHVzr+ZLjnDuo+MQhMZoPiGAMu8q251UuF6M/V3uwMJFJKSHvHQFDnNlaIzV6xPHnXyWaw== X-Received: by 2002:ac2:596c:0:b0:4de:6973:82aa with SMTP id h12-20020ac2596c000000b004de697382aamr1153078lfp.68.1678835073722; Tue, 14 Mar 2023 16:04:33 -0700 (PDT) Received: from bigfoot.. (host-176-36-0-241.b024.la.net.ua. [176.36.0.241]) by smtp.gmail.com with ESMTPSA id b1-20020ac25e81000000b004cc7acfbd2bsm569638lfq.287.2023.03.14.16.04.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Mar 2023 16:04:33 -0700 (PDT) From: Eduard Zingerman To: dwarves@vger.kernel.org, arnaldo.melo@gmail.com Cc: bpf@vger.kernel.org, kernel-team@fb.com, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, yhs@fb.com, jose.marchesi@oracle.com, david.faust@oracle.com, alan.maguire@oracle.com, Eduard Zingerman Subject: [PATCH dwarves v2 3/5] dwarf_loader: Consolidate llvm_annotation and btf_type_tag_type Date: Wed, 15 Mar 2023 01:04:15 +0200 Message-Id: <20230314230417.1507266-4-eddyz87@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230314230417.1507266-1-eddyz87@gmail.com> References: <20230314230417.1507266-1-eddyz87@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org In recent discussion in BPF mailing list ([1]) participants agreed to add a new DWARF representation for "btf_type_tag" annotations. Existing representation is DW_TAG_LLVM_annotation object attached as a child to a DW_TAG_pointer_type. It means that "btf_type_tag" annotation is attached to a pointee type. New representation is DW_TAG_LLVM_annotation object attached as a child to *any* type. It means that "btf_type_tag" annotation is attached to the parent type. For example, consider the following C code: struct alpha { int __attribute__((btf_type_tag("__alpha_a"))) *a; } g; And corresponding DWARF: 0x29: DW_TAG_structure_type DW_AT_name ("alpha") 0x2e: DW_TAG_member DW_AT_name ("a") DW_AT_type (0x38 "int *") 0x38: DW_TAG_pointer_type DW_AT_type (0x41 "int") 0x3d: DW_TAG_LLVM_annotation DW_AT_name ("btf_type_tag") DW_AT_const_value ("__alpha_a") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Old style representation 0x41: DW_TAG_base_type DW_AT_name ("int") DW_AT_encoding (DW_ATE_signed) DW_AT_byte_size (0x04) 0x45: DW_TAG_LLVM_annotation DW_AT_name ("btf:type_tag") DW_AT_const_value ("__alpha_a") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ New style representation This means that new style type tags could be attached to any type from the list below: - base types; - arrays; - pointers; - structs - unions; - enums; - typedefs. This commit is a preparatory step for `btf:type_tag` support: - structs, unions and typedefs could be annotated with two kinds of `DW_TAG_LLVM_annotation` when new type tag representation is used: - BTF_DECL_TAG - BTF_TYPE_TAG In order to keep these objects in a single annotations list `struct llvm_annotation` and `struct btf_type_tag_type` are consolidated as a single type with a special discriminator field to distinguish one from the other; - Because many types could be annotated with `btf:type_tag` the `annots` field is moved to `struct tag`, consequently: - type `struct btf_type_tag_type_ptr` is removed; - field `struct namespace::annots` is removed. [1] Mailing list discussion regarding `btf:type_tag` Various approaches are discussed, Solution #2 is accepted https://lore.kernel.org/bpf/87r0w9jjoq.fsf@oracle.com/ Signed-off-by: Eduard Zingerman --- btf_encoder.c | 13 ++- dwarf_loader.c | 230 ++++++++++++++++++++++++++----------------------- dwarves.h | 49 ++++------- 3 files changed, 150 insertions(+), 142 deletions(-) diff --git a/btf_encoder.c b/btf_encoder.c index 65f6e71..1aa4ffc 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -893,6 +893,9 @@ static int32_t btf_encoder__add_func(struct btf_encoder *encoder, struct functio return -1; } list_for_each_entry(annot, &fn->annots, node) { + if (annot->kind != BTF_DECL_TAG) + continue; + tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, btf_fn_id, annot->component_idx); if (tag_type_id < 0) { @@ -1175,7 +1178,7 @@ static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag, name = namespace__name(tag__namespace(tag)); return btf_encoder__add_ref_type(encoder, BTF_KIND_TYPEDEF, ref_type_id, name, false); case DW_TAG_LLVM_annotation: - name = tag__btf_type_tag(tag)->value; + name = tag__llvm_annotation(tag)->value; return btf_encoder__add_ref_type(encoder, BTF_KIND_TYPE_TAG, ref_type_id, name, false); case DW_TAG_structure_type: case DW_TAG_union_type: @@ -1600,6 +1603,9 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) } list_for_each_entry(annot, &var->annots, node) { + if (annot->kind != BTF_DECL_TAG) + continue; + int tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, id, annot->component_idx); if (tag_type_id < 0) { fprintf(stderr, "error: failed to encode tag '%s' to variable '%s' with component_idx %d\n", @@ -1793,7 +1799,10 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co btf_type_id = encoder->type_id_off + core_id; ns = tag__namespace(pos); - list_for_each_entry(annot, &ns->annots, node) { + list_for_each_entry(annot, &ns->tag.annots, node) { + if (annot->kind != BTF_DECL_TAG) + continue; + tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, btf_type_id, annot->component_idx); if (tag_type_id < 0) { fprintf(stderr, "error: failed to encode tag '%s' to %s '%s' with component_idx %d\n", diff --git a/dwarf_loader.c b/dwarf_loader.c index 4efa4e1..17a2773 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -112,6 +112,17 @@ static dwarf_off_ref dwarf_tag__spec(struct dwarf_tag *dtag) return *(dwarf_off_ref *)(dtag + 1); } +#define cu__tag_not_handled(die) __cu__tag_not_handled(die, __FUNCTION__) + +static void __cu__tag_not_handled(Dwarf_Die *die, const char *fn) +{ + uint32_t tag = dwarf_tag(die); + + fprintf(stderr, "%s: DW_TAG_%s (%#x) @ <%#llx> not handled!\n", + fn, dwarf_tag_name(tag), tag, + (unsigned long long)dwarf_dieoffset(die)); +} + static void dwarf_tag__set_spec(struct dwarf_tag *dtag, dwarf_off_ref spec) { *(dwarf_off_ref *)(dtag + 1) = spec; @@ -519,6 +530,7 @@ static void tag__init(struct tag *tag, struct cu *cu, Dwarf_Die *die) } INIT_LIST_HEAD(&tag->node); + INIT_LIST_HEAD(&tag->annots); } static struct tag *tag__new(Dwarf_Die *die, struct cu *cu) @@ -608,7 +620,6 @@ static void namespace__init(struct namespace *namespace, Dwarf_Die *die, { tag__init(&namespace->tag, cu, die); INIT_LIST_HEAD(&namespace->tags); - INIT_LIST_HEAD(&namespace->annots); namespace->name = attr_string(die, DW_AT_name, conf); namespace->nr_tags = 0; namespace->shared_tags = 0; @@ -876,8 +887,40 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b return -ENOMEM; } -static int add_llvm_annotation(Dwarf_Die *die, int component_idx, struct conf_load *conf, - struct list_head *head) +static struct llvm_annotation *die__create_new_llvm_annotation(Dwarf_Die *die, + struct cu *cu, + struct conf_load *conf) +{ + struct llvm_annotation *tag; + + tag = tag__alloc_with_spec(cu, sizeof(struct llvm_annotation)); + if (tag == NULL) + return NULL; + + tag__init(&tag->tag, cu, die); + return tag; +} + +/** Allocate small_id for specified @tag */ +static int cu__assign_tag_id(struct cu *cu, struct tag *tag) +{ + struct dwarf_tag *dtag = tag->priv; + uint32_t id; + + if (cu__table_add_tag(cu, tag, &id) < 0) + return -ENOMEM; + + dtag->small_id = id; + cu__hash(cu, tag); + + return 0; +} + +static int add_btf_decl_tag(Dwarf_Die *die, + struct cu *cu, + int component_idx, + struct conf_load *conf, + struct list_head *head) { struct llvm_annotation *annot; const char *name; @@ -890,17 +933,57 @@ static int add_llvm_annotation(Dwarf_Die *die, int component_idx, struct conf_lo if (strcmp(name, "btf_decl_tag") != 0) return 0; - annot = zalloc(sizeof(*annot)); + annot = die__create_new_llvm_annotation(die, cu, conf); if (!annot) return -ENOMEM; + /* Don't assign id for btf_decl_tag */ + + annot->kind = BTF_DECL_TAG; annot->value = attr_string(die, DW_AT_const_value, conf); annot->component_idx = component_idx; list_add_tail(&annot->node, head); return 0; } -static int add_child_llvm_annotations(Dwarf_Die *die, int component_idx, +static int add_btf_type_tag(Dwarf_Die *die, + struct cu *cu, + struct conf_load *conf, + struct list_head *head) +{ + struct llvm_annotation *annot; + const char *name; + + if (conf->skip_encoding_btf_type_tag) + return 0; + + name = attr_string(die, DW_AT_name, conf); + + if (strcmp(name, "btf_type_tag") != 0) + return 0; + + /* Create a btf_type_tag type for this annotation. */ + annot = die__create_new_llvm_annotation(die, cu, conf); + if (annot == NULL) + return -ENOMEM; + + cu__assign_tag_id(cu, &annot->tag); + + annot->kind = BTF_TYPE_TAG_POINTEE; + annot->value = attr_string(die, DW_AT_const_value, conf); + annot->component_idx = -1; + + /* For a list of DW_TAG_LLVM_annotation like tag1 -> tag2 -> tag3, + * the tag->tags contains tag3 -> tag2 -> tag1. + */ + list_add(&annot->node, head); + + return 0; +} + +static int add_child_llvm_annotations(Dwarf_Die *die, + struct cu *cu, + int component_idx, struct conf_load *conf, struct list_head *head) { Dwarf_Die child; @@ -912,9 +995,14 @@ static int add_child_llvm_annotations(Dwarf_Die *die, int component_idx, die = &child; do { if (dwarf_tag(die) == DW_TAG_LLVM_annotation) { - ret = add_llvm_annotation(die, component_idx, conf, head); + ret = add_btf_decl_tag(die, cu, component_idx, conf, head); if (ret) return ret; + ret = add_btf_type_tag(die, cu, conf, head); + if (ret) + return ret; + } else { + cu__tag_not_handled(die); } } while (dwarf_siblingof(die, die) == 0); @@ -1340,19 +1428,8 @@ static uint64_t attr_upper_bound(Dwarf_Die *die) return 0; } -static void __cu__tag_not_handled(Dwarf_Die *die, const char *fn) -{ - uint32_t tag = dwarf_tag(die); - - fprintf(stderr, "%s: DW_TAG_%s (%#x) @ <%#llx> not handled!\n", - fn, dwarf_tag_name(tag), tag, - (unsigned long long)dwarf_dieoffset(die)); -} - static struct tag unsupported_tag; -#define cu__tag_not_handled(die) __cu__tag_not_handled(die, __FUNCTION__) - static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu, int toplevel, const char *fn, struct conf_load *conf); @@ -1372,89 +1449,17 @@ static struct tag *die__create_new_tag(Dwarf_Die *die, struct cu *cu) return tag; } -static struct btf_type_tag_ptr_type *die__create_new_btf_type_tag_ptr_type(Dwarf_Die *die, struct cu *cu) +static struct tag *die__create_new_annotated_tag(Dwarf_Die *die, struct cu *cu, + struct conf_load *conf) { - struct btf_type_tag_ptr_type *tag; - - tag = tag__alloc_with_spec(cu, sizeof(struct btf_type_tag_ptr_type)); - if (tag == NULL) - return NULL; - - tag__init(&tag->tag, cu, die); - tag->tag.has_btf_type_tag = true; - INIT_LIST_HEAD(&tag->tags); - return tag; -} - -static struct btf_type_tag_type *die__create_new_btf_type_tag_type(Dwarf_Die *die, struct cu *cu, - struct conf_load *conf) -{ - struct btf_type_tag_type *tag; + struct tag *tag = tag__new(die, cu); - tag = tag__alloc_with_spec(cu, sizeof(struct btf_type_tag_type)); - if (tag == NULL) + if (add_child_llvm_annotations(die, cu, -1, conf, &tag->annots)) return NULL; - tag__init(&tag->tag, cu, die); - tag->value = attr_string(die, DW_AT_const_value, conf); return tag; } -static struct tag *die__create_new_pointer_tag(Dwarf_Die *die, struct cu *cu, - struct conf_load *conf) -{ - struct btf_type_tag_ptr_type *tag = NULL; - struct btf_type_tag_type *annot; - Dwarf_Die *cdie, child; - const char *name; - uint32_t id; - - /* If no child tags or skipping btf_type_tag encoding, just create a new tag - * and return - */ - if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0 || - conf->skip_encoding_btf_type_tag) - return tag__new(die, cu); - - /* Otherwise, check DW_TAG_LLVM_annotation child tags */ - cdie = &child; - do { - if (dwarf_tag(cdie) != DW_TAG_LLVM_annotation) - continue; - - /* Only check btf_type_tag annotations */ - name = attr_string(cdie, DW_AT_name, conf); - if (strcmp(name, "btf_type_tag") != 0) - continue; - - if (tag == NULL) { - /* Create a btf_type_tag_ptr type. */ - tag = die__create_new_btf_type_tag_ptr_type(die, cu); - if (!tag) - return NULL; - } - - /* Create a btf_type_tag type for this annotation. */ - annot = die__create_new_btf_type_tag_type(cdie, cu, conf); - if (annot == NULL) - return NULL; - - if (cu__table_add_tag(cu, &annot->tag, &id) < 0) - return NULL; - - struct dwarf_tag *dtag = annot->tag.priv; - dtag->small_id = id; - cu__hash(cu, &annot->tag); - - /* For a list of DW_TAG_LLVM_annotation like tag1 -> tag2 -> tag3, - * the tag->tags contains tag3 -> tag2 -> tag1. - */ - list_add(&annot->node, &tag->tags); - } while (dwarf_siblingof(cdie, cdie) == 0); - - return tag ? &tag->tag : tag__new(die, cu); -} - static struct tag *die__create_new_ptr_to_member_type(Dwarf_Die *die, struct cu *cu) { @@ -1541,7 +1546,7 @@ static struct tag *die__create_new_typedef(Dwarf_Die *die, struct cu *cu, struct if (tdef == NULL) return NULL; - if (add_child_llvm_annotations(die, -1, conf, &tdef->namespace.annots)) + if (add_child_llvm_annotations(die, cu, -1, conf, &tdef->namespace.tag.annots)) return NULL; return &tdef->namespace.tag; @@ -1610,7 +1615,8 @@ static struct tag *die__create_new_parameter(Dwarf_Die *die, if (ftype != NULL) { ftype__add_parameter(ftype, parm); if (param_idx >= 0) { - if (add_child_llvm_annotations(die, param_idx, conf, &(tag__function(&ftype->tag)->annots))) + if (add_child_llvm_annotations(die, cu, param_idx, conf, + &ftype->tag.annots)) return NULL; } } else { @@ -1651,7 +1657,7 @@ static struct tag *die__create_new_variable(Dwarf_Die *die, struct cu *cu, struc { struct variable *var = variable__new(die, cu, conf); - if (var == NULL || add_child_llvm_annotations(die, -1, conf, &var->annots)) + if (var == NULL || add_child_llvm_annotations(die, cu, -1, conf, &var->annots)) return NULL; return &var->ip.tag; @@ -1806,13 +1812,16 @@ static int die__process_class(Dwarf_Die *die, struct type *class, type__add_member(class, member); cu__hash(cu, &member->tag); - if (add_child_llvm_annotations(die, member_idx, conf, &class->namespace.annots)) + if (add_child_llvm_annotations(die, cu, member_idx, conf, + &class->namespace.tag.annots)) return -ENOMEM; member_idx++; } continue; case DW_TAG_LLVM_annotation: - if (add_llvm_annotation(die, -1, conf, &class->namespace.annots)) + if (add_btf_decl_tag(die, cu, -1, conf, &class->namespace.tag.annots)) + return -ENOMEM; + if (add_btf_type_tag(die, cu, conf, &class->namespace.tag.annots)) return -ENOMEM; continue; default: { @@ -2089,7 +2098,8 @@ static int die__process_function(Dwarf_Die *die, struct ftype *ftype, goto out_enomem; continue; case DW_TAG_LLVM_annotation: - if (add_llvm_annotation(die, -1, conf, &(tag__function(&ftype->tag)->annots))) + if (add_btf_decl_tag(die, cu, -1, conf, + &(tag__function(&ftype->tag)->annots))) goto out_enomem; continue; default: @@ -2165,7 +2175,7 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu, case DW_TAG_unspecified_type: tag = die__create_new_tag(die, cu); break; case DW_TAG_pointer_type: - tag = die__create_new_pointer_tag(die, cu, conf); break; + tag = die__create_new_annotated_tag(die, cu, conf); break; case DW_TAG_ptr_to_member_type: tag = die__create_new_ptr_to_member_type(die, cu); break; case DW_TAG_enumeration_type: @@ -2493,10 +2503,10 @@ static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu) } } -static void dwarf_cu__recode_btf_type_tag_ptr(struct btf_type_tag_ptr_type *tag, +static void dwarf_cu__recode_btf_type_tag_ptr(struct tag *tag, uint32_t pointee_type) { - struct btf_type_tag_type *annot; + struct llvm_annotation *annot; struct dwarf_tag *annot_dtag; struct tag *prev_tag; @@ -2523,8 +2533,8 @@ static void dwarf_cu__recode_btf_type_tag_ptr(struct btf_type_tag_ptr_type *tag, * int tag1 tag2 tag3 *p; * and this matches the user/kernel code. */ - prev_tag = &tag->tag; - list_for_each_entry(annot, &tag->tags, node) { + prev_tag = tag; + list_for_each_entry(annot, &tag->annots, node) { annot_dtag = annot->tag.priv; prev_tag->type = annot_dtag->small_id; prev_tag = &annot->tag; @@ -2636,15 +2646,17 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu) var->spec = tag__variable(dtype->tag); } } + break; } - + case DW_TAG_LLVM_annotation: + return 0; } if (dtag->type.off == 0) { - if (tag->tag != DW_TAG_pointer_type || !tag->has_btf_type_tag) + if (tag->tag != DW_TAG_pointer_type) tag->type = 0; /* void */ else - dwarf_cu__recode_btf_type_tag_ptr(tag__btf_type_tag_ptr(tag), 0); + dwarf_cu__recode_btf_type_tag_ptr(tag, 0); return 0; } @@ -2656,10 +2668,10 @@ check_type: return 0; } out: - if (tag->tag != DW_TAG_pointer_type || !tag->has_btf_type_tag) + if (tag->tag != DW_TAG_pointer_type) tag->type = dtype->small_id; else - dwarf_cu__recode_btf_type_tag_ptr(tag__btf_type_tag_ptr(tag), dtype->small_id); + dwarf_cu__recode_btf_type_tag_ptr(tag, dtype->small_id); return 0; } diff --git a/dwarves.h b/dwarves.h index 7a319d1..0b0b0cc 100644 --- a/dwarves.h +++ b/dwarves.h @@ -419,8 +419,8 @@ int cu__for_all_tags(struct cu *cu, void *cookie); /** struct tag - basic representation of a debug info element - * @priv - extra data, for instance, DWARF offset, id, decl_{file,line} - * @top_level - + * @priv - extra data, for instance, DWARF offset, id, decl_{file,line} + * @annots - list of btf_type_tag and btf_decl_tag annotations. */ struct tag { struct list_head node; @@ -428,8 +428,8 @@ struct tag { uint16_t tag; bool visited; bool top_level; - bool has_btf_type_tag; uint16_t recursivity_level; + struct list_head annots; void *priv; }; @@ -625,43 +625,31 @@ static inline struct ptr_to_member_type * return (struct ptr_to_member_type *)tag; } -struct llvm_annotation { - const char *value; - int16_t component_idx; - struct list_head node; +enum annotation_kind { + BTF_DECL_TAG, + /* "btf_type_tag" in DWARF, attached to a pointer, applies to pointee type */ + BTF_TYPE_TAG_POINTEE, }; -/** struct btf_type_tag_type - representing a btf_type_tag annotation +/** struct llvm_annotation - representing objects with DW_TAG_LLVM_annotation tag * - * @tag - DW_TAG_LLVM_annotation tag - * @value - btf_type_tag value string - * @node - list_head node + * @tag - DW_TAG_LLVM_annotation tag + * @kind - annotation kind + * @value - value string, valid for both "btf_decl_tag" and "btf_type_tag" + * @component_idx - component index, valid only for "btf_decl_tag" + * @node - list_head node */ -struct btf_type_tag_type { +struct llvm_annotation { struct tag tag; + enum annotation_kind kind; const char *value; + int16_t component_idx; struct list_head node; }; -/** The struct btf_type_tag_ptr_type - type containing both pointer type and - * its btf_type_tag annotations - * - * @tag - pointer type tag - * @tags - btf_type_tag annotations for the pointer type - */ -struct btf_type_tag_ptr_type { - struct tag tag; - struct list_head tags; -}; - -static inline struct btf_type_tag_ptr_type *tag__btf_type_tag_ptr(struct tag *tag) +static inline struct llvm_annotation *tag__llvm_annotation(struct tag *tag) { - return (struct btf_type_tag_ptr_type *)tag; -} - -static inline struct btf_type_tag_type *tag__btf_type_tag(struct tag *tag) -{ - return (struct btf_type_tag_type *)tag; + return (struct llvm_annotation *)tag; } /** struct namespace - base class for enums, structs, unions, typedefs, etc @@ -675,7 +663,6 @@ struct namespace { uint16_t nr_tags; uint8_t shared_tags; struct list_head tags; - struct list_head annots; }; static inline struct namespace *tag__namespace(const struct tag *tag) From patchwork Tue Mar 14 23:04:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eduard Zingerman X-Patchwork-Id: 13175116 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 38958C76196 for ; Tue, 14 Mar 2023 23:04:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231172AbjCNXEj (ORCPT ); Tue, 14 Mar 2023 19:04:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40954 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230414AbjCNXEi (ORCPT ); Tue, 14 Mar 2023 19:04:38 -0400 Received: from mail-lf1-x133.google.com (mail-lf1-x133.google.com [IPv6:2a00:1450:4864:20::133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DFD2324129; Tue, 14 Mar 2023 16:04:36 -0700 (PDT) Received: by mail-lf1-x133.google.com with SMTP id d36so22056423lfv.8; Tue, 14 Mar 2023 16:04:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1678835075; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ubRg4GwuSCyuA5dYlB706nezzHSSXG6dO41jC6tYL7o=; b=iNw6xSifYopVxI8ZkAmbCUC0seQH5Ld29Ci53BMmfZuEZvVzcLib5vY3g27sS7IC6D oSjcB8pWU9o6JIktGHAFCPh3kWg1DLZ/UaTyt5AYzWg9rMFZdUkGRiJgTfNVCkgaYN8V WJ130BGkmPv3bBl/cb/JQ1pRoVM9uHcvfEBSWydt0x96oUNAwQpI1rVNnBi3fqYpy+pj SE+hczSxpIL1Fn9gCYlSEPKzkgFfMGjUfkvyo260eenabfzxWMPF3og8VeAJFtKXecUl rGBUKz0wWpyZXSTrJKxWdGBlTdT3Udwwbgx8jJimAJXEYtO+9OCDDybJ+YnnflWPcX7d 7bBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678835075; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ubRg4GwuSCyuA5dYlB706nezzHSSXG6dO41jC6tYL7o=; b=SDU3IjN2pHuKqyCBEw/BvTWAAT5KGE1Z10ne4Kthyoi+/jLEdq3lRXO9zNaRN0Tkj5 s8W29CSx65C0ZSfIVAHGAZfgTnb4iSzGQtxV9Oxx/jm9qZdGR/jL5pp+UK/HF+mOQO9y gCBWqDkWNQfABh16ZTpe0W6oa9kpnffTG3uNCbW3THwixxL6tZENy0VH3fp90WSlTfwo xcKb1pEz7UkfHI3+mrZFUNFqNRecvIExegzHs5EzPnmgqBdaLV/sJ5mlYaIeEmf0NQHD wy+og9GdqcOIAdX57nOP3hdiextIM0tOHOAbQqaNbdT8+UzNlq3OIDgSe9+9Yi2KVtXb i+7g== X-Gm-Message-State: AO0yUKUPdUHsFT0Z8XvuAMHX97nOWsowmrIW5XQWSyplV9aLKYCg+Iuu 4F1EFu13/e+rRNGUj18QvdYz52t9Vix+QsSP X-Google-Smtp-Source: AK7set+3+QNe7Rma6sNYUPczMgQYfpJynMzsO1MxKGi1STP0qWvD/SpOPqzftNdojl0eESqL7FMbLA== X-Received: by 2002:ac2:4a78:0:b0:4e8:49fa:ec1a with SMTP id q24-20020ac24a78000000b004e849faec1amr1161566lfp.51.1678835074855; Tue, 14 Mar 2023 16:04:34 -0700 (PDT) Received: from bigfoot.. (host-176-36-0-241.b024.la.net.ua. [176.36.0.241]) by smtp.gmail.com with ESMTPSA id b1-20020ac25e81000000b004cc7acfbd2bsm569638lfq.287.2023.03.14.16.04.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Mar 2023 16:04:34 -0700 (PDT) From: Eduard Zingerman To: dwarves@vger.kernel.org, arnaldo.melo@gmail.com Cc: bpf@vger.kernel.org, kernel-team@fb.com, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, yhs@fb.com, jose.marchesi@oracle.com, david.faust@oracle.com, alan.maguire@oracle.com, Eduard Zingerman Subject: [PATCH dwarves v2 4/5] dwarf_loader: Track unspecified types in a separate list Date: Wed, 15 Mar 2023 01:04:16 +0200 Message-Id: <20230314230417.1507266-5-eddyz87@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230314230417.1507266-1-eddyz87@gmail.com> References: <20230314230417.1507266-1-eddyz87@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org In recent discussion in BPF mailing list ([1]) participants agreed to add a new DWARF representation for "btf_type_tag" annotations. The agreed representation of void pointers uses unspecified types. For example, consider the following C code: struct alpha { void __attribute__((btf_type_tag("__alpha_a"))) *a; } g; And corresponding DWARF: 0x29: DW_TAG_structure_type DW_AT_name ("alpha") 0x2e: DW_TAG_member DW_AT_name ("a") DW_AT_type (0x38 "void *") 0x38: DW_TAG_pointer_type DW_AT_type (0x41 "void") 0x41: DW_TAG_unspecified_type DW_AT_name ("void") 0x43: DW_TAG_LLVM_annotation DW_AT_name ("btf:type_tag") DW_AT_const_value ("__alpha_a") This is a preparatory patch for new type tags representation support, specifically it adds `struct unspecified_type` and a new `cu` field `struct cu::unspecified_types`. These would be used in a subsequent patch to recode type tags attached to DW_TAG_unspecified_type as in the example above. [1] Mailing list discussion regarding `btf:type_tag` Various approaches are discussed, Solution #2 is accepted https://lore.kernel.org/bpf/87r0w9jjoq.fsf@oracle.com/ Signed-off-by: Eduard Zingerman --- dwarf_loader.c | 36 ++++++++++++++++++++++++++++++++++-- dwarves.c | 1 + dwarves.h | 17 +++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/dwarf_loader.c b/dwarf_loader.c index 17a2773..218806b 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -176,14 +176,19 @@ static struct dwarf_cu *dwarf_cu__new(struct cu *cu) return dwarf_cu; } +static void unspecified_type__delete(struct cu *cu, struct unspecified_type *utype); + static void dwarf_cu__delete(struct cu *cu) { if (cu == NULL || cu->priv == NULL) return; struct dwarf_cu *dcu = cu->priv; + struct list_head *pos, *n; // dcu->hash_tags & dcu->hash_types are on cu->obstack + list_for_each_safe(pos, n, &cu->unspecified_types) + unspecified_type__delete(cu, container_of(pos, struct unspecified_type, node)); cu__free(cu, dcu); cu->priv = NULL; } @@ -1449,6 +1454,33 @@ static struct tag *die__create_new_tag(Dwarf_Die *die, struct cu *cu) return tag; } +static struct tag *die__create_new_unspecified_type(Dwarf_Die *die, struct cu *cu, + struct conf_load *conf) +{ + struct unspecified_type *tag; + + tag = tag__alloc_with_spec(cu, sizeof(struct unspecified_type)); + if (tag == NULL) + return NULL; + + tag__init(&tag->tag, cu, die); + INIT_LIST_HEAD(&tag->node); + + tag->name = attr_string(die, DW_AT_name, conf); + + list_add(&tag->node, &cu->unspecified_types); + + return &tag->tag; +} + +static void unspecified_type__delete(struct cu *cu, struct unspecified_type *utype) +{ + struct dwarf_tag *dtag = utype->tag.priv; + + cu__free(cu, dtag); + cu__free(cu, utype); +} + static struct tag *die__create_new_annotated_tag(Dwarf_Die *die, struct cu *cu, struct conf_load *conf) { @@ -2172,10 +2204,10 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu, case DW_TAG_volatile_type: case DW_TAG_atomic_type: tag = die__create_new_tag(die, cu); break; - case DW_TAG_unspecified_type: - tag = die__create_new_tag(die, cu); break; case DW_TAG_pointer_type: tag = die__create_new_annotated_tag(die, cu, conf); break; + case DW_TAG_unspecified_type: + tag = die__create_new_unspecified_type(die, cu, conf); break; case DW_TAG_ptr_to_member_type: tag = die__create_new_ptr_to_member_type(die, cu); break; case DW_TAG_enumeration_type: diff --git a/dwarves.c b/dwarves.c index b43031c..7e66a98 100644 --- a/dwarves.c +++ b/dwarves.c @@ -681,6 +681,7 @@ struct cu *cu__new(const char *name, uint8_t addr_size, cu->dfops = NULL; INIT_LIST_HEAD(&cu->tags); INIT_LIST_HEAD(&cu->tool_list); + INIT_LIST_HEAD(&cu->unspecified_types); cu->addr_size = addr_size; cu->extra_dbg_info = 0; diff --git a/dwarves.h b/dwarves.h index 0b0b0cc..cbd2913 100644 --- a/dwarves.h +++ b/dwarves.h @@ -242,6 +242,7 @@ struct cu { struct list_head node; struct list_head tags; struct list_head tool_list; /* To be used by tools such as ctracer */ + struct list_head unspecified_types; struct ptr_table types_table; struct ptr_table functions_table; struct ptr_table tags_table; @@ -652,6 +653,22 @@ static inline struct llvm_annotation *tag__llvm_annotation(struct tag *tag) return (struct llvm_annotation *)tag; } +/** struct unspecified_type - representation of DW_TAG_unspecified_type. + * + * @name - DW_AT_name associated with this tag + * @node - a node for cu::unspecified_types list + */ +struct unspecified_type { + struct tag tag; + const char *name; + struct list_head node; +}; + +static inline struct unspecified_type *tag__unspecified_type(struct tag *tag) +{ + return (struct unspecified_type *)tag; +} + /** struct namespace - base class for enums, structs, unions, typedefs, etc * * @tags - class_member, enumerators, etc From patchwork Tue Mar 14 23:04:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eduard Zingerman X-Patchwork-Id: 13175118 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 73F72C7618B for ; Tue, 14 Mar 2023 23:04:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229734AbjCNXEm (ORCPT ); Tue, 14 Mar 2023 19:04:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41020 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230414AbjCNXEl (ORCPT ); Tue, 14 Mar 2023 19:04:41 -0400 Received: from mail-lf1-x12d.google.com (mail-lf1-x12d.google.com [IPv6:2a00:1450:4864:20::12d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 42CC82412B; Tue, 14 Mar 2023 16:04:37 -0700 (PDT) Received: by mail-lf1-x12d.google.com with SMTP id x17so5941292lfu.5; Tue, 14 Mar 2023 16:04:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1678835076; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4b5D46r0egTUZOP7UsIE7L+hvcUSuvgdra47+VJ8O/M=; b=CdFkAwWzsRwvMCd8WeY7vl+PvPWbIQc+CWNkn/kQ+5DUeuVCGAsld4YjenTuCRCYsq ilhRQjiMnsTGt8Q7ydEzxEpEuuJIh0GEgA0bZZs2V57zuEiVZ5GL24tcg2zvfFVNE36s weq7J25zOyWDEYs/Lj/xOddkPfoXxVAhnWYrsFCZSOZwjv5iGxgRgaPuAvvEcMQ1cR5q N0oFVVaa625iwNaeeuICOwKKTJpdt2uDLneESnodyX2Ac4VG2nXz7dAeMafbOCI0uggX QNbvJuKDRUu9ZYwcjiUu92u4Uia04QY7nVRTbA5zX7kZvhWKW5cbEc/T7mtytKHbfLLy 9vxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678835076; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4b5D46r0egTUZOP7UsIE7L+hvcUSuvgdra47+VJ8O/M=; b=phew7ms0QVmFR5x8kZkSl0LQg+8FkPBTtTb9ycHhV9OZoxDskn/6BHgAFp3IJYXzmf OmxylZcajm9ERAfe9go1hiyfzhDm0XJ4zWir7r9ARoAZb8XzlH9ZwayghSggee+hy/VP TAhImRVHVdIhhWtrsTxzqg+D/r9F5nuoiKJnlPfxRjQ78rX+A1wR9a1GIIjdozGEkP+g EdGXHj5KZ8MTgkwh6oxOR3LyHg64YyIkuh+NWf1KGK3t6/kHqGuCPOWo9PM4Orq7Z8vt cuBFKgHfzOIlCnfXZNVO/bqByY9Oi2WY+sn9rZXgCPlR1ktUH9ybcoifHZnMDhtmkZJJ jLwA== X-Gm-Message-State: AO0yUKUQrbbV9UakWU2Ml7XPO6d5TvITlx0DfhUI9sb76bDh9cOLNIB+ dub03F/xtyPxGs9t9QpL+sxCvoLwjJxyApWk X-Google-Smtp-Source: AK7set/9ViMyjOfhX2WZNuHYg3rZG3UEAhDQoDgO/IJCBJNzR82/xYts49JDy+DhxBMG+UqtpvfFHA== X-Received: by 2002:ac2:5927:0:b0:4e8:41fc:b37 with SMTP id v7-20020ac25927000000b004e841fc0b37mr1202243lfi.10.1678835076035; Tue, 14 Mar 2023 16:04:36 -0700 (PDT) Received: from bigfoot.. (host-176-36-0-241.b024.la.net.ua. [176.36.0.241]) by smtp.gmail.com with ESMTPSA id b1-20020ac25e81000000b004cc7acfbd2bsm569638lfq.287.2023.03.14.16.04.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Mar 2023 16:04:35 -0700 (PDT) From: Eduard Zingerman To: dwarves@vger.kernel.org, arnaldo.melo@gmail.com Cc: bpf@vger.kernel.org, kernel-team@fb.com, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, yhs@fb.com, jose.marchesi@oracle.com, david.faust@oracle.com, alan.maguire@oracle.com, Eduard Zingerman Subject: [PATCH dwarves v2 5/5] dwarf_loader: Support for btf:type_tag Date: Wed, 15 Mar 2023 01:04:17 +0200 Message-Id: <20230314230417.1507266-6-eddyz87@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230314230417.1507266-1-eddyz87@gmail.com> References: <20230314230417.1507266-1-eddyz87@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org "btf:type_tag" is an DW_TAG_LLVM_annotation object that encodes btf_type_tag attributes in DWARF. Contrary to existing "btf_type_tag" it allows to associate such attributes with non-pointer types. When "btf:type_tag" is attached to a type it applies to this type. For example the following C code: struct echo { int __attribute__((btf_type_tag("__c"))) c; } Produces the following DWARF: 0x29: DW_TAG_structure_type DW_AT_name ("echo") 0x40: DW_TAG_member DW_AT_name ("c") DW_AT_type (0x8c "int") 0x8c: DW_TAG_base_type DW_AT_name ("int") DW_AT_encoding (DW_ATE_signed) DW_AT_byte_size (0x04) 0x90: DW_TAG_LLVM_annotation DW_AT_name ("btf:type_tag") DW_AT_const_value ("__c") Meaning that type 0x8c is an `int` with type tag `__c`. Corresponding BTF looks as follows: [1] STRUCT 'echo' ... 'c' type_id=8 bits_offset=128 [4] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED [8] TYPE_TAG '__c' type_id=4 This commit adds support for DW_TAG_LLVM_annotation "btf:type_tag" attached to the following entities: - base types; - arrays; - pointers; - structs - unions; - enums; - typedefs. To allow backwards compatibility and void additional invocation options, implementation acts in a following way: - both `btf_type_tag` and `btf:type_tag` could be present in the debug info; - if `btf:type_tag` are present in the debug info, `btf_type_tag` annotations are ignored. Modifications done by this commit: - DWARF load phase is updated: - `annots` fields are filled for the above mentioned types; - `cu` instance is updated to reflect which version of type tags is used in the debug info; - Recode phase is split in several sub-phases: - `cu__allocate_btf_type_tags()` `llvm_annotation` instances corresponding to preferred version of type tags are added to types table; - `tag__recode_dwarf_type()` (the original phase logic); - `update_btf_type_tag_refs()` Updates `->type` field of each tag if that type refers to a type with `btf:type_tag` annotation. The id of the type is replaced by id of the type tag. See also: [1] Mailing list discussion regarding `btf:type_tag` Various approaches are discussed, Solution #2 is accepted https://lore.kernel.org/bpf/87r0w9jjoq.fsf@oracle.com/ Signed-off-by: Eduard Zingerman --- dwarf_loader.c | 530 ++++++++++++++++++++++++++++++++++++++++++++----- dwarves.h | 10 +- 2 files changed, 484 insertions(+), 56 deletions(-) diff --git a/dwarf_loader.c b/dwarf_loader.c index 218806b..fe38c29 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -57,6 +57,36 @@ #define EM_RISCV 243 #endif +/** struct btf_type_tag_mapping - information about btf type tags attached + * to a particular host type. Each field is a small_id of the dwarf tag. + * This information is used to replace references to host type with + * references to first btf type tag during the recode phase. + * + * @host_type_id - type annotated with btf_type_tag annotations + * @first_tag_id - first btf type tag attached to host_type_id + * @last_tag_id - last btf type tag attached to host_type_id + * + */ +struct btf_type_tag_mapping { + uint32_t host_type_id; + uint32_t first_tag_id; + uint32_t last_tag_id; +}; + +/** struct recode_context - information local to recode phase, + * currently only btf type tag mappings. + * + * @mappings - an array of host id to btf type tag mappings, + * dynamically enlarged when new mappings are added; + * @nr_allocated - number of elements allocated for @mappings array; + * @nr_entries - index of the next free entry in the @mappings array. + */ +struct recode_context { + struct btf_type_tag_mapping *mappings; + uint32_t nr_allocated; + uint32_t nr_entries; +}; + static pthread_mutex_t libdw__lock = PTHREAD_MUTEX_INITIALIZER; static uint32_t hashtags__bits = 12; @@ -958,13 +988,16 @@ static int add_btf_type_tag(Dwarf_Die *die, { struct llvm_annotation *annot; const char *name; + bool v1, v2; if (conf->skip_encoding_btf_type_tag) return 0; name = attr_string(die, DW_AT_name, conf); + v1 = strcmp(name, "btf_type_tag") == 0; + v2 = strcmp(name, "btf:type_tag") == 0; - if (strcmp(name, "btf_type_tag") != 0) + if (!v1 && !v2) return 0; /* Create a btf_type_tag type for this annotation. */ @@ -972,11 +1005,11 @@ static int add_btf_type_tag(Dwarf_Die *die, if (annot == NULL) return -ENOMEM; - cu__assign_tag_id(cu, &annot->tag); - - annot->kind = BTF_TYPE_TAG_POINTEE; + annot->kind = v2 ? BTF_TYPE_TAG : BTF_TYPE_TAG_POINTEE; annot->value = attr_string(die, DW_AT_const_value, conf); annot->component_idx = -1; + if (v2) + cu->ignore_btf_type_tag_pointee = 1; /* For a list of DW_TAG_LLVM_annotation like tag1 -> tag2 -> tag3, * the tag->tags contains tag3 -> tag2 -> tag1. @@ -1467,6 +1500,8 @@ static struct tag *die__create_new_unspecified_type(Dwarf_Die *die, struct cu *c INIT_LIST_HEAD(&tag->node); tag->name = attr_string(die, DW_AT_name, conf); + if (add_child_llvm_annotations(die, cu, -1, conf, &tag->tag.annots)) + return NULL; list_add(&tag->node, &cu->unspecified_types); @@ -1564,9 +1599,8 @@ static struct tag *die__create_new_base_type(Dwarf_Die *die, struct cu *cu, stru if (base == NULL) return NULL; - if (dwarf_haschildren(die)) - fprintf(stderr, "%s: DW_TAG_base_type WITH children!\n", - __func__); + if (add_child_llvm_annotations(die, cu, -1, conf, &base->tag.annots)) + return NULL; return &base->tag; } @@ -1584,7 +1618,7 @@ static struct tag *die__create_new_typedef(Dwarf_Die *die, struct cu *cu, struct return &tdef->namespace.tag; } -static struct tag *die__create_new_array(Dwarf_Die *die, struct cu *cu) +static struct tag *die__create_new_array(Dwarf_Die *die, struct cu *cu, struct conf_load *conf) { Dwarf_Die child; /* "64 dimensions will be enough for everybody." acme, 2006 */ @@ -1600,17 +1634,25 @@ static struct tag *die__create_new_array(Dwarf_Die *die, struct cu *cu) die = &child; do { - if (dwarf_tag(die) == DW_TAG_subrange_type) { + switch (dwarf_tag(die)) { + case DW_TAG_subrange_type: nr_entries[array->dimensions++] = attr_upper_bound(die); if (array->dimensions == max_dimensions) { fprintf(stderr, "%s: only %u dimensions are " "supported!\n", __FUNCTION__, max_dimensions); - break; + goto _break; } - } else + break; + case DW_TAG_LLVM_annotation: + if (add_btf_type_tag(die, cu, conf, &array->tag.annots)) + goto out_free; + break; + default: cu__tag_not_handled(die); + } } while (dwarf_siblingof(die, die) == 0); +_break: array->nr_entries = memdup(nr_entries, array->dimensions * sizeof(uint32_t), cu); @@ -1722,6 +1764,10 @@ static struct tag *die__create_new_subroutine_type(Dwarf_Die *die, case DW_TAG_unspecified_parameters: ftype->unspec_parms = 1; continue; + case DW_TAG_LLVM_annotation: + if (add_btf_type_tag(die, cu, conf, &ftype->tag.annots)) + goto out_delete; + continue; default: tag = die__process_tag(die, cu, 0, conf); if (tag == NULL) @@ -1778,17 +1824,25 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu, st die = &child; do { - struct enumerator *enumerator; + switch (dwarf_tag(die)) { + case DW_TAG_enumerator: { + struct enumerator *enumerator; + + enumerator = enumerator__new(die, cu, conf); + if (enumerator == NULL) + goto out_delete; - if (dwarf_tag(die) != DW_TAG_enumerator) { + enumeration__add(enumeration, enumerator); + break; + } + case DW_TAG_LLVM_annotation: + if (add_btf_type_tag(die, cu, conf, + &enumeration->namespace.tag.annots)) + goto out_delete; + break; + default: cu__tag_not_handled(die); - continue; } - enumerator = enumerator__new(die, cu, conf); - if (enumerator == NULL) - goto out_delete; - - enumeration__add(enumeration, enumerator); } while (dwarf_siblingof(die, die) == 0); out: return &enumeration->namespace.tag; @@ -2191,19 +2245,19 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu, case DW_TAG_imported_unit: return NULL; // We don't support imported units yet, so to avoid segfaults case DW_TAG_array_type: - tag = die__create_new_array(die, cu); break; + tag = die__create_new_array(die, cu, conf); break; case DW_TAG_string_type: // FORTRAN stuff, looks like an array tag = die__create_new_string_type(die, cu); break; case DW_TAG_base_type: tag = die__create_new_base_type(die, cu, conf); break; - case DW_TAG_const_type: case DW_TAG_imported_declaration: case DW_TAG_imported_module: case DW_TAG_reference_type: - case DW_TAG_restrict_type: - case DW_TAG_volatile_type: case DW_TAG_atomic_type: tag = die__create_new_tag(die, cu); break; + case DW_TAG_const_type: + case DW_TAG_restrict_type: + case DW_TAG_volatile_type: case DW_TAG_pointer_type: tag = die__create_new_annotated_tag(die, cu, conf); break; case DW_TAG_unspecified_type: @@ -2294,20 +2348,99 @@ static int die__process_unit(Dwarf_Die *die, struct cu *cu, struct conf_load *co return 0; } -static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu); +/** Add @tuple to @ctx->mappings array, extend it if necessary. */ +static int push_btf_type_tag_mapping(struct btf_type_tag_mapping *tuple, + struct recode_context *ctx) +{ + if (ctx->nr_allocated == ctx->nr_entries) { + uint32_t new_nr = ctx->nr_allocated * 2; + void *new_array = realloc(ctx->mappings, new_nr * sizeof(ctx->mappings[0])); + if (!new_array) + return -ENOMEM; + ctx->mappings = new_array; + ctx->nr_allocated = new_nr; + } + + ctx->mappings[ctx->nr_entries++] = *tuple; -static int namespace__recode_dwarf_types(struct tag *tag, struct cu *cu) + return 0; +} + +/** Connect `type` fields of btf:type_tag annotations attached to a + * host type. Collect information about first and last tag. + * `type` field are connected as below: + * + * tag1.type -> tag2.type -> host_type + * + * @tags - list of llvm_annotation objects; + * @host_type - small_id of the type with attached annotations. + */ +static void __recode_btf_type_tags(struct list_head *tags, + uint32_t host_type, + struct btf_type_tag_mapping *mapping) +{ + struct llvm_annotation *annot; + struct dwarf_tag *annot_dtag; + struct tag *prev_tag = NULL; + uint32_t first_tag_id = 0; + + list_for_each_entry(annot, tags, node) { + if (annot->kind != BTF_TYPE_TAG) + continue; + annot_dtag = annot->tag.priv; + if (prev_tag) + prev_tag->type = annot_dtag->small_id; + if (!first_tag_id) + first_tag_id = annot_dtag->small_id; + prev_tag = &annot->tag; + } + + mapping->host_type_id = host_type; + if (prev_tag) { + prev_tag->type = host_type; + mapping->first_tag_id = first_tag_id; + mapping->last_tag_id = annot_dtag->small_id; + } else { + mapping->first_tag_id = 0; + mapping->last_tag_id = 0; + } +} + +static int recode_btf_type_tags(struct list_head *tags, + uint32_t host_type, + struct recode_context *ctx) +{ + struct btf_type_tag_mapping mapping; + + if (list_empty(tags)) + return 0; + + __recode_btf_type_tags(tags, host_type, &mapping); + if (!mapping.first_tag_id) + return 0; + + return push_btf_type_tag_mapping(&mapping, ctx); +} + +static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu, + struct recode_context *ctx); + +static int namespace__recode_dwarf_types(struct tag *tag, struct cu *cu, + struct recode_context *ctx) { struct tag *pos; struct dwarf_cu *dcu = cu->priv; + struct dwarf_tag *dtag = tag->priv; struct namespace *ns = tag__namespace(tag); + recode_btf_type_tags(&tag->annots, dtag->small_id, ctx); + namespace__for_each_tag(ns, pos) { struct dwarf_tag *dtype; struct dwarf_tag *dpos = pos->priv; if (tag__has_namespace(pos)) { - if (namespace__recode_dwarf_types(pos, cu)) + if (namespace__recode_dwarf_types(pos, cu, ctx)) return -1; continue; } @@ -2328,7 +2461,7 @@ static int namespace__recode_dwarf_types(struct tag *tag, struct cu *cu) break; case DW_TAG_subroutine_type: case DW_TAG_subprogram: - ftype__recode_dwarf_types(pos, cu); + ftype__recode_dwarf_types(pos, cu, ctx); break; case DW_TAG_imported_module: dtype = dwarf_cu__find_tag_by_ref(dcu, &dpos->type); @@ -2393,7 +2526,8 @@ static void __tag__print_abstract_origin_not_found(struct tag *tag, #define tag__print_abstract_origin_not_found(tag ) \ __tag__print_abstract_origin_not_found(tag, __func__) -static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu) +static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu, + struct recode_context *ctx) { struct parameter *pos; struct dwarf_cu *dcu = cu->priv; @@ -2441,9 +2575,13 @@ static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu) } pos->tag.type = dtype->small_id; } + + struct dwarf_tag *dtag = tag->priv; + recode_btf_type_tags(&tag->annots, dtag->small_id, ctx); } -static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu) +static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu, + struct recode_context *ctx) { struct tag *pos; struct dwarf_cu *dcu = cu->priv; @@ -2454,7 +2592,7 @@ static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu) switch (pos->tag) { case DW_TAG_lexical_block: - lexblock__recode_dwarf_types(tag__lexblock(pos), cu); + lexblock__recode_dwarf_types(tag__lexblock(pos), cu, ctx); continue; case DW_TAG_inlined_subroutine: if (dpos->type.off != 0) @@ -2468,7 +2606,7 @@ static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu) tag__print_abstract_origin_not_found(pos); continue; } - ftype__recode_dwarf_types(dtype->tag, cu); + ftype__recode_dwarf_types(dtype->tag, cu, ctx); continue; case DW_TAG_formal_parameter: @@ -2535,8 +2673,144 @@ static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu) } } +static int recode_context_init(struct recode_context *ctx) +{ + const int initial_nr = 16; + + ctx->mappings = reallocarray(NULL, initial_nr, sizeof(ctx->mappings[0])); + if (!ctx->mappings) + return -ENOMEM; + + ctx->nr_allocated = initial_nr; + ctx->nr_entries = 0; + + return 0; +} + +static void recode_context_free(struct recode_context *ctx) +{ + free(ctx->mappings); + ctx->nr_allocated = 0; + ctx->nr_entries = 0; +} + +/** Compare two `btf_type_tag_mapping` objects using host_type_id as key. */ +static int compare_btf_type_tag_recode_mappings(const void *_a, const void *_b) +{ + const struct btf_type_tag_mapping *a = _a; + const struct btf_type_tag_mapping *b = _b; + long diff = (long)a->host_type_id - (long)b->host_type_id; + + if (diff < 0) + return -1; + if (diff > 0) + return 1; + return 0; +} + +/** Sort @ctx->mappings array by btf_type_tag_mapping::host_type_id, + * function `lookup_btf_type_tag_by_host()` uses binary search to find + * elements of this array. + */ +static void sort_btf_type_tags(struct recode_context *ctx) +{ + qsort(ctx->mappings, ctx->nr_entries, sizeof(ctx->mappings[0]), + compare_btf_type_tag_recode_mappings); +} + +static struct btf_type_tag_mapping *lookup_btf_type_tag_by_host(uint32_t host_type_id, + struct recode_context *ctx) +{ + struct btf_type_tag_mapping key = { .host_type_id = host_type_id }; + + return bsearch(&key, ctx->mappings, ctx->nr_entries, sizeof(key), + compare_btf_type_tag_recode_mappings); +} + +/** Update @tag->type fields by replacing types by ids of associated + * btf:type_tag objects. @ctx->mappings should be sorted when this + * function is called. + * + * When "btf:type_tag" is attached to a type it applies to this type. + * For example, the following dwarf: + * + * 0x00000040: DW_TAG_member + * DW_AT_name ("c") + * DW_AT_type (0x0000008c "int") + * DW_AT_decl_file ("/home/eddy/work/tmp/test.c") + * DW_AT_decl_line (13) + * DW_AT_data_member_location (0x10) + * + * 0x0000008c: DW_TAG_base_type + * DW_AT_name ("int") + * DW_AT_encoding (DW_ATE_signed) + * DW_AT_byte_size (0x04) + * + * 0x00000090: DW_TAG_LLVM_annotation + * DW_AT_name ("btf:type_tag") + * DW_AT_const_value ("__c") + * + * Means that type 0x0000008c is an `int` with type tag `__c`. + * Corresponding BTF looks as follows: + * + * [1] STRUCT 'echo' + * ... + * 'c' type_id=8 bits_offset=128 + * [4] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED + * [8] TYPE_TAG '__c' type_id=4 + * + * Before the call to `update_btf_type_tag_refs` for member 0x00000040 + * its `type` field points to 0x0000008c. `update_btf_type_tag_refs` + * updates this link to point to `0x00000090` instead, thus obtaining the + * desired BTF shape. + */ +static int update_btf_type_tag_refs(struct tag *tag, + struct cu *cu, + struct recode_context *ctx) +{ + struct btf_type_tag_mapping *tuple; + struct dwarf_tag *dtag = tag->priv; + + /* Kernel does not support VAR entries with types of form + * 'VAR -> TYPE_TAG -> something': + * - in verifier.c:check_pseudo_btf_id() instruction auxiliary + * data is set to point to variable type w/o stripping modifiers; + * - btf.c:btf_struct_access() -> btf.c:btf_struct_walk() + * does not skip modifiers prior to btf_type_is_struct() check. + * + * So, skip type tag recoding for variables. + */ + if (tag->tag == DW_TAG_variable) + return 0; + + tuple = lookup_btf_type_tag_by_host(tag->type, ctx); + /* Avoid creation of circular references, last btf:type_tag + * object points to the host type. + */ + if (tuple && tuple->last_tag_id != dtag->small_id) + tag->type = tuple->first_tag_id; + + if (tag__is_type(tag)) { + struct type *type = tag__type(tag); + struct class_member *pos; + + type__for_each_data_member(type, pos) + update_btf_type_tag_refs(&pos->tag, cu, ctx); + } else if (tag->tag == DW_TAG_subprogram || + tag->tag == DW_TAG_subroutine_type) { + struct ftype *ftype = tag__ftype(tag); + struct parameter *pos; + + ftype__for_each_parameter(ftype, pos) + update_btf_type_tag_refs(&pos->tag, cu, ctx); + } + + return 0; +} + static void dwarf_cu__recode_btf_type_tag_ptr(struct tag *tag, - uint32_t pointee_type) + uint32_t pointee_type, + struct cu *cu) { struct llvm_annotation *annot; struct dwarf_tag *annot_dtag; @@ -2566,15 +2840,19 @@ static void dwarf_cu__recode_btf_type_tag_ptr(struct tag *tag, * and this matches the user/kernel code. */ prev_tag = tag; - list_for_each_entry(annot, &tag->annots, node) { - annot_dtag = annot->tag.priv; - prev_tag->type = annot_dtag->small_id; - prev_tag = &annot->tag; + if (!cu->ignore_btf_type_tag_pointee) { + list_for_each_entry(annot, &tag->annots, node) { + if (annot->kind != BTF_TYPE_TAG_POINTEE) + continue; + annot_dtag = annot->tag.priv; + prev_tag->type = annot_dtag->small_id; + prev_tag = &annot->tag; + } } prev_tag->type = pointee_type; } -static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu) +static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu, struct recode_context *ctx) { struct dwarf_tag *dtag = tag->priv; struct dwarf_tag *dtype; @@ -2587,7 +2865,7 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu) type__recode_dwarf_specification(tag, cu); if (tag__has_namespace(tag)) - return namespace__recode_dwarf_types(tag, cu); + return namespace__recode_dwarf_types(tag, cu, ctx); switch (tag->tag) { case DW_TAG_subprogram: { @@ -2619,17 +2897,17 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu) (unsigned long long)specification.off); } } - lexblock__recode_dwarf_types(&fn->lexblock, cu); + lexblock__recode_dwarf_types(&fn->lexblock, cu, ctx); } /* Fall thru */ case DW_TAG_subroutine_type: - ftype__recode_dwarf_types(tag, cu); + ftype__recode_dwarf_types(tag, cu, ctx); /* Fall thru, for the function return type */ break; case DW_TAG_lexical_block: - lexblock__recode_dwarf_types(tag__lexblock(tag), cu); + lexblock__recode_dwarf_types(tag__lexblock(tag), cu, ctx); return 0; case DW_TAG_ptr_to_member_type: { @@ -2650,7 +2928,7 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu) break; case DW_TAG_namespace: - return namespace__recode_dwarf_types(tag, cu); + return namespace__recode_dwarf_types(tag, cu, ctx); /* Damn, DW_TAG_inlined_subroutine is an special case as dwarf_tag->id is in fact an abtract origin, i.e. must be looked up in the tags_table, not in the types_table. @@ -2684,11 +2962,13 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu) return 0; } + recode_btf_type_tags(&tag->annots, dtag->small_id, ctx); + if (dtag->type.off == 0) { if (tag->tag != DW_TAG_pointer_type) tag->type = 0; /* void */ else - dwarf_cu__recode_btf_type_tag_ptr(tag, 0); + dwarf_cu__recode_btf_type_tag_ptr(tag, 0, cu); return 0; } @@ -2703,7 +2983,7 @@ out: if (tag->tag != DW_TAG_pointer_type) tag->type = dtype->small_id; else - dwarf_cu__recode_btf_type_tag_ptr(tag, dtype->small_id); + dwarf_cu__recode_btf_type_tag_ptr(tag, dtype->small_id, cu); return 0; } @@ -2788,28 +3068,168 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu) return 0; } -static int cu__recode_dwarf_types_table(struct cu *cu, - struct ptr_table *pt, - uint32_t i) +typedef int (*recode_tag_visitor)(struct tag *, struct cu*, struct recode_context *); + +static int cu__visit_all_tags(struct cu *cu, recode_tag_visitor fn, struct recode_context *ctx) { - for (; i < pt->nr_entries; ++i) { - struct tag *tag = pt->entries[i]; + const int nr_tables = 3; + struct { + struct ptr_table *table; + uint32_t start_idx; + } tables[] = { + { &cu->types_table, 1 }, + { &cu->tags_table, 0 }, + { &cu->functions_table, 0 } + }; + struct ptr_table *pt; + struct tag *tag; + uint32_t i, t; - if (tag != NULL) /* void, see cu__new */ - if (tag__recode_dwarf_type(tag, cu)) + for (t = 0; t < nr_tables; ++t) { + pt = tables[t].table; + for (i = tables[t].start_idx; i < pt->nr_entries; ++i) { + tag = pt->entries[i]; + if (!tag) /* void, see cu__new */ + continue; + if (fn(tag, cu, ctx)) return -1; + } + } + + return 0; +} + +/* See comment for cu__allocate_btf_type_tags() below. */ +static int tag__allocate_btf_type_tags(struct tag *tag, struct cu *cu) +{ + enum annotation_kind target = cu->ignore_btf_type_tag_pointee + ? BTF_TYPE_TAG + : BTF_TYPE_TAG_POINTEE; + struct list_head *annots = &tag->annots; + struct llvm_annotation *annot; + + list_for_each_entry(annot, annots, node) { + if (annot->kind != target) + continue; + + int err = cu__assign_tag_id(cu, &annot->tag); + if (err) + return err; } return 0; } +/* The flag `cu->ignore_btf_type_tag_pointee` is set at DWARF load phase. + * Before it is set it is not known what kind of type tags is used in + * the program, BTF_TYPE_TAG or BTF_TYPE_TAG_POINTEE. + * It is necessary to allocate only a single kind of tags to avoid + * spurious entries in the type table (and resultant BTF). + * Thus, the allocation of type tags is done as a separate step. + */ +static int cu__allocate_btf_type_tags(struct cu *cu) +{ + struct unspecified_type *utype; + struct tag *pos; + uint32_t id; + int err = 0; + + cu__for_each_type(cu, id, pos) { + err = tag__allocate_btf_type_tags(pos, cu); + if (err) + return err; + } + + list_for_each_entry(utype, &cu->unspecified_types, node) { + err = tag__allocate_btf_type_tags(&utype->tag, cu); + if (err) + return err; + } + + return err; +} + +/* `btf:type_tag` tags have special representation, when attached to void type. + * For example, DWARF for the following C code: + * + * struct st { + * void __attribute__(btf_type_tag("__d")) *d; + * } + * + * Looks as follows: + * + * 0x29: DW_TAG_structure_type + * DW_AT_name ("st") + * + * 0x49: DW_TAG_member + * DW_AT_name ("d") + * DW_AT_type (0xa6 "void *") + * + * 0xa6: DW_TAG_pointer_type + * DW_AT_type (0xaf "void") + * + * 0xaf: DW_TAG_unspecified_type + * DW_AT_name ("void") + * + * 0xb1: DW_TAG_LLVM_annotation + * DW_AT_name ("btf:type_tag") + * DW_AT_const_value ("__d") + * + * Here `void` type is encoded as `DW_TAG_unspecified_type` with + * `DW_TAG_LLVM_annotation` children. + * + * This function replaces `small_id` of the unspecified type (0xaf) with + * `small_id` of the first `btf:type_tag` annotation (0xb1). + * Thus further recode passes will use id of the type tag in place of the + * unspecified type id, when references to unspecified type are resolved. + */ +static void cu__recode_unspecified_types(struct cu *cu) +{ + struct btf_type_tag_mapping mapping; + struct unspecified_type *utype; + struct dwarf_tag *dtag; + + list_for_each_entry(utype, &cu->unspecified_types, node) { + __recode_btf_type_tags(&utype->tag.annots, 0, &mapping); + dtag = utype->tag.priv; + dtag->small_id = mapping.first_tag_id; + } +} + static int cu__recode_dwarf_types(struct cu *cu) { - if (cu__recode_dwarf_types_table(cu, &cu->types_table, 1) || - cu__recode_dwarf_types_table(cu, &cu->tags_table, 0) || - cu__recode_dwarf_types_table(cu, &cu->functions_table, 0)) + struct recode_context ctx = {}; + int err = 0; + + if (recode_context_init(&ctx)) return -1; - return 0; + + if (cu__allocate_btf_type_tags(cu)) { + err = -1; + goto cleanup; + } + + cu__recode_unspecified_types(cu); + + if (cu__visit_all_tags(cu, tag__recode_dwarf_type, &ctx)) { + err = -1; + goto cleanup; + } + + /* No need for second pass if there are no btf type tags */ + if (ctx.nr_entries == 0) + goto cleanup; + + sort_btf_type_tags(&ctx); + + if (cu__visit_all_tags(cu, update_btf_type_tag_refs, &ctx)) { + err = -1; + goto cleanup; + } + +cleanup: + recode_context_free(&ctx); + return err; } static const char *dwarf_tag__decl_file(const struct tag *tag, diff --git a/dwarves.h b/dwarves.h index cbd2913..fa95267 100644 --- a/dwarves.h +++ b/dwarves.h @@ -261,6 +261,10 @@ struct cu { uint8_t has_addr_info:1; uint8_t uses_global_strings:1; uint8_t little_endian:1; + /* When set means that "btf:type_tags" annotations are present + * and "btf_type_tags" annotations should be ignored during export. + */ + uint8_t ignore_btf_type_tag_pointee:1; uint8_t nr_register_params; int register_params[ARCH_MAX_REGISTER_PARAMS]; uint16_t language; @@ -628,8 +632,12 @@ static inline struct ptr_to_member_type * enum annotation_kind { BTF_DECL_TAG, - /* "btf_type_tag" in DWARF, attached to a pointer, applies to pointee type */ + /* "btf_type_tag" in DWARF, attached to a pointer, applies to pointee type. + * Old-style encoding kept for backwards compatibility. + */ BTF_TYPE_TAG_POINTEE, + /* "btf:type_tag" in DWARF, attached to any type, applies to parent type */ + BTF_TYPE_TAG, }; /** struct llvm_annotation - representing objects with DW_TAG_LLVM_annotation tag