From patchwork Mon Jan 30 14:29:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Maguire X-Patchwork-Id: 13121264 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 4B322C54EAA for ; Mon, 30 Jan 2023 14:32:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237851AbjA3OcS (ORCPT ); Mon, 30 Jan 2023 09:32:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49534 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237713AbjA3Ob7 (ORCPT ); Mon, 30 Jan 2023 09:31:59 -0500 Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 77DF4BB9F for ; Mon, 30 Jan 2023 06:30:25 -0800 (PST) Received: from pps.filterd (m0246632.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30UASxid001079; Mon, 30 Jan 2023 14:29:59 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2022-7-12; bh=Dgj+CIPZYQHPwtT05ckoOq3krno492UqoPCTKdX4El0=; b=lg7tlKvCayabXcKeGw7scsD7q2/jef5+YVCimK/gZNNJKX//akUOGGVMi9Rm8RU7KO/m EnQDJX1Irlsb4Xxm9NP48n2PHH+UoSxJNkZCl5h57yQXnl311ES8PeeBf63VQWQrJ+g+ OH4LvkhM1DPziH+J/a7KjtX3tkxKm+rzhUN1wAT0+yqcfHOMoEKzzIRcKqiWbOiU8i2L G2Cg4Uy8X2PulHBcLHd6vTFdUK5CzkqjiiyvcP0KwYWsRn/fLgYIcPktwj4eOVqP5eJR plXeSITx0r1+afrOWEGomY/HwmyWROCkLXewF+zX2+XCFrOAnVB3JAtPPDc/svIvK7jr lQ== Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.appoci.oracle.com [138.1.114.2]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3ncvmhjyr4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 30 Jan 2023 14:29:59 +0000 Received: from pps.filterd (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.5/8.17.1.5) with ESMTP id 30UDumMF000778; Mon, 30 Jan 2023 14:29:58 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3nct5462r5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 30 Jan 2023 14:29:58 +0000 Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 30UETrIr020648; Mon, 30 Jan 2023 14:29:57 GMT Received: from myrouter.uk.oracle.com (dhcp-10-175-214-73.vpn.oracle.com [10.175.214.73]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3nct5462kh-2; Mon, 30 Jan 2023 14:29:57 +0000 From: Alan Maguire To: acme@kernel.org, yhs@fb.com, ast@kernel.org, olsajiri@gmail.com, eddyz87@gmail.com, sinquersw@gmail.com, timo@incline.eu Cc: daniel@iogearbox.net, andrii@kernel.org, songliubraving@fb.com, john.fastabend@gmail.com, kpsingh@chromium.org, sdf@google.com, haoluo@google.com, martin.lau@kernel.org, bpf@vger.kernel.org, Alan Maguire Subject: [PATCH v2 dwarves 1/5] dwarves: help dwarf loader spot functions with optimized-out parameters Date: Mon, 30 Jan 2023 14:29:41 +0000 Message-Id: <1675088985-20300-2-git-send-email-alan.maguire@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1675088985-20300-1-git-send-email-alan.maguire@oracle.com> References: <1675088985-20300-1-git-send-email-alan.maguire@oracle.com> X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-30_13,2023-01-30_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 adultscore=0 malwarescore=0 spamscore=0 phishscore=0 mlxlogscore=999 suspectscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301300140 X-Proofpoint-ORIG-GUID: cff2YXSJEhYGzuMQKbxZOfBsVegGRLKC X-Proofpoint-GUID: cff2YXSJEhYGzuMQKbxZOfBsVegGRLKC Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org Compilation generates DWARF at several stages, and often the later DWARF representations more accurately represent optimizations that have occurred during compilation. In particular, parameter representations can be spotted by their abstract origin references to the original parameter, but they often have more accurate location information. In most cases, the parameter locations will match calling conventions, and be registers for the first 6 parameters on x86_64, first 8 on ARM64 etc. If the parameter is not a register when it should be however, it is likely passed via the stack or the compiler has used a constant representation instead. The latter can often be spotted by checking for a DW_AT_const_value attribute, as noted by Eduard. In addition, absence of a location tag (either across the abstract origin reference and the original parameter, or in the standalone parameter description) is evidence of an optimized-out parameter. Presence of a location tag is stored in the parameter description and shared between abstract tags and their original referents. This change adds a field to parameters and their associated ftype to note if a parameter has been optimized out. Having this information allows us to skip such functions, as their presence in CUs makes BTF encoding impossible. Signed-off-by: Alan Maguire --- dwarf_loader.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- dwarves.h | 5 ++- 2 files changed, 122 insertions(+), 8 deletions(-) diff --git a/dwarf_loader.c b/dwarf_loader.c index 5a74035..93c2307 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -992,13 +992,98 @@ static struct class_member *class_member__new(Dwarf_Die *die, struct cu *cu, return member; } -static struct parameter *parameter__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf) +/* How many function parameters are passed via registers? Used below in + * determining if an argument has been optimized out or if it is simply + * an argument > NR_REGISTER_PARAMS. Setting NR_REGISTER_PARAMS to 0 + * allows unsupported architectures to skip tagging optimized-out + * values. + */ +#if defined(__x86_64__) +#define NR_REGISTER_PARAMS 6 +#elif defined(__s390__) +#define NR_REGISTER_PARAMS 5 +#elif defined(__aarch64__) +#define NR_REGISTER_PARAMS 8 +#elif defined(__mips__) +#define NR_REGISTER_PARAMS 8 +#elif defined(__powerpc__) +#define NR_REGISTER_PARAMS 8 +#elif defined(__sparc__) +#define NR_REGISTER_PARAMS 6 +#elif defined(__riscv) && __riscv_xlen == 64 +#define NR_REGISTER_PARAMS 8 +#elif defined(__arc__) +#define NR_REGISTER_PARAMS 8 +#else +#define NR_REGISTER_PARAMS 0 +#endif + +static struct parameter *parameter__new(Dwarf_Die *die, struct cu *cu, + struct conf_load *conf, int param_idx) { struct parameter *parm = tag__alloc(cu, sizeof(*parm)); if (parm != NULL) { + bool has_const_value; + Dwarf_Attribute attr; + struct location loc; + tag__init(&parm->tag, cu, die); parm->name = attr_string(die, DW_AT_name, conf); + + if (param_idx >= NR_REGISTER_PARAMS) + return parm; + /* Parameters which use DW_AT_abstract_origin to point at + * the original parameter definition (with no name in the DIE) + * are the result of later DWARF generation during compilation + * so often better take into account if arguments were + * optimized out. + * + * By checking that locations for parameters that are expected + * to be passed as registers are actually passed as registers, + * we can spot optimized-out parameters. + * + * It can also be the case that a parameter DIE has + * a constant value attribute reflecting optimization or + * has no location attribute. + * + * From the DWARF spec: + * + * "4.1.10 + * + * A DW_AT_const_value attribute for an entry describing a + * variable or formal parameter whose value is constant and not + * represented by an object in the address space of the program, + * or an entry describing a named constant. (Note + * that such an entry does not have a location attribute.)" + * + * So we can also use the absence of a location for a parameter + * as evidence it has been optimized out. This info will + * need to be shared between a parameter and any abstract + * origin references however, since gcc can have location + * information in the parameter that refers back to the original + * via abstract origin, so we need to share location presence + * between these parameter representations. See + * ftype__recode_dwarf_types() below for how this is handled. + */ + parm->has_loc = dwarf_attr(die, DW_AT_location, &attr) != NULL; + has_const_value = dwarf_attr(die, DW_AT_const_value, &attr) != NULL; + if (parm->has_loc && + attr_location(die, &loc.expr, &loc.exprlen) == 0 && + loc.exprlen != 0) { + Dwarf_Op *expr = loc.expr; + + switch (expr->atom) { + case DW_OP_reg1 ... DW_OP_reg31: + case DW_OP_breg0 ... DW_OP_breg31: + break; + default: + parm->optimized = 1; + break; + } + } else if (has_const_value) { + parm->optimized = 1; + } } return parm; @@ -1450,7 +1535,7 @@ static struct tag *die__create_new_parameter(Dwarf_Die *die, struct cu *cu, struct conf_load *conf, int param_idx) { - struct parameter *parm = parameter__new(die, cu, conf); + struct parameter *parm = parameter__new(die, cu, conf, param_idx); if (parm == NULL) return NULL; @@ -2194,6 +2279,7 @@ static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu) ftype__for_each_parameter(type, pos) { struct dwarf_tag *dpos = pos->tag.priv; + struct parameter *opos; struct dwarf_tag *dtype; if (dpos->type.off == 0) { @@ -2207,8 +2293,18 @@ static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu) tag__print_abstract_origin_not_found(&pos->tag); continue; } - pos->name = tag__parameter(dtype->tag)->name; + opos = tag__parameter(dtype->tag); + pos->name = opos->name; pos->tag.type = dtype->tag->type; + /* share location information between parameter and + * abstract origin; if neither have location, we will + * mark the parameter as optimized out. + */ + if (pos->has_loc) + opos->has_loc = pos->has_loc; + + if (pos->optimized) + opos->optimized = pos->optimized; continue; } @@ -2478,18 +2574,33 @@ out: return 0; } -static int cu__resolve_func_ret_types(struct cu *cu) +static int cu__resolve_func_ret_types_optimized(struct cu *cu) { struct ptr_table *pt = &cu->functions_table; uint32_t i; for (i = 0; i < pt->nr_entries; ++i) { struct tag *tag = pt->entries[i]; + struct parameter *pos; + struct function *fn = tag__function(tag); + + /* mark function as optimized if parameter is, or + * if parameter does not have a location; at this + * point location presence has been marked in + * abstract origins for cases where a parameter + * location is not stored in the original function + * parameter tag. + */ + ftype__for_each_parameter(&fn->proto, pos) { + if (pos->optimized || !pos->has_loc) { + fn->proto.optimized_parms = 1; + break; + } + } if (tag == NULL || tag->type != 0) continue; - struct function *fn = tag__function(tag); if (!fn->abstract_origin) continue; @@ -2612,7 +2723,7 @@ static int die__process_and_recode(Dwarf_Die *die, struct cu *cu, struct conf_lo if (ret != 0) return ret; - return cu__resolve_func_ret_types(cu); + return cu__resolve_func_ret_types_optimized(cu); } static int class_member__cache_byte_size(struct tag *tag, struct cu *cu, @@ -3132,7 +3243,7 @@ static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf, * encoded in another subprogram through abstract_origin * tag. Let us visit all subprograms again to resolve this. */ - if (cu__resolve_func_ret_types(cu) != LSK__KEEPIT) + if (cu__resolve_func_ret_types_optimized(cu) != LSK__KEEPIT) goto out_abort; if (cus__finalize(cus, cu, conf, NULL) == LSK__STOP_LOADING) diff --git a/dwarves.h b/dwarves.h index 589588e..2723466 100644 --- a/dwarves.h +++ b/dwarves.h @@ -808,6 +808,8 @@ size_t lexblock__fprintf(const struct lexblock *lexblock, const struct cu *cu, struct parameter { struct tag tag; const char *name; + uint8_t optimized:1; + uint8_t has_loc:1; }; static inline struct parameter *tag__parameter(const struct tag *tag) @@ -827,7 +829,8 @@ struct ftype { struct tag tag; struct list_head parms; uint16_t nr_parms; - uint8_t unspec_parms; /* just one bit is needed */ + uint8_t unspec_parms:1; /* just one bit is needed */ + uint8_t optimized_parms:1; }; static inline struct ftype *tag__ftype(const struct tag *tag) From patchwork Mon Jan 30 14:29:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Maguire X-Patchwork-Id: 13121266 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 1DCD6C636CB for ; Mon, 30 Jan 2023 14:32:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237789AbjA3OcU (ORCPT ); Mon, 30 Jan 2023 09:32:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54066 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237179AbjA3OcB (ORCPT ); Mon, 30 Jan 2023 09:32:01 -0500 Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4D8646598 for ; Mon, 30 Jan 2023 06:30:27 -0800 (PST) Received: from pps.filterd (m0246632.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30UASxif001079; Mon, 30 Jan 2023 14:30:03 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2022-7-12; bh=7LgsJ6E+xYUz1trfwI2/26h1pwL/Z6t4PUaJSu4v7vU=; b=qELFyhBQYAxn5TPW3/wyMBohCcDjo1lp3kkYdlQ99e0HPSiMIx4y560sJmm6tRDXEGdP I005g+loCuw/kmhWF818htuPAy0X9j2cqjLY+21LoKFRwj5reaWblqKxqOChUf1NGWzg 4B9syBrq6Auk1/R0is2upJyz60hBNvXKJcjxywG2TYQT57N2cpMcvrQyy51BsebEXdKA JBbyEWqVPWVnmNyoS5ZPPCDbtgbgvQTDrCNILEhkkK2VLxpM7gVPV7Gt2B7V1fI/Rk2B 3YdC32VNcaVzWNT443k4SDuO2k6/G7ybNZlAzK3ehhsx9WUutEQvV+J9U4SwTs+sMDmx QQ== Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.appoci.oracle.com [138.1.114.2]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3ncvmhjyrg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 30 Jan 2023 14:30:03 +0000 Received: from pps.filterd (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.5/8.17.1.5) with ESMTP id 30UE3nxx000649; Mon, 30 Jan 2023 14:30:02 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3nct5462ut-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 30 Jan 2023 14:30:02 +0000 Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 30UETrIt020648; Mon, 30 Jan 2023 14:30:01 GMT Received: from myrouter.uk.oracle.com (dhcp-10-175-214-73.vpn.oracle.com [10.175.214.73]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3nct5462kh-3; Mon, 30 Jan 2023 14:30:01 +0000 From: Alan Maguire To: acme@kernel.org, yhs@fb.com, ast@kernel.org, olsajiri@gmail.com, eddyz87@gmail.com, sinquersw@gmail.com, timo@incline.eu Cc: daniel@iogearbox.net, andrii@kernel.org, songliubraving@fb.com, john.fastabend@gmail.com, kpsingh@chromium.org, sdf@google.com, haoluo@google.com, martin.lau@kernel.org, bpf@vger.kernel.org, Alan Maguire Subject: [PATCH v2 dwarves 2/5] btf_encoder: refactor function addition into dedicated btf_encoder__add_func Date: Mon, 30 Jan 2023 14:29:42 +0000 Message-Id: <1675088985-20300-3-git-send-email-alan.maguire@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1675088985-20300-1-git-send-email-alan.maguire@oracle.com> References: <1675088985-20300-1-git-send-email-alan.maguire@oracle.com> X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-30_13,2023-01-30_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 adultscore=0 malwarescore=0 spamscore=0 phishscore=0 mlxlogscore=999 suspectscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301300140 X-Proofpoint-ORIG-GUID: p0RrQDSJK_PGMfufzV1IT568yyA54AQN X-Proofpoint-GUID: p0RrQDSJK_PGMfufzV1IT568yyA54AQN Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org This will be useful for postponing local function addition later on. As part of this, store the type id offset and unspecified type in the encoder, as this will simplify late addition of local functions. Signed-off-by: Alan Maguire --- btf_encoder.c | 101 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/btf_encoder.c b/btf_encoder.c index a5fa04a..44f1905 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -54,6 +54,8 @@ struct btf_encoder { struct gobuffer percpu_secinfo; const char *filename; struct elf_symtab *symtab; + uint32_t type_id_off; + uint32_t unspecified_type; bool has_index_type, need_index_type, skip_encoding_vars, @@ -593,20 +595,20 @@ static int32_t btf_encoder__add_func_param(struct btf_encoder *encoder, const ch } } -static int32_t btf_encoder__tag_type(struct btf_encoder *encoder, uint32_t type_id_off, uint32_t tag_type) +static int32_t btf_encoder__tag_type(struct btf_encoder *encoder, uint32_t tag_type) { if (tag_type == 0) return 0; - if (encoder->cu->unspecified_type.tag && tag_type == encoder->cu->unspecified_type.type) { + if (tag_type == encoder->unspecified_type) { // No provision for encoding this, turn it into void. return 0; } - return type_id_off + tag_type; + return encoder->type_id_off + tag_type; } -static int32_t btf_encoder__add_func_proto(struct btf_encoder *encoder, struct ftype *ftype, uint32_t type_id_off) +static int32_t btf_encoder__add_func_proto(struct btf_encoder *encoder, struct ftype *ftype) { struct btf *btf = encoder->btf; const struct btf_type *t; @@ -616,7 +618,7 @@ static int32_t btf_encoder__add_func_proto(struct btf_encoder *encoder, struct f /* add btf_type for func_proto */ nr_params = ftype->nr_parms + (ftype->unspec_parms ? 1 : 0); - type_id = btf_encoder__tag_type(encoder, type_id_off, ftype->tag.type); + type_id = btf_encoder__tag_type(encoder, ftype->tag.type); id = btf__add_func_proto(btf, type_id); if (id > 0) { @@ -634,7 +636,7 @@ static int32_t btf_encoder__add_func_proto(struct btf_encoder *encoder, struct f ftype__for_each_parameter(ftype, param) { const char *name = parameter__name(param); - type_id = param->tag.type == 0 ? 0 : type_id_off + param->tag.type; + type_id = param->tag.type == 0 ? 0 : encoder->type_id_off + param->tag.type; ++param_idx; if (btf_encoder__add_func_param(encoder, name, type_id, param_idx == nr_params)) return -1; @@ -762,6 +764,31 @@ static int32_t btf_encoder__add_decl_tag(struct btf_encoder *encoder, const char return id; } +static int32_t btf_encoder__add_func(struct btf_encoder *encoder, struct function *fn) +{ + int btf_fnproto_id, btf_fn_id, tag_type_id; + struct llvm_annotation *annot; + const char *name; + + btf_fnproto_id = btf_encoder__add_func_proto(encoder, &fn->proto); + name = function__name(fn); + btf_fn_id = btf_encoder__add_ref_type(encoder, BTF_KIND_FUNC, btf_fnproto_id, name, false); + if (btf_fnproto_id < 0 || btf_fn_id < 0) { + printf("error: failed to encode function '%s'\n", function__name(fn)); + return -1; + } + list_for_each_entry(annot, &fn->annots, node) { + tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, btf_fn_id, + annot->component_idx); + if (tag_type_id < 0) { + fprintf(stderr, "error: failed to encode tag '%s' to func %s with component_idx %d\n", + annot->value, name, annot->component_idx); + return -1; + } + } + return 0; +} + /* * This corresponds to the same macro defined in * include/linux/kallsyms.h @@ -859,22 +886,21 @@ static void dump_invalid_symbol(const char *msg, const char *sym, fprintf(stderr, "PAHOLE: Error: Use '--btf_encode_force' to ignore such symbols and force emit the btf.\n"); } -static int tag__check_id_drift(const struct tag *tag, - uint32_t core_id, uint32_t btf_type_id, - uint32_t type_id_off) +static int tag__check_id_drift(struct btf_encoder *encoder, const struct tag *tag, + uint32_t core_id, uint32_t btf_type_id) { - if (btf_type_id != (core_id + type_id_off)) { + if (btf_type_id != (core_id + encoder->type_id_off)) { fprintf(stderr, "%s: %s id drift, core_id: %u, btf_type_id: %u, type_id_off: %u\n", __func__, dwarf_tag_name(tag->tag), - core_id, btf_type_id, type_id_off); + core_id, btf_type_id, encoder->type_id_off); return -1; } return 0; } -static int32_t btf_encoder__add_struct_type(struct btf_encoder *encoder, struct tag *tag, uint32_t type_id_off) +static int32_t btf_encoder__add_struct_type(struct btf_encoder *encoder, struct tag *tag) { struct type *type = tag__type(tag); struct class_member *pos; @@ -896,7 +922,8 @@ static int32_t btf_encoder__add_struct_type(struct btf_encoder *encoder, struct * is required. */ name = class_member__name(pos); - if (btf_encoder__add_field(encoder, name, type_id_off + pos->tag.type, pos->bitfield_size, pos->bit_offset)) + if (btf_encoder__add_field(encoder, name, encoder->type_id_off + pos->tag.type, + pos->bitfield_size, pos->bit_offset)) return -1; } @@ -936,11 +963,11 @@ static int32_t btf_encoder__add_enum_type(struct btf_encoder *encoder, struct ta return type_id; } -static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag, uint32_t type_id_off, +static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag, struct conf_load *conf_load) { /* single out type 0 as it represents special type "void" */ - uint32_t ref_type_id = tag->type == 0 ? 0 : type_id_off + tag->type; + uint32_t ref_type_id = tag->type == 0 ? 0 : encoder->type_id_off + tag->type; struct base_type *bt; const char *name; @@ -970,7 +997,7 @@ static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag, if (tag__type(tag)->declaration) return btf_encoder__add_ref_type(encoder, BTF_KIND_FWD, 0, name, tag->tag == DW_TAG_union_type); else - return btf_encoder__add_struct_type(encoder, tag, type_id_off); + return btf_encoder__add_struct_type(encoder, tag); case DW_TAG_array_type: /* TODO: Encode one dimension at a time. */ encoder->need_index_type = true; @@ -978,7 +1005,7 @@ static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag, case DW_TAG_enumeration_type: return btf_encoder__add_enum_type(encoder, tag, conf_load); case DW_TAG_subroutine_type: - return btf_encoder__add_func_proto(encoder, tag__ftype(tag), type_id_off); + return btf_encoder__add_func_proto(encoder, tag__ftype(tag)); case DW_TAG_unspecified_type: /* Just don't encode this for now, converting anything with this type to void (0) instead. * @@ -1281,7 +1308,7 @@ static bool ftype__has_arg_names(const struct ftype *ftype) return true; } -static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder, uint32_t type_id_off) +static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder) { struct cu *cu = encoder->cu; uint32_t core_id; @@ -1366,7 +1393,7 @@ static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder, uint32_ continue; } - type = var->ip.tag.type + type_id_off; + type = var->ip.tag.type + encoder->type_id_off; linkage = var->external ? BTF_VAR_GLOBAL_ALLOCATED : BTF_VAR_STATIC; if (encoder->verbose) { @@ -1507,7 +1534,6 @@ void btf_encoder__delete(struct btf_encoder *encoder) int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct conf_load *conf_load) { - uint32_t type_id_off = btf__type_cnt(encoder->btf) - 1; struct llvm_annotation *annot; int btf_type_id, tag_type_id, skipped_types = 0; uint32_t core_id; @@ -1516,21 +1542,24 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co int err = 0; encoder->cu = cu; + encoder->type_id_off = btf__type_cnt(encoder->btf) - 1; + if (encoder->cu->unspecified_type.tag) + encoder->unspecified_type = encoder->cu->unspecified_type.type; if (!encoder->has_index_type) { /* cu__find_base_type_by_name() takes "type_id_t *id" */ type_id_t id; if (cu__find_base_type_by_name(cu, "int", &id)) { encoder->has_index_type = true; - encoder->array_index_id = type_id_off + id; + encoder->array_index_id = encoder->type_id_off + id; } else { encoder->has_index_type = false; - encoder->array_index_id = type_id_off + cu->types_table.nr_entries; + encoder->array_index_id = encoder->type_id_off + cu->types_table.nr_entries; } } cu__for_each_type(cu, core_id, pos) { - btf_type_id = btf_encoder__encode_tag(encoder, pos, type_id_off, conf_load); + btf_type_id = btf_encoder__encode_tag(encoder, pos, conf_load); if (btf_type_id == 0) { ++skipped_types; @@ -1538,7 +1567,7 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co } if (btf_type_id < 0 || - tag__check_id_drift(pos, core_id, btf_type_id + skipped_types, type_id_off)) { + tag__check_id_drift(encoder, pos, core_id, btf_type_id + skipped_types)) { err = -1; goto out; } @@ -1572,7 +1601,7 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co continue; } - btf_type_id = type_id_off + core_id; + btf_type_id = encoder->type_id_off + core_id; ns = tag__namespace(pos); list_for_each_entry(annot, &ns->annots, node) { tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, btf_type_id, annot->component_idx); @@ -1585,8 +1614,6 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co } cu__for_each_function(cu, core_id, fn) { - int btf_fnproto_id, btf_fn_id; - const char *name; /* * Skip functions that: @@ -1616,27 +1643,13 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co continue; } - btf_fnproto_id = btf_encoder__add_func_proto(encoder, &fn->proto, type_id_off); - name = function__name(fn); - btf_fn_id = btf_encoder__add_ref_type(encoder, BTF_KIND_FUNC, btf_fnproto_id, name, false); - if (btf_fnproto_id < 0 || btf_fn_id < 0) { - err = -1; - printf("error: failed to encode function '%s'\n", function__name(fn)); + err = btf_encoder__add_func(encoder, fn); + if (err) goto out; - } - - list_for_each_entry(annot, &fn->annots, node) { - tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, btf_fn_id, annot->component_idx); - if (tag_type_id < 0) { - fprintf(stderr, "error: failed to encode tag '%s' to func %s with component_idx %d\n", - annot->value, name, annot->component_idx); - goto out; - } - } } if (!encoder->skip_encoding_vars) - err = btf_encoder__encode_cu_variables(encoder, type_id_off); + err = btf_encoder__encode_cu_variables(encoder); out: encoder->cu = NULL; return err; From patchwork Mon Jan 30 14:29:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Maguire X-Patchwork-Id: 13121265 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 A2EA0C54EED for ; Mon, 30 Jan 2023 14:32:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237834AbjA3OcU (ORCPT ); Mon, 30 Jan 2023 09:32:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49268 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237835AbjA3OcA (ORCPT ); Mon, 30 Jan 2023 09:32:00 -0500 Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5472A1B572 for ; Mon, 30 Jan 2023 06:30:28 -0800 (PST) Received: from pps.filterd (m0246630.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30UAStv8009420; Mon, 30 Jan 2023 14:30:08 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2022-7-12; bh=ZkJU3BTK7LN6DjlJ53vQ3r3GdppJBKjGGqxCQcsnMxw=; b=RDltXSA/QExttXFMOgcpMWJdv5XS3zZLeJxSJHuz0ckXJGXnWJ4hc4RiDZpMV1t44LkH 6Y+PlroZz9BYM3XMAFfcmdFPprPavRPNub/tQqovf9ydP0grKf7iIXJ0hCew0gGkWiYp oQwQ1Jz6eDsA2LLkc0I1UnvLaCU4Yi2QqeRkEv334s76mqvQfkAOVfY+NJgjQIcpadT1 bSEcTKFTIOscg/mXoCDMBP479ol8P7zAnKDpV0crAw/b68Nu+xs8qgk3KQTShyoo6RRF ZxDPwR53M6Sr/9ukIhiypf3zgdeY0IM8xuaBoQs3DaDgW50WiZCWR/5Z5X5KuyXhwlQo QQ== Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.appoci.oracle.com [138.1.114.2]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3ncvn9tytq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 30 Jan 2023 14:30:08 +0000 Received: from pps.filterd (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.5/8.17.1.5) with ESMTP id 30UDV1XD001501; Mon, 30 Jan 2023 14:30:07 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3nct54631n-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 30 Jan 2023 14:30:07 +0000 Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 30UETrIv020648; Mon, 30 Jan 2023 14:30:06 GMT Received: from myrouter.uk.oracle.com (dhcp-10-175-214-73.vpn.oracle.com [10.175.214.73]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3nct5462kh-4; Mon, 30 Jan 2023 14:30:06 +0000 From: Alan Maguire To: acme@kernel.org, yhs@fb.com, ast@kernel.org, olsajiri@gmail.com, eddyz87@gmail.com, sinquersw@gmail.com, timo@incline.eu Cc: daniel@iogearbox.net, andrii@kernel.org, songliubraving@fb.com, john.fastabend@gmail.com, kpsingh@chromium.org, sdf@google.com, haoluo@google.com, martin.lau@kernel.org, bpf@vger.kernel.org, Alan Maguire Subject: [PATCH v2 dwarves 3/5] btf_encoder: rework btf_encoders__*() API to allow traversal of encoders Date: Mon, 30 Jan 2023 14:29:43 +0000 Message-Id: <1675088985-20300-4-git-send-email-alan.maguire@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1675088985-20300-1-git-send-email-alan.maguire@oracle.com> References: <1675088985-20300-1-git-send-email-alan.maguire@oracle.com> X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-30_13,2023-01-30_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 adultscore=0 malwarescore=0 spamscore=0 phishscore=0 mlxlogscore=999 suspectscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301300140 X-Proofpoint-GUID: tJ86XFqPM8F6P3g3KikdmjHgJOCp8eh1 X-Proofpoint-ORIG-GUID: tJ86XFqPM8F6P3g3KikdmjHgJOCp8eh1 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org To coordinate across multiple encoders at collection time, there will be a need to access the set of encoders. Rework the unused btf_encoders__*() API to facilitate this. Signed-off-by: Alan Maguire --- btf_encoder.c | 30 ++++++++++++++++++++++-------- btf_encoder.h | 6 ------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/btf_encoder.c b/btf_encoder.c index 44f1905..e20b628 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -30,6 +30,7 @@ #include #include +#include struct elf_function { const char *name; @@ -79,21 +80,32 @@ struct btf_encoder { } functions; }; -void btf_encoders__add(struct list_head *encoders, struct btf_encoder *encoder) -{ - list_add_tail(&encoder->node, encoders); -} +static LIST_HEAD(encoders); +static pthread_mutex_t encoders__lock = PTHREAD_MUTEX_INITIALIZER; -struct btf_encoder *btf_encoders__first(struct list_head *encoders) +/* mutex only needed for add/delete, as this can happen in multiple encoding + * threads. Traversal of the list is currently confined to thread collection. + */ +static void btf_encoders__add(struct btf_encoder *encoder) { - return list_first_entry(encoders, struct btf_encoder, node); + pthread_mutex_lock(&encoders__lock); + list_add_tail(&encoder->node, &encoders); + pthread_mutex_unlock(&encoders__lock); } -struct btf_encoder *btf_encoders__next(struct btf_encoder *encoder) +#define btf_encoders__for_each_encoder(encoder) \ + list_for_each_entry(encoder, &encoders, node) + +static void btf_encoders__delete(struct btf_encoder *encoder) { - return list_next_entry(encoder, node); + pthread_mutex_lock(&encoders__lock); + list_del(&encoder->node); + pthread_mutex_unlock(&encoders__lock); } +#define btf_encoders__for_each_encoder(encoder) \ + list_for_each_entry(encoder, &encoders, node) + #define PERCPU_SECTION ".data..percpu" /* @@ -1505,6 +1517,7 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam if (encoder->verbose) printf("File %s:\n", cu->filename); + btf_encoders__add(encoder); } out: return encoder; @@ -1519,6 +1532,7 @@ void btf_encoder__delete(struct btf_encoder *encoder) if (encoder == NULL) return; + btf_encoders__delete(encoder); __gobuffer__delete(&encoder->percpu_secinfo); zfree(&encoder->filename); btf__free(encoder->btf); diff --git a/btf_encoder.h b/btf_encoder.h index a65120c..34516bb 100644 --- a/btf_encoder.h +++ b/btf_encoder.h @@ -23,12 +23,6 @@ int btf_encoder__encode(struct btf_encoder *encoder); int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct conf_load *conf_load); -void btf_encoders__add(struct list_head *encoders, struct btf_encoder *encoder); - -struct btf_encoder *btf_encoders__first(struct list_head *encoders); - -struct btf_encoder *btf_encoders__next(struct btf_encoder *encoder); - struct btf *btf_encoder__btf(struct btf_encoder *encoder); int btf_encoder__add_encoder(struct btf_encoder *encoder, struct btf_encoder *other); From patchwork Mon Jan 30 14:29:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Maguire X-Patchwork-Id: 13121267 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 057A4C61DA4 for ; Mon, 30 Jan 2023 14:32:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237823AbjA3OcX (ORCPT ); Mon, 30 Jan 2023 09:32:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49608 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237813AbjA3OcD (ORCPT ); Mon, 30 Jan 2023 09:32:03 -0500 Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 620D838B7B for ; Mon, 30 Jan 2023 06:30:32 -0800 (PST) Received: from pps.filterd (m0333520.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30UASo9O018733; Mon, 30 Jan 2023 14:30:12 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2022-7-12; bh=Z83iENfB4ksF4ROaFPP71YZE8zQGrrdeJWUk99/aWM4=; b=AEmgRjuEjSGZhCE2qBsiGHhyVC+AvnaXaSd8MLyU24voQh4GIfwjmcIXAaaI4EyNRizO h8OnklfyNj8HoLlsd6tYQCM4Az1RZisURncBkEL0ZQ+yL+0KMuM5Hxs7WYrb5IsPlvti te+nPmmoZAIx6jYNedmT0DWl3sIEkVrcHOBfVD4p97ww1+WMQA/BC/XLBjvbw7vDSz5q WDI1iTGXWFpU/27BE7O66/MW6D4SZ5bRuvJmh/shA5cQtRTiRH/afrfCypGeNuQ6G7HM QnU2YRgb8Hcth/z75vDgqZHsq1ZM1vpsgDP1mowvw3SymhDpj7gz+BdHaHX4c/Ua1Shq aA== Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.appoci.oracle.com [138.1.114.2]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3ncvqwu0jb-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 30 Jan 2023 14:30:12 +0000 Received: from pps.filterd (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.5/8.17.1.5) with ESMTP id 30UDxHdn000723; Mon, 30 Jan 2023 14:30:11 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3nct54636y-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 30 Jan 2023 14:30:11 +0000 Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 30UETrIx020648; Mon, 30 Jan 2023 14:30:10 GMT Received: from myrouter.uk.oracle.com (dhcp-10-175-214-73.vpn.oracle.com [10.175.214.73]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3nct5462kh-5; Mon, 30 Jan 2023 14:30:10 +0000 From: Alan Maguire To: acme@kernel.org, yhs@fb.com, ast@kernel.org, olsajiri@gmail.com, eddyz87@gmail.com, sinquersw@gmail.com, timo@incline.eu Cc: daniel@iogearbox.net, andrii@kernel.org, songliubraving@fb.com, john.fastabend@gmail.com, kpsingh@chromium.org, sdf@google.com, haoluo@google.com, martin.lau@kernel.org, bpf@vger.kernel.org, Alan Maguire Subject: [PATCH v2 dwarves 4/5] btf_encoder: represent "."-suffixed functions (".isra.0") in BTF Date: Mon, 30 Jan 2023 14:29:44 +0000 Message-Id: <1675088985-20300-5-git-send-email-alan.maguire@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1675088985-20300-1-git-send-email-alan.maguire@oracle.com> References: <1675088985-20300-1-git-send-email-alan.maguire@oracle.com> X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-30_13,2023-01-30_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 adultscore=0 malwarescore=0 spamscore=0 phishscore=0 mlxlogscore=999 suspectscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301300140 X-Proofpoint-ORIG-GUID: 9tyxeauERh4kb_W6NTaA_wCCcIKbheXU X-Proofpoint-GUID: 9tyxeauERh4kb_W6NTaA_wCCcIKbheXU Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org At gcc optimization level O2 or higher, many function optimizations occur such as - constant propagation (.constprop.0); - interprocedural scalar replacement of aggregates, removal of unused parameters and replacement of parameters passed by reference by parameters passed by value (.isra.0) See [1] for details. Currently BTF encoding does not handle such optimized functions that get renamed with a "." suffix such as ".isra.0", ".constprop.0". This is safer because such suffixes can often indicate parameters have been optimized out. Since we can now spot this, support matching to a "." suffix and represent the function in BTF if it does not have optimized-out parameters. First an attempt to match by exact name is made; if that fails we fall back to checking for a "."-suffixed name. The BTF representation will use the original function name "foo" not "foo.isra.0" for consistency with DWARF representation. There is a complication however, and this arises because we process each CU separately and merge BTF when complete. Different CUs may optimize differently, so in one CU, a function may have optimized-out parameters - and thus be ineligible for BTF - while in another it does not have optimized-out parameters - making it eligible for BTF. The NF_HOOK function is an example of this. To avoid disrupting BTF generation parallelism, the approach taken is to save such functions in a per-encoder binary tree for later addition. That way, at thread collection time, observations about optimizations can be merged across encoders and we know whether it is safe to add a "."-suffixed function or not. The result of this is we add 602 "."-suffixed functions to the BTF representation. However, note that the optimization checks are applied to both "."-suffixed and normal functions. They find 1428 of the latter with optimized-out parameters also, and these are dropped from the BTF representation also. For example, bad_inode_permission() is skipped because no location information is supplied for any of its parameters; disassembling it we see why this might be: (gdb) disassemble bad_inode_permission Dump of assembler code for function bad_inode_permission: 0xffffffff813ef180 <+0>: callq 0xffffffff81088c70 <__fentry__> 0xffffffff813ef185 <+5>: push %rbp 0xffffffff813ef186 <+6>: mov $0xfffffffb,%eax 0xffffffff813ef18b <+11>: mov %rsp,%rbp 0xffffffff813ef18e <+14>: pop %rbp 0xffffffff813ef18f <+15>: jmpq 0xffffffff81c6e600 <__x86_return_thunk> End of assembler dump. ...since the function is simply: static int bad_inode_permission(struct user_namespace *mnt_userns, struct inode *inode, int mask) { return -EIO; } So these changes lead to a net decrease of 826 functions in vmlinux BTF. [1] https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html Signed-off-by: Alan Maguire --- btf_encoder.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- dwarves.h | 2 + pahole.c | 14 ++--- 3 files changed, 200 insertions(+), 13 deletions(-) diff --git a/btf_encoder.c b/btf_encoder.c index e20b628..f36150e 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -30,11 +30,13 @@ #include #include +#include /* for tsearch(), tfind() and tdestroy() */ #include struct elf_function { const char *name; bool generated; + size_t prefixlen; }; #define MAX_PERCPU_VAR_CNT 4096 @@ -57,6 +59,8 @@ struct btf_encoder { struct elf_symtab *symtab; uint32_t type_id_off; uint32_t unspecified_type; + void *saved_func_tree; + int saved_func_cnt; bool has_index_type, need_index_type, skip_encoding_vars, @@ -77,12 +81,15 @@ struct btf_encoder { struct elf_function *entries; int allocated; int cnt; + int suffix_cnt; /* number of .isra, .part etc */ } functions; }; static LIST_HEAD(encoders); static pthread_mutex_t encoders__lock = PTHREAD_MUTEX_INITIALIZER; +static void btf_encoder__add_saved_funcs(struct btf_encoder *encoder); + /* mutex only needed for add/delete, as this can happen in multiple encoding * threads. Traversal of the list is currently confined to thread collection. */ @@ -701,6 +708,10 @@ int32_t btf_encoder__add_encoder(struct btf_encoder *encoder, struct btf_encoder int32_t i, id; struct btf_var_secinfo *vsi; + btf_encoder__add_saved_funcs(other); + if (encoder == other) + return 0; + for (i = 0; i < nr_var_secinfo; i++) { vsi = (struct btf_var_secinfo *)var_secinfo_buf->entries + i; type_id = next_type_id + vsi->type - 1; /* Type ID starts from 1 */ @@ -776,6 +787,70 @@ static int32_t btf_encoder__add_decl_tag(struct btf_encoder *encoder, const char return id; } + +static int function__compare(const void *a, const void *b) +{ + struct function *fa = (struct function *)a, *fb = (struct function *)b; + + return strcmp(function__name(fa), function__name(fb)); +} + +struct btf_encoder_state { + struct btf_encoder *encoder; + uint32_t type_id_off; +}; + +static void btf_encoder__merge_func(struct btf_encoder *encoder, struct function *fn) +{ + struct function **nodep; + + nodep = tfind(fn, &encoder->saved_func_tree, function__compare); + if (!nodep || !*nodep) + return; + /* merge characteristics across different encoder representations + * of functions. + */ + fn->proto.optimized_parms |= (*nodep)->proto.optimized_parms; + (*nodep)->proto.optimized_parms |= fn->proto.optimized_parms; + (*nodep)->proto.processed = 1; +} + +static int32_t btf_encoder__save_func(struct btf_encoder *encoder, struct function *fn) +{ + const char *name = function__name(fn); + struct function **nodep; + + nodep = tsearch(fn, &encoder->saved_func_tree, function__compare); + if (nodep == NULL) { + fprintf(stderr, "error: out of memory adding static function '%s'\n", + name); + return -1; + } + /* If saving and we find an existing entry, we want to merge + * observations across both functions, checking that the + * "seen optimized parameters" status is reflected in our tree entry. + * If the entry is new, record encoder state required + * to add the local function later (encoder + type_id_off) + * such that we can add the function later. + */ + if (*nodep != fn) { + (*nodep)->proto.optimized_parms |= fn->proto.optimized_parms; + } else { + struct btf_encoder_state *state = zalloc(sizeof(*state)); + + if (state == NULL) { + fprintf(stderr, "error: out of memory adding local function '%s'\n", + name); + return -1; + } + state->encoder = encoder; + state->type_id_off = encoder->type_id_off; + fn->priv = state; + encoder->saved_func_cnt++; + } + return 0; +} + static int32_t btf_encoder__add_func(struct btf_encoder *encoder, struct function *fn) { int btf_fnproto_id, btf_fn_id, tag_type_id; @@ -801,6 +876,67 @@ static int32_t btf_encoder__add_func(struct btf_encoder *encoder, struct functio return 0; } +/* visit each node once, adding associated function. */ +static void btf_encoder__add_saved_func(const void *nodep, const VISIT which, + const int depth __maybe_unused) +{ + struct btf_encoder *encoder, *other_encoder; + struct btf_encoder_state *state; + struct function *fn = NULL; + + switch (which) { + case preorder: + case endorder: + break; + case postorder: + case leaf: + fn = *((struct function **)nodep); + break; + } + if (!fn || !fn->priv || fn->proto.processed) + return; + state = (struct btf_encoder_state *)fn->priv; + encoder = state->encoder; + encoder->type_id_off = state->type_id_off; + + /* merge optimized-out status across encoders */ + btf_encoders__for_each_encoder(other_encoder) { + if (other_encoder != encoder) + btf_encoder__merge_func(other_encoder, fn); + } + + if (fn->proto.optimized_parms) { + if (encoder->verbose) { + const char *name = function__name(fn); + + printf("skipping addition of '%s'(%s) due to optimized-out parameters\n", + name, fn->alias ?: name); + } + } else { + btf_encoder__add_func(encoder, fn); + fn->proto.processed = 1; + } +} + +static void saved_func__free(void *node) +{ + struct function *fn = node; + + if (fn->priv) + free(fn->priv); +} + +void btf_encoder__add_saved_funcs(struct btf_encoder *encoder) +{ + if (!encoder->saved_func_tree) + return; + + encoder->type_id_off = 0; + twalk(encoder->saved_func_tree, btf_encoder__add_saved_func); + tdestroy(encoder->saved_func_tree, saved_func__free); + encoder->saved_func_tree = NULL; +} + /* * This corresponds to the same macro defined in * include/linux/kallsyms.h @@ -812,6 +948,11 @@ static int functions_cmp(const void *_a, const void *_b) const struct elf_function *a = _a; const struct elf_function *b = _b; + /* if search key allows prefix match, verify target has matching + * prefix len and prefix matches. + */ + if (a->prefixlen && a->prefixlen == b->prefixlen) + return strncmp(a->name, b->name, b->prefixlen); return strcmp(a->name, b->name); } @@ -844,14 +985,21 @@ static int btf_encoder__collect_function(struct btf_encoder *encoder, GElf_Sym * } encoder->functions.entries[encoder->functions.cnt].name = name; + if (strchr(name, '.')) { + const char *suffix = strchr(name, '.'); + + encoder->functions.suffix_cnt++; + encoder->functions.entries[encoder->functions.cnt].prefixlen = suffix - name; + } encoder->functions.entries[encoder->functions.cnt].generated = false; encoder->functions.cnt++; return 0; } -static struct elf_function *btf_encoder__find_function(const struct btf_encoder *encoder, const char *name) +static struct elf_function *btf_encoder__find_function(const struct btf_encoder *encoder, + const char *name, size_t prefixlen) { - struct elf_function key = { .name = name }; + struct elf_function key = { .name = name, .prefixlen = prefixlen }; return bsearch(&key, encoder->functions.entries, encoder->functions.cnt, sizeof(key), functions_cmp); } @@ -1181,6 +1329,9 @@ int btf_encoder__encode(struct btf_encoder *encoder) { int err; + /* for single-threaded case, saved funcs are added here */ + btf_encoder__add_saved_funcs(encoder); + if (gobuffer__size(&encoder->percpu_secinfo) != 0) btf_encoder__add_datasec(encoder, PERCPU_SECTION); @@ -1628,6 +1779,7 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co } cu__for_each_function(cu, core_id, fn) { + bool save = false; /* * Skip functions that: @@ -1648,22 +1800,55 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co if (!name) continue; - func = btf_encoder__find_function(encoder, name); - if (!func || func->generated) + /* prefer exact function name match... */ + func = btf_encoder__find_function(encoder, name, 0); + if (func) { + if (func->generated) + continue; + func->generated = true; + } else if (encoder->functions.suffix_cnt) { + /* falling back to name.isra.0 match if no exact + * match is found; only bother if we found any + * .suffix function names. The function + * will be saved and added once we ensure + * it does not have optimized-out parameters + * in any cu. + */ + func = btf_encoder__find_function(encoder, name, + strlen(name)); + if (func) { + save = true; + if (encoder->verbose) + printf("matched function '%s' with '%s'%s\n", + name, func->name, + fn->proto.optimized_parms ? + ", has optimized-out parameters" : ""); + } + } + if (!func) continue; - func->generated = true; + fn->alias = func->name; } else { if (!fn->external) continue; } - err = btf_encoder__add_func(encoder, fn); + if (save) + err = btf_encoder__save_func(encoder, fn); + else + err = btf_encoder__add_func(encoder, fn); if (err) goto out; } if (!encoder->skip_encoding_vars) err = btf_encoder__encode_cu_variables(encoder); + + /* It is only safe to delete this CU if we have not stashed any static + * functions for later addition. + */ + if (!err) + err = encoder->saved_func_cnt > 0 ? LSK__KEEPIT : LSK__DELETE; out: encoder->cu = NULL; return err; diff --git a/dwarves.h b/dwarves.h index 2723466..64c7c56 100644 --- a/dwarves.h +++ b/dwarves.h @@ -831,6 +831,7 @@ struct ftype { uint16_t nr_parms; uint8_t unspec_parms:1; /* just one bit is needed */ uint8_t optimized_parms:1; + uint8_t processed:1; }; static inline struct ftype *tag__ftype(const struct tag *tag) @@ -883,6 +884,7 @@ struct function { struct rb_node rb_node; const char *name; const char *linkage_name; + const char *alias; /* name.isra.0 */ uint32_t cu_total_size_inline_expansions; uint16_t cu_total_nr_inline_expansions; uint8_t inlined:2; diff --git a/pahole.c b/pahole.c index 6f4f87c..bc120cb 100644 --- a/pahole.c +++ b/pahole.c @@ -2980,20 +2980,20 @@ static int pahole_threads_collect(struct conf_load *conf, int nr_threads, void * * Merge content of the btf instances of worker threads to the btf * instance of the primary btf_encoder. */ - if (!threads[i]->btf || threads[i]->encoder == btf_encoder) - continue; /* The primary btf_encoder */ + if (!threads[i]->btf) + continue; err = btf_encoder__add_encoder(btf_encoder, threads[i]->encoder); if (err < 0) goto out; - btf_encoder__delete(threads[i]->encoder); - threads[i]->encoder = NULL; } err = 0; out: for (i = 0; i < nr_threads; i++) { - if (threads[i]->encoder && threads[i]->encoder != btf_encoder) + if (threads[i]->encoder && threads[i]->encoder != btf_encoder) { btf_encoder__delete(threads[i]->encoder); + threads[i]->encoder = NULL; + } } free(threads[0]); @@ -3077,11 +3077,11 @@ static enum load_steal_kind pahole_stealer(struct cu *cu, encoder = btf_encoder; } - if (btf_encoder__encode_cu(encoder, cu, conf_load)) { + ret = btf_encoder__encode_cu(encoder, cu, conf_load); + if (ret < 0) { fprintf(stderr, "Encountered error while encoding BTF.\n"); exit(1); } - ret = LSK__DELETE; out_btf: return ret; } From patchwork Mon Jan 30 14:29:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Maguire X-Patchwork-Id: 13121268 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 DC15CC636D0 for ; Mon, 30 Jan 2023 14:32:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237813AbjA3OcZ (ORCPT ); Mon, 30 Jan 2023 09:32:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54090 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237540AbjA3OcE (ORCPT ); Mon, 30 Jan 2023 09:32:04 -0500 Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A37C73A5A3 for ; Mon, 30 Jan 2023 06:30:34 -0800 (PST) Received: from pps.filterd (m0333520.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30UASrXY018801; Mon, 30 Jan 2023 14:30:16 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2022-7-12; bh=P+ygTO2FqWzljYCYc8fzL/YTDuRDhr7O02s8w8XC5BM=; b=nJ1jOc5kilpnwQM5Wm/Gf6TbxOd1Az4USnOVi87f99LZ+92VCVouoP4maHzjCKFUKuSU G3Mad9xHeFY0muD1tj4wzLMOWO2AoDvgsoccA0hEJnydkGRghhLA67vlOm8pgZ4rVY7d JDH+d5A/VUTehFF4xjIpEFZxf5xngFuprGcmS77vdoYdkqLQaxqtd1y6ngdQjtDcO46x rgbT93g6Xd0pw7ZbSbnGTBMjGq1yHXnF0guaePcZQf+U8EI+NocpShcmepFqhexuM4mC LThwWHK4zhEIgcMla4rsAD2eaGVdEvuq4mNLruLxMsL5kmdqfdi6FsCD67WCKH/nyIns 6g== Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.appoci.oracle.com [138.1.114.2]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3ncvqwu0jk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 30 Jan 2023 14:30:16 +0000 Received: from pps.filterd (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.5/8.17.1.5) with ESMTP id 30UE6GjR000661; Mon, 30 Jan 2023 14:30:15 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3nct5463cv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 30 Jan 2023 14:30:15 +0000 Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 30UETrJ1020648; Mon, 30 Jan 2023 14:30:14 GMT Received: from myrouter.uk.oracle.com (dhcp-10-175-214-73.vpn.oracle.com [10.175.214.73]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3nct5462kh-6; Mon, 30 Jan 2023 14:30:14 +0000 From: Alan Maguire To: acme@kernel.org, yhs@fb.com, ast@kernel.org, olsajiri@gmail.com, eddyz87@gmail.com, sinquersw@gmail.com, timo@incline.eu Cc: daniel@iogearbox.net, andrii@kernel.org, songliubraving@fb.com, john.fastabend@gmail.com, kpsingh@chromium.org, sdf@google.com, haoluo@google.com, martin.lau@kernel.org, bpf@vger.kernel.org, Alan Maguire Subject: [PATCH v2 dwarves 5/5] btf_encoder: delay function addition to check for function prototype inconsistencies Date: Mon, 30 Jan 2023 14:29:45 +0000 Message-Id: <1675088985-20300-6-git-send-email-alan.maguire@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1675088985-20300-1-git-send-email-alan.maguire@oracle.com> References: <1675088985-20300-1-git-send-email-alan.maguire@oracle.com> X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.930,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-30_13,2023-01-30_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 adultscore=0 malwarescore=0 spamscore=0 phishscore=0 mlxlogscore=999 suspectscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301300140 X-Proofpoint-ORIG-GUID: 7bLuTm07zFQ5BKfV_RPTrqgYrIRt7B6I X-Proofpoint-GUID: 7bLuTm07zFQ5BKfV_RPTrqgYrIRt7B6I Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org There are multiple sources of inconsistency that can result in functions of the same name having multiple prototypes: - multiple static functions in different CUs share the same name - static and external functions share the same name Here we attempt to catch such cases by finding inconsistencies across CUs using the save/compare/merge mechanisms that were previously introduced to handle optimized-out parameters, using it for all functions. For two instances of a function to be considered consistent: - number of parameters must match - parameter names must match The latter is a less strong method than a full type comparison but suffices to match functions. With these changes, we see 278 functions removed due to protoype inconsistency. For example, wakeup_show() has two distinct prototypes: static ssize_t wakeup_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) (from kernel/irq/irqdesc.c) static ssize_t wakeup_show(struct device *dev, struct device_attribute *attr, char *buf) (from drivers/base/power/sysfs.c) In some other cases, the parameter comparisons weed out additional inconsistencies in "."-suffixed functions across CUs. We also see a large number of functions eliminated due to optimized-out parameters; 2542 functions are eliminated for this reason, both "."-suffixed (1007) and otherwise (1535). Because the save/compare/merge process occurs for all functions it is important to assess performance effects. In addition, prior to these changes the number of functions ultimately represented in BTF was non-deterministic when pahole was run with multiple threads. This was due to the fact that functions were marked as generated on a per-encoder basis when first added, and as such the same function could be added multiple times for different encoders, and if they encountered inconsistent function prototypes, deduplication could leave multiple entries in place for the same name. When run in a single thread, the "generated" state associated with the name would prevent this. Here we assess both BTF encoding performance and determinism of the function representation in baseline compared to with these changes. Determinism is assessed by counting the number of functions in BTF. Comparisons are done for 1, 4 and 8 threads. Baseline $ time LLVM_OBJCOPY=objcopy pahole -J vmlinux real 0m18.160s user 0m17.179s sys 0m0.757s $ grep " FUNC " /tmp/vmlinux.btf.base |awk '{print $3}'|sort|wc -l 51150 $ grep " FUNC " /tmp/vmlinux.btf.base |awk '{print $3}'|sort|uniq|wc -l 51150 $ time LLVM_OBJCOPY=objcopy pahole -J -j4 vmlinux real 0m8.078s user 0m17.978s sys 0m0.732s $ grep " FUNC " /tmp/vmlinux.btf.base |awk '{print $3}'|sort|wc -l 51592 $ grep " FUNC " /tmp/vmlinux.btf.base |awk '{print $3}'|sort|uniq|wc -l 51150 $ time LLVM_OBJCOPY=objcopy pahole -J -j8 vmlinux real 0m7.075s user 0m19.010s sys 0m0.587s $ grep " FUNC " /tmp/vmlinux.btf.base |awk '{print $3}'|sort|wc -l 51683 $ grep " FUNC " /tmp/vmlinux.btf.base |awk '{print $3}'|sort|uniq|wc -l 51150 Test: $ time LLVM_OBJCOPY=objcopy pahole -J vmlinux real 0m19.039s user 0m17.617s sys 0m1.419s $ bpftool btf dump file vmlinux | grep ' FUNC ' |sort|wc -l 49871 $ bpftool btf dump file vmlinux | grep ' FUNC ' |sort|uniq|wc -l 49871 $ time LLVM_OBJCOPY=objcopy pahole -J -j4 vmlinux real 0m8.482s user 0m18.233s sys 0m2.412s $ bpftool btf dump file vmlinux | grep ' FUNC ' |sort|wc -l 49871 $ bpftool btf dump file vmlinux | grep ' FUNC ' |sort|uniq|wc -l 49871 $ time LLVM_OBJCOPY=objcopy pahole -J -j8 vmlinux real 0m7.614s user 0m19.384s sys 0m3.739s $ bpftool btf dump file vmlinux | grep ' FUNC ' |sort|wc -l 49871 $ bpftool btf dump file vmlinux | grep ' FUNC ' |sort|uniq|wc -l So there is a small cost in performance, but we improve determinism and the consistency of representation. Future work could support maintaining multiple inconsistent prototypes; having a way to associate the function BTF representation with the function site would be needed however, and the BPF infrastructure would need to ensure that an fentry program was attached to the right site with the right prototype for example. BTF declaration tags with specifying the function address(es) a prototype referred to could help here, but edge cases like KASLR (where addresses change dynamically at boot-time) would have to be considered to make this work well. Similarly, future work could potentially accommodate function prototypes with optimized-out parameters, similarly using tagging to identify them. Again the kernel would have to be aware of such tagging and handle it. For now it is better to have an incomplete representation that more accurately reflects the actual function parameters used, removing inconsistencies that could otherwise do harm. Signed-off-by: Alan Maguire --- btf_encoder.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++------------ dwarves.h | 1 + 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/btf_encoder.c b/btf_encoder.c index f36150e..44739a9 100644 --- a/btf_encoder.c +++ b/btf_encoder.c @@ -35,7 +35,6 @@ struct elf_function { const char *name; - bool generated; size_t prefixlen; }; @@ -708,6 +707,9 @@ int32_t btf_encoder__add_encoder(struct btf_encoder *encoder, struct btf_encoder int32_t i, id; struct btf_var_secinfo *vsi; + /* saved functions are added to each encoder's BTF prior to it + * being merged with the parent encoder. + */ btf_encoder__add_saved_funcs(other); if (encoder == other) return 0; @@ -795,11 +797,72 @@ static int function__compare(const void *a, const void *b) return strcmp(function__name(fa), function__name(fb)); } +#define BTF_ENCODER_MAX_PARAMETERS 12 + struct btf_encoder_state { struct btf_encoder *encoder; uint32_t type_id_off; + bool got_parameter_names; + const char *parameter_names[BTF_ENCODER_MAX_PARAMETERS]; }; +static void parameter_names__get(struct ftype *ftype, size_t nr_parameters, + const char **parameter_names) +{ + struct parameter *parameter; + int i = 0; + + ftype__for_each_parameter(ftype, parameter) { + if (i >= nr_parameters) + break; + parameter_names[i++] = parameter__name(parameter); + } +} + +static bool funcs__match(struct function *f1, struct function *f2) +{ + + const char *parameter_names[BTF_ENCODER_MAX_PARAMETERS]; + struct btf_encoder_state *state = f1->priv; + const char *name = function__name(f1); + int i; + + if (!state) + return false; + + if (f1->proto.nr_parms != f2->proto.nr_parms) { + if (state->encoder->verbose) + printf("function mismatch for '%s'(%s): %d params != %d params\n", + name, f1->alias ?: name, + f1->proto.nr_parms, f2->proto.nr_parms); + return false; + } + + if (!state->got_parameter_names) { + parameter_names__get(&f1->proto, BTF_ENCODER_MAX_PARAMETERS, + state->parameter_names); + state->got_parameter_names = true; + } + parameter_names__get(&f2->proto, BTF_ENCODER_MAX_PARAMETERS, parameter_names); + for (i = 0; i < f1->proto.nr_parms && i < BTF_ENCODER_MAX_PARAMETERS; i++) { + if (!state->parameter_names[i]) { + if (!parameter_names[i]) + continue; + } else if (parameter_names[i]) { + if (strcmp(state->parameter_names[i], parameter_names[i]) == 0) + continue; + } + if (state->encoder->verbose) + printf("function mismatch for '%s'(%s): parameter #%d '%s' != '%s'\n", + name, f1->alias ?: name, i, + state->parameter_names[i] ?: "", + parameter_names[i] ?: ""); + + return false; + } + return true; +} + static void btf_encoder__merge_func(struct btf_encoder *encoder, struct function *fn) { struct function **nodep; @@ -812,6 +875,9 @@ static void btf_encoder__merge_func(struct btf_encoder *encoder, struct function */ fn->proto.optimized_parms |= (*nodep)->proto.optimized_parms; (*nodep)->proto.optimized_parms |= fn->proto.optimized_parms; + if ((fn->proto.inconsistent_proto || (*nodep)->proto.inconsistent_proto) || + !funcs__match(fn, *nodep)) + (*nodep)->proto.inconsistent_proto = fn->proto.inconsistent_proto = 1; (*nodep)->proto.processed = 1; } @@ -822,19 +888,22 @@ static int32_t btf_encoder__save_func(struct btf_encoder *encoder, struct functi nodep = tsearch(fn, &encoder->saved_func_tree, function__compare); if (nodep == NULL) { - fprintf(stderr, "error: out of memory adding static function '%s'\n", + fprintf(stderr, "error: out of memory adding function '%s'\n", name); return -1; } /* If saving and we find an existing entry, we want to merge * observations across both functions, checking that the - * "seen optimized parameters" status is reflected in our tree entry. + * "seen optimized parameters" and inconsistent prototype + * status is reflected in our tree entry. * If the entry is new, record encoder state required * to add the local function later (encoder + type_id_off) * such that we can add the function later. */ if (*nodep != fn) { (*nodep)->proto.optimized_parms |= fn->proto.optimized_parms; + if (!funcs__match(*nodep, fn)) + (*nodep)->proto.inconsistent_proto = fn->proto.inconsistent_proto = 1; } else { struct btf_encoder_state *state = zalloc(sizeof(*state)); @@ -905,12 +974,14 @@ static void btf_encoder__add_saved_func(const void *nodep, const VISIT which, btf_encoder__merge_func(other_encoder, fn); } - if (fn->proto.optimized_parms) { + if (fn->proto.optimized_parms || fn->proto.inconsistent_proto) { if (encoder->verbose) { const char *name = function__name(fn); - printf("skipping addition of '%s'(%s) due to optimized-out parameters\n", - name, fn->alias ?: name); + printf("skipping addition of '%s'(%s) due to %s\n", + name, fn->alias ?: name, + fn->proto.optimized_parms ? "optimized-out parameters" : + "multiple inconsistent function prototypes"); } } else { btf_encoder__add_func(encoder, fn); @@ -991,7 +1062,6 @@ static int btf_encoder__collect_function(struct btf_encoder *encoder, GElf_Sym * encoder->functions.suffix_cnt++; encoder->functions.entries[encoder->functions.cnt].prefixlen = suffix - name; } - encoder->functions.entries[encoder->functions.cnt].generated = false; encoder->functions.cnt++; return 0; } @@ -1779,8 +1849,6 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co } cu__for_each_function(cu, core_id, fn) { - bool save = false; - /* * Skip functions that: * - are marked as declarations @@ -1802,11 +1870,7 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co /* prefer exact function name match... */ func = btf_encoder__find_function(encoder, name, 0); - if (func) { - if (func->generated) - continue; - func->generated = true; - } else if (encoder->functions.suffix_cnt) { + if (!func && encoder->functions.suffix_cnt) { /* falling back to name.isra.0 match if no exact * match is found; only bother if we found any * .suffix function names. The function @@ -1817,7 +1881,7 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co func = btf_encoder__find_function(encoder, name, strlen(name)); if (func) { - save = true; + fn->alias = func->name; if (encoder->verbose) printf("matched function '%s' with '%s'%s\n", name, func->name, @@ -1827,16 +1891,12 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co } if (!func) continue; - fn->alias = func->name; } else { if (!fn->external) continue; } - if (save) - err = btf_encoder__save_func(encoder, fn); - else - err = btf_encoder__add_func(encoder, fn); + err = btf_encoder__save_func(encoder, fn); if (err) goto out; } diff --git a/dwarves.h b/dwarves.h index 64c7c56..ba94573 100644 --- a/dwarves.h +++ b/dwarves.h @@ -832,6 +832,7 @@ struct ftype { uint8_t unspec_parms:1; /* just one bit is needed */ uint8_t optimized_parms:1; uint8_t processed:1; + uint8_t inconsistent_proto:1; }; static inline struct ftype *tag__ftype(const struct tag *tag)