From patchwork Tue Mar 19 05:50:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596130 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4EBA545959; Tue, 19 Mar 2024 05:51:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827478; cv=none; b=GW6h9WnbaLcS4YdfB7nI91GzUh+EadLIAHWH/bEKJq8UY9nbJVZ9yB+1aNLo6APupC64njs+ogAij3sSM56LwukcLPNdLNx3SRYnoEwVm258a37amMCy1xmIXcY/X29kAggdGVbP5ZJ++ucU5ITe+ziD45Uu0i/jAPuLHkQsKVc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827478; c=relaxed/simple; bh=C7LYq6JKaTAwOM2QkVdpQCMOhtyFYmI4+gd4jRMnB14=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W8eZHGBZ4xTPGdHZgCG7B2DjqWvevpbpfUkynBrgy6blTDyFQ5guKjDXRWJjkDuFAL3kMnjYIhTZ962zzYy1VBGFB+bRf7Jso2EIpO6bKMbXF9KSmvaNLJdo/+Ecr6pideWhwEIj9RodEhh4qnxmrP83qgvHpYL3ApavyvTeMFE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kZG40xFb; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kZG40xFb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6FBF4C43399; Tue, 19 Mar 2024 05:51:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827477; bh=C7LYq6JKaTAwOM2QkVdpQCMOhtyFYmI4+gd4jRMnB14=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kZG40xFbs4VlIycftOn8idSvy3zl45dTcJFgZ+zEzTQEgl+Yen29pc4FIL5vjJcey t+bpNsMA4c1OOFtaPpuCgw3JBJPV24uxtqm3hr/12SPDwbXugGtwpeh9NKoW9ddEg3 7QykcT7S+LNHElvYu+94VHXVmyrCUT8cqAALrpx5XdMCU60pAniQhUEsfA4eDp7Bg4 WQMLo2QpAu1BqrETgUu/BVTErMTJ/e3lmSW+9k2O889WvfOsfDY4ELGHNtzV8cyjz8 qinra53kU8Xkdck+XXYDlPvUJFiPodhNEGnc6uOfcUXksUv+M6wUhebvzm6/rQ3LQF qtY+US9jSCxoQ== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 01/23] perf dwarf-aux: Remove unused pc argument Date: Mon, 18 Mar 2024 22:50:53 -0700 Message-ID: <20240319055115.4063940-2-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 It's not used, let's get rid of it. Signed-off-by: Namhyung Kim Reviewed-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 4 ++-- tools/perf/util/dwarf-aux.c | 7 ++----- tools/perf/util/dwarf-aux.h | 6 ++---- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 30c4d19fcf11..59ce5f4f4a40 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -263,7 +263,7 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, offset = loc->offset; if (reg == DWARF_REG_PC) { - if (die_find_variable_by_addr(&cu_die, pc, addr, &var_die, &offset)) { + if (die_find_variable_by_addr(&cu_die, addr, &var_die, &offset)) { ret = check_variable(&var_die, type_die, offset, /*is_pointer=*/false); loc->offset = offset; @@ -312,7 +312,7 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, /* Search from the inner-most scope to the outer */ for (i = nr_scopes - 1; i >= 0; i--) { if (reg == DWARF_REG_PC) { - if (!die_find_variable_by_addr(&scopes[i], pc, addr, + if (!die_find_variable_by_addr(&scopes[i], addr, &var_die, &offset)) continue; } else { diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 2791126069b4..e84d0d6a7750 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1456,7 +1456,6 @@ static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg) /** * die_find_variable_by_addr - Find variable located at given address * @sc_die: a scope DIE - * @pc: the program address to find * @addr: the data address to find * @die_mem: a buffer to save the resulting DIE * @offset: the offset in the resulting type @@ -1464,12 +1463,10 @@ static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg) * Find the variable DIE located at the given address (in PC-relative mode). * This is usually for global variables. */ -Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc, - Dwarf_Addr addr, Dwarf_Die *die_mem, - int *offset) +Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr addr, + Dwarf_Die *die_mem, int *offset) { struct find_var_data data = { - .pc = pc, .addr = addr, }; Dwarf_Die *result; diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 85dd527ae1f7..9973801a20c1 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -146,9 +146,8 @@ Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, Dwarf_Die *die_mem); /* Find a (global) variable located in the 'addr' */ -Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc, - Dwarf_Addr addr, Dwarf_Die *die_mem, - int *offset); +Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr addr, + Dwarf_Die *die_mem, int *offset); #else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ @@ -170,7 +169,6 @@ static inline Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die __maybe_unus } static inline Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die __maybe_unused, - Dwarf_Addr pc __maybe_unused, Dwarf_Addr addr __maybe_unused, Dwarf_Die *die_mem __maybe_unused, int *offset __maybe_unused) From patchwork Tue Mar 19 05:50:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596131 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 03CB14CDEB; Tue, 19 Mar 2024 05:51:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827479; cv=none; b=AKYINXO/ay8kKje61b0cHo52aLlc26IGq9O08vRgeDZEMW4YAopLQ0CQEE8r0LJ5uK1GQz6mV2ZeXI3NoGhpkUbvt973ToNd2+/4DOWh61wryNkC3spOuVdZl+hNr7OiIL51+NjLeEpyCKmL8aHn6gvUazcfYLnQJb+NHK8jo5w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827479; c=relaxed/simple; bh=przeKXxbKOyzoWsi4ae34zOaUqPq/+Uecl8MReIGEjE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=odP2vJtoZ1ILT9f4hDfZY/28p0nGx0PS6PWeYBoAhiaNgmMputkbkGO+lw6T8quN7csz7/60KRantiypKTiPe3dEojWA3kSMM+g4x7LkCUSXf45gh3ecF+KmkcdxehM/TmfsRYhP/oJAGrRxfsUYpNxpcsW0+8CeqRiV+acAV6o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=omlgjw4G; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="omlgjw4G" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 18A0DC433A6; Tue, 19 Mar 2024 05:51:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827478; bh=przeKXxbKOyzoWsi4ae34zOaUqPq/+Uecl8MReIGEjE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=omlgjw4G3JwX2vrRO8EH9OMTmNcMmzl8xHe5g5AkaorCLIKLgFypQJYl9FC44GUgr d41X6nsl1TSNo7aRFVWqmnD97lEYp2zwl+57zjvnvj66ShBATXz+m0Zoj7yPn7fU6O ODeOKfQ9KT05vcjdR0B7BM3jfkZi7pZo3UKBmI9gQGOksxpZ475Qks69NpwZM//hnB PQNB8WFnSV+QyDoznN3kCqntMDXI5bvgbR4WjSs25u6P6n0WnXeKGOdVz7xEQLxdY3 246CWwDjT8mIfHvRi2xjMKccKBcfK36Mtyzez2IbGyuG4kV26ABN4gS2hqFad2hW76 T/a0aec9pXFlQ== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 02/23] perf dwarf-aux: Add die_collect_vars() Date: Mon, 18 Mar 2024 22:50:54 -0700 Message-ID: <20240319055115.4063940-3-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The die_collect_vars() is to find all variable information in the scope including function parameters. The struct die_var_type is to save the type of the variable with the location (reg and offset) as well as where it's defined in the code (addr). Acked-by: Masami Hiramatsu (Google) Signed-off-by: Namhyung Kim Acked-by: Arnaldo Carvalho de Melo --- tools/perf/util/dwarf-aux.c | 118 +++++++++++++++++++++++++++--------- tools/perf/util/dwarf-aux.h | 17 ++++++ 2 files changed, 107 insertions(+), 28 deletions(-) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index e84d0d6a7750..785aa7a3d725 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1136,6 +1136,40 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf) return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); } +#if defined(HAVE_DWARF_GETLOCATIONS_SUPPORT) || defined(HAVE_DWARF_CFI_SUPPORT) +static int reg_from_dwarf_op(Dwarf_Op *op) +{ + switch (op->atom) { + case DW_OP_reg0 ... DW_OP_reg31: + return op->atom - DW_OP_reg0; + case DW_OP_breg0 ... DW_OP_breg31: + return op->atom - DW_OP_breg0; + case DW_OP_regx: + case DW_OP_bregx: + return op->number; + default: + break; + } + return -1; +} + +static int offset_from_dwarf_op(Dwarf_Op *op) +{ + switch (op->atom) { + case DW_OP_reg0 ... DW_OP_reg31: + case DW_OP_regx: + return 0; + case DW_OP_breg0 ... DW_OP_breg31: + return op->number; + case DW_OP_bregx: + return op->number2; + default: + break; + } + return -1; +} +#endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT || HAVE_DWARF_CFI_SUPPORT */ + #ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT /** * die_get_var_innermost_scope - Get innermost scope range of given variable DIE @@ -1476,41 +1510,69 @@ Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr addr, *offset = data.offset; return result; } -#endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ -#ifdef HAVE_DWARF_CFI_SUPPORT -static int reg_from_dwarf_op(Dwarf_Op *op) +static int __die_collect_vars_cb(Dwarf_Die *die_mem, void *arg) { - switch (op->atom) { - case DW_OP_reg0 ... DW_OP_reg31: - return op->atom - DW_OP_reg0; - case DW_OP_breg0 ... DW_OP_breg31: - return op->atom - DW_OP_breg0; - case DW_OP_regx: - case DW_OP_bregx: - return op->number; - default: - break; - } - return -1; + struct die_var_type **var_types = arg; + Dwarf_Die type_die; + int tag = dwarf_tag(die_mem); + Dwarf_Attribute attr; + Dwarf_Addr base, start, end; + Dwarf_Op *ops; + size_t nops; + struct die_var_type *vt; + + if (tag != DW_TAG_variable && tag != DW_TAG_formal_parameter) + return DIE_FIND_CB_SIBLING; + + if (dwarf_attr(die_mem, DW_AT_location, &attr) == NULL) + return DIE_FIND_CB_SIBLING; + + /* + * Only collect the first location as it can reconstruct the + * remaining state by following the instructions. + * start = 0 means it covers the whole range. + */ + if (dwarf_getlocations(&attr, 0, &base, &start, &end, &ops, &nops) <= 0) + return DIE_FIND_CB_SIBLING; + + if (die_get_real_type(die_mem, &type_die) == NULL) + return DIE_FIND_CB_SIBLING; + + vt = malloc(sizeof(*vt)); + if (vt == NULL) + return DIE_FIND_CB_END; + + vt->die_off = dwarf_dieoffset(&type_die); + vt->addr = start; + vt->reg = reg_from_dwarf_op(ops); + vt->offset = offset_from_dwarf_op(ops); + vt->next = *var_types; + *var_types = vt; + + return DIE_FIND_CB_SIBLING; } -static int offset_from_dwarf_op(Dwarf_Op *op) +/** + * die_collect_vars - Save all variables and parameters + * @sc_die: a scope DIE + * @var_types: a pointer to save the resulting list + * + * Save all variables and parameters in the @sc_die and save them to @var_types. + * The @var_types is a singly-linked list containing type and location info. + * Actual type can be retrieved using dwarf_offdie() with 'die_off' later. + * + * Callers should free @var_types. + */ +void die_collect_vars(Dwarf_Die *sc_die, struct die_var_type **var_types) { - switch (op->atom) { - case DW_OP_reg0 ... DW_OP_reg31: - case DW_OP_regx: - return 0; - case DW_OP_breg0 ... DW_OP_breg31: - return op->number; - case DW_OP_bregx: - return op->number2; - default: - break; - } - return -1; + Dwarf_Die die_mem; + + die_find_child(sc_die, __die_collect_vars_cb, (void *)var_types, &die_mem); } +#endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ +#ifdef HAVE_DWARF_CFI_SUPPORT /** * die_get_cfa - Get frame base information * @dwarf: a Dwarf info diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 9973801a20c1..cd171b06fd4c 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -135,6 +135,15 @@ void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, /* Get the list of including scopes */ int die_get_scopes(Dwarf_Die *cu_die, Dwarf_Addr pc, Dwarf_Die **scopes); +/* Variable type information */ +struct die_var_type { + struct die_var_type *next; + u64 die_off; + u64 addr; + int reg; + int offset; +}; + #ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT /* Get byte offset range of given variable DIE */ @@ -149,6 +158,9 @@ Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr addr, Dwarf_Die *die_mem, int *offset); +/* Save all variables and parameters in this scope */ +void die_collect_vars(Dwarf_Die *sc_die, struct die_var_type **var_types); + #else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ static inline int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, @@ -176,6 +188,11 @@ static inline Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die __maybe_unu return NULL; } +static inline void die_collect_vars(Dwarf_Die *sc_die __maybe_unused, + struct die_var_type **var_types __maybe_unused) +{ +} + #endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ #ifdef HAVE_DWARF_CFI_SUPPORT From patchwork Tue Mar 19 05:50:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596132 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9EE7A7BAE2; Tue, 19 Mar 2024 05:51:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827479; cv=none; b=GcSTefz54OlAPUKzXoODufw2gOhX7nPtUds18C7Z/vy20ItQadyeVM6/U5HL/x/qXTP/F1KkGrmzNJjqmZOKJWzJLboPkj2lS0Hn1coC18WPBZP8WsKPpJFG8YNxTY+Sdin3doo1bIBQkw2iNbrDhCnjjjxReZS/ekVartBR8Aw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827479; c=relaxed/simple; bh=D4wjM5/Vro/0+8JywfcuXi11ySFZtDEA5F2ZmXZ1Ue4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tfQl0hJa1UwV33F1duawBHCyjf58+OiJ+pHOpBTyyVNkqhVlDmNwR3rXH93JIN79ACe9KnkROSCKfLjDl/NyO19xK7JSN46NXyQbCHA6OoDnjZ9qNeyHmEkbFq43sDNi6vNbNfq4DEGkez/ugqUIiqSldlfEzfEahgpLfl0a8Sk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nB9mEA4J; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nB9mEA4J" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AF03BC4167E; Tue, 19 Mar 2024 05:51:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827479; bh=D4wjM5/Vro/0+8JywfcuXi11ySFZtDEA5F2ZmXZ1Ue4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nB9mEA4J/Ax61BWXfbJa+7gpFM8i4CTZOk19XhkshI1lg0tQqkHHUOtwP2fZMtIgw QpuE3ogp+myRXaraE9BtjtteqICRp713lkIcannBve0nLkeql47BXMBxU0R/N7cMv6 sVCu4QjIkakpBU16fAhrbHEAD0rTn0U5oZI1NXxVeX/Sxmx/TryJwCEVhHqaklzlMM 2lJlIZIxJFty3JooojlomZaaiJZt/yJMbvPeWWt4KC/3sS5zzyURN28TYPKx7v4tLp 0AYUhYpiiQDnY3iq5mG9xfI1VimzfDmK8cNY70BQksSxqFbQCJa2tZaEvCZ85qaYOw LyGTQDe+LHeQQ== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 03/23] perf dwarf-aux: Handle type transfer for memory access Date: Mon, 18 Mar 2024 22:50:55 -0700 Message-ID: <20240319055115.4063940-4-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 We want to track type states as instructions are executed. Each instruction can access compound types like struct or union and load/ store its members to a different location. The die_deref_ptr_type() is to find a type of memory access with a pointer variable. If it points to a compound type like struct, the target memory is a member in the struct. The access will happen with an offset indicating which member it refers. Let's follow the DWARF info to figure out the type of the pointer target. For example, say we have the following code. struct foo { int a; int b; }; struct foo *p = malloc(sizeof(*p)); p->b = 0; The last pointer access should produce x86 asm like below: mov 0x0, 4(%rbx) And we know %rbx register has a pointer to struct foo. Then offset 4 should return the debug info of member 'b'. Also variables of compound types can be accessed directly without a pointer. The die_get_member_type() is to handle a such case. Acked-by: Masami Hiramatsu (Google) Signed-off-by: Namhyung Kim --- tools/perf/util/dwarf-aux.c | 110 ++++++++++++++++++++++++++++++++++++ tools/perf/util/dwarf-aux.h | 6 ++ 2 files changed, 116 insertions(+) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 785aa7a3d725..cd9364d296b6 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1838,3 +1838,113 @@ int die_get_scopes(Dwarf_Die *cu_die, Dwarf_Addr pc, Dwarf_Die **scopes) *scopes = data.scopes; return data.nr; } + +static int __die_find_member_offset_cb(Dwarf_Die *die_mem, void *arg) +{ + Dwarf_Die type_die; + Dwarf_Word size, loc; + Dwarf_Word offset = (long)arg; + int tag = dwarf_tag(die_mem); + + if (tag != DW_TAG_member) + return DIE_FIND_CB_SIBLING; + + /* Unions might not have location */ + if (die_get_data_member_location(die_mem, &loc) < 0) + loc = 0; + + if (offset == loc) + return DIE_FIND_CB_END; + + die_get_real_type(die_mem, &type_die); + + if (dwarf_aggregate_size(&type_die, &size) < 0) + size = 0; + + if (loc < offset && offset < (loc + size)) + return DIE_FIND_CB_END; + + return DIE_FIND_CB_SIBLING; +} + +/** + * die_get_member_type - Return type info of struct member + * @type_die: a type DIE + * @offset: offset in the type + * @die_mem: a buffer to save the resulting DIE + * + * This function returns a type of a member in @type_die where it's located at + * @offset if it's a struct. For now, it just returns the first matching + * member in a union. For other types, it'd return the given type directly + * if it's within the size of the type or NULL otherwise. + */ +Dwarf_Die *die_get_member_type(Dwarf_Die *type_die, int offset, + Dwarf_Die *die_mem) +{ + Dwarf_Die *member; + Dwarf_Die mb_type; + int tag; + + tag = dwarf_tag(type_die); + /* If it's not a compound type, return the type directly */ + if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { + Dwarf_Word size; + + if (dwarf_aggregate_size(type_die, &size) < 0) + size = 0; + + if ((unsigned)offset >= size) + return NULL; + + *die_mem = *type_die; + return die_mem; + } + + mb_type = *type_die; + /* TODO: Handle union types better? */ + while (tag == DW_TAG_structure_type || tag == DW_TAG_union_type) { + member = die_find_child(&mb_type, __die_find_member_offset_cb, + (void *)(long)offset, die_mem); + if (member == NULL) + return NULL; + + if (die_get_real_type(member, &mb_type) == NULL) + return NULL; + + tag = dwarf_tag(&mb_type); + + if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type) { + Dwarf_Word loc; + + /* Update offset for the start of the member struct */ + if (die_get_data_member_location(member, &loc) == 0) + offset -= loc; + } + } + *die_mem = mb_type; + return die_mem; +} + +/** + * die_deref_ptr_type - Return type info for pointer access + * @ptr_die: a pointer type DIE + * @offset: access offset for the pointer + * @die_mem: a buffer to save the resulting DIE + * + * This function follows the pointer in @ptr_die with given @offset + * and saves the resulting type in @die_mem. If the pointer points + * a struct type, actual member at the offset would be returned. + */ +Dwarf_Die *die_deref_ptr_type(Dwarf_Die *ptr_die, int offset, + Dwarf_Die *die_mem) +{ + Dwarf_Die type_die; + + if (dwarf_tag(ptr_die) != DW_TAG_pointer_type) + return NULL; + + if (die_get_real_type(ptr_die, &type_die) == NULL) + return NULL; + + return die_get_member_type(&type_die, offset, die_mem); +} diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index cd171b06fd4c..16c916311bc0 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -144,6 +144,12 @@ struct die_var_type { int offset; }; +/* Return type info of a member at offset */ +Dwarf_Die *die_get_member_type(Dwarf_Die *type_die, int offset, Dwarf_Die *die_mem); + +/* Return type info where the pointer and offset point to */ +Dwarf_Die *die_deref_ptr_type(Dwarf_Die *ptr_die, int offset, Dwarf_Die *die_mem); + #ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT /* Get byte offset range of given variable DIE */ From patchwork Tue Mar 19 05:50:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596133 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 524277C0BA; Tue, 19 Mar 2024 05:51:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827480; cv=none; b=rkfbpXVsCmccrarJe3xgdcM0mnfStTc4n1l2vLc2/gjOzJv4lQ54PRnB5Iar2rjMH2AWSKFZtglEM93wqbBCLpSLQS2LNqo9YOJ7Y1x44BzPAiikcE8g5ryVapEVSyms2HACZ+HhaaVPULt4tl2zHp1xSPmmhLOTJSrzovQzO38= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827480; c=relaxed/simple; bh=WMphHepUfbpYGRKmFUiOHSnJjO7ivT7ai1Zyujs+j20=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eYjBf12Wj/SfiwPAJtloo/bM0mjRBbxFUWDDGEPLztnltUjUvna8D/tFHOOYistUkMDQcdDxYSVgJTpDJHRyG1qcL7zWD6dL4KyEZQz3S65HBznKJtHAQMvLbmJvTYuPvLEZ1G1qSvMkTZx0ww2eWpDLaSHiil/uVUXHLLIKqbg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HrPViAIc; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="HrPViAIc" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5D7BDC433B1; Tue, 19 Mar 2024 05:51:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827479; bh=WMphHepUfbpYGRKmFUiOHSnJjO7ivT7ai1Zyujs+j20=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HrPViAIc2rkJp3ROlZ/5mRnPP9LI3J+f3rT0y/CBSWeNuGMayEEhJUIPHX1PsEZC6 tmbQZ71+DRtskBu75xZgyzo8lgiCisfmKFm0oQ0RQneLHB90CPnTssgNuOAR6RBHRD lUZNVUAPG4yS4CPD07lKuBG+Ku6KdKyHnyMROPttdqNOrkGK+uARsXN2pHzyPTZZpl S546O/YhfRnqKGTmONHCPTiQTHr7gtv9HDLxUe4KnHSrnBKJwlYwiT9hHTTQTkN0kK TohtfDWCfkt96dwk9qkFHnIFamjCQxUBy1eZiZtTAFUlEPgbrxTfOCn8JInVEjebEg RcRMd8ocLc33A== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 04/23] perf dwarf-aux: Add die_find_func_rettype() Date: Mon, 18 Mar 2024 22:50:56 -0700 Message-ID: <20240319055115.4063940-5-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The die_find_func_rettype() is to find a debug entry for the given function name and sets the type information of the return value. By convention, it'd return the pointer to the type die (should be the same as the given mem_die argument) if found, or NULL otherwise. Cc: Masami Hiramatsu Signed-off-by: Namhyung Kim --- tools/perf/util/dwarf-aux.c | 43 +++++++++++++++++++++++++++++++++++++ tools/perf/util/dwarf-aux.h | 4 ++++ 2 files changed, 47 insertions(+) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index cd9364d296b6..9080119a258c 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -696,6 +696,49 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, return die_mem; } +static int __die_find_func_rettype_cb(Dwarf_Die *die_mem, void *data) +{ + const char *func_name; + + if (dwarf_tag(die_mem) != DW_TAG_subprogram) + return DIE_FIND_CB_SIBLING; + + func_name = dwarf_diename(die_mem); + if (func_name && !strcmp(func_name, data)) + return DIE_FIND_CB_END; + + return DIE_FIND_CB_SIBLING; +} + +/** + * die_find_func_rettype - Search a return type of function + * @cu_die: a CU DIE + * @name: target function name + * @die_mem: a buffer for result DIE + * + * Search a non-inlined function which matches to @name and stores the + * return type of the function to @die_mem and returns it if found. + * Returns NULL if failed. Note that it doesn't needs to find a + * definition of the function, so it doesn't match with address. + * Most likely, it can find a declaration at the top level. Thus the + * callback function continues to sibling entries only. + */ +Dwarf_Die *die_find_func_rettype(Dwarf_Die *cu_die, const char *name, + Dwarf_Die *die_mem) +{ + Dwarf_Die tmp_die; + + cu_die = die_find_child(cu_die, __die_find_func_rettype_cb, + (void *)name, &tmp_die); + if (!cu_die) + return NULL; + + if (die_get_real_type(&tmp_die, die_mem) == NULL) + return NULL; + + return die_mem; +} + struct __instance_walk_param { void *addr; int (*callback)(Dwarf_Die *, void *); diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 16c916311bc0..b0f25fbf9668 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -94,6 +94,10 @@ Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, Dwarf_Die *die_mem); +/* Search a non-inlined function by name and returns its return type */ +Dwarf_Die *die_find_func_rettype(Dwarf_Die *sp_die, const char *name, + Dwarf_Die *die_mem); + /* Walk on the instances of given DIE */ int die_walk_instances(Dwarf_Die *in_die, int (*callback)(Dwarf_Die *, void *), void *data); From patchwork Tue Mar 19 05:50:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596134 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C00F17CF0F; Tue, 19 Mar 2024 05:51:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827480; cv=none; b=E4n19kSIkQZXEhytjo9YwdDna34WQG2bcT2JeJGRd+ZUEnO9JVtg22+fZ5urwm+/1YVSbqs3e1MUYVMX83CEV5duy6wp8ckwsQLRNV4Srml7GaFq9Vx7MDW0+s3B0oFcIvl2eC+xjFikQSEn9gcQA66onA28pFVodMKLDuyEDYM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827480; c=relaxed/simple; bh=bAEbqgWbLQcfN0MLUSyPEU2jzHHBr14ThaOBDSWbtkE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TWz7TVejQcyRhuYOEUQr9eJbS/A0AlqsBZQ97eQOT9IxSUTtyOq/RLNMI+TlRkZDTpuP0j+E0xEtZ1DolF09KVhjZsq72VxsRDLymTauKlDAaytnhrMWeiqUgqp/lLzspsVaQWGcNxaK4Pm+2WoLSXoaU2TcrIYxNCWWSwNSMRM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Dl2o4ui5; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Dl2o4ui5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0C1ACC43142; Tue, 19 Mar 2024 05:51:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827480; bh=bAEbqgWbLQcfN0MLUSyPEU2jzHHBr14ThaOBDSWbtkE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Dl2o4ui5dqaiRWRM0Z5GOkX7RV6mXREl6wRfu+BD5PuBKCYiJZB8vD1hsD5yVmr5s D1J5wM2qgWjuUFABe32ywmnp8SovoSUpAgBjbIG5/XfxRqE5QGqcr1SjMPd+7D5/jg mbzclIly5Lki1PhigV2HqucZcpx04jUXJAzogdl2ltrW+GDrs/xOM4IbfORppN3Q+z Mkf5AV7xkW/kzTKyuIhv+XCgQr26aGEwqJ6/mSDCBFmBferaNKyvSq+PTXiJDWRbgq MlEmihcKYEaVBDV16EDUPW8eO4U+ED9KwDMzfhUySqfdPmLElOSUp2BYqOnvNz6a9i D7POQN3mWNTuw== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 05/23] perf map: Add map__objdump_2rip() Date: Mon, 18 Mar 2024 22:50:57 -0700 Message-ID: <20240319055115.4063940-6-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Sometimes we want to convert an address in objdump output to map-relative address to match with a sample data. Let's add map__objdump_2rip() for that. Cc: Adrian Hunter Signed-off-by: Namhyung Kim --- tools/perf/util/map.c | 17 +++++++++++++++++ tools/perf/util/map.h | 3 +++ 2 files changed, 20 insertions(+) diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 14a5ea70d81e..a5d57c201a30 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -587,6 +587,23 @@ u64 map__objdump_2mem(struct map *map, u64 ip) return ip + map__reloc(map); } +/* convert objdump address to relative address. (To be removed) */ +u64 map__objdump_2rip(struct map *map, u64 ip) +{ + const struct dso *dso = map__dso(map); + + if (!dso->adjust_symbols) + return ip; + + if (dso->rel) + return ip + map__pgoff(map); + + if (dso->kernel == DSO_SPACE__USER) + return ip - dso->text_offset; + + return map__map_ip(map, ip + map__reloc(map)); +} + bool map__contains_symbol(const struct map *map, const struct symbol *sym) { u64 ip = map__unmap_ip(map, sym->start); diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 49756716cb13..65e2609fa1b1 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -132,6 +132,9 @@ u64 map__rip_2objdump(struct map *map, u64 rip); /* objdump address -> memory address */ u64 map__objdump_2mem(struct map *map, u64 ip); +/* objdump address -> rip */ +u64 map__objdump_2rip(struct map *map, u64 ip); + struct symbol; struct thread; From patchwork Tue Mar 19 05:50:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596135 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8FD7A7D083; Tue, 19 Mar 2024 05:51:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827481; cv=none; b=d3fhtoS1+KDImLG2GN5RRRpY1dl6INH8NP36x6TIYiZVnkhvFhTfzmjfz5+ULEmDEgSyjHw913DeWie9H6pMrXNU/ZhSUe88PwSNAWX5mbfjQHYO30xa7E+MeszxcfnmVerIneDls56U5QfrZb39dv6FSU2g0hnNo9Gf4XD31D0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827481; c=relaxed/simple; bh=UX9mTUvbk7qwxvPah6fBFKMdKSmHpzJRI47a0N/qiEY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LEjVfzlAsO9IbMRqd2oFeZvOhjB4klFvP4w9upJLu4lowtiq6OfJMtqSqym8nCi2WQM+t/8zThKatKt84/XL5/tUwI3WwnfXkhoLekcZxGMT+KCY1CSbFBlEpebAf2QKnGaXIgcYzRx4dKMoCau8XaPeeaSjPyNOAqaUAqIzggU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bhtlHHFr; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="bhtlHHFr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9FE7EC43330; Tue, 19 Mar 2024 05:51:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827481; bh=UX9mTUvbk7qwxvPah6fBFKMdKSmHpzJRI47a0N/qiEY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bhtlHHFr1qOHAZRR7PsjBrdIUKeriX+xUVwAJKWC1SyNkAE7rQ10YXvMTGx2zTPxk Xug31p9k8w7EZj3a6bgLW8ytzmxNK43/aFhptbvMkN0wMAWTSwOuvgiU9BA5xFjE7F SBJH+SEf2D0lrlNcctZR3iH7c+23M/MGF5o22xWfxdGUPKyS25p/dBASja5BcgcaDS 5yhv+TOLRMDqqyKEUnQ8mW71vqTH/EuFjp8rzHvYd8K8mpON7rXm+Q3a/i4bVrtZVy spvQ6Z04Zad49mwcBOs2RHLS7MvnxhFM7Bx14oJ9+4TULDrcPI2KSqzO94P5MWh3nu wbHCDoy5SGDhQ== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 06/23] perf annotate-data: Introduce struct data_loc_info Date: Mon, 18 Mar 2024 22:50:58 -0700 Message-ID: <20240319055115.4063940-7-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The find_data_type() needs many information to describe the location of the data. Add the new struct data_loc_info to pass those information at once. No functional changes intended. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 83 +++++++++++++++++---------------- tools/perf/util/annotate-data.h | 38 ++++++++++++--- tools/perf/util/annotate.c | 30 ++++++------ 3 files changed, 91 insertions(+), 60 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 59ce5f4f4a40..ff81d164aa57 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -239,21 +239,28 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset, } /* The result will be saved in @type_die */ -static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, - const char *var_name, struct annotated_op_loc *loc, - Dwarf_Die *type_die) +static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) { + struct annotated_op_loc *loc = dloc->op; Dwarf_Die cu_die, var_die; Dwarf_Die *scopes = NULL; int reg, offset; int ret = -1; int i, nr_scopes; int fbreg = -1; - bool is_fbreg = false; int fb_offset = 0; + bool is_fbreg = false; + u64 pc; + + /* + * IP is a relative instruction address from the start of the map, as + * it can be randomized/relocated, it needs to translate to PC which is + * a file address for DWARF processing. + */ + pc = map__rip_2objdump(dloc->ms->map, dloc->ip); /* Get a compile_unit for this address */ - if (!find_cu_die(di, pc, &cu_die)) { + if (!find_cu_die(dloc->di, pc, &cu_die)) { pr_debug("cannot find CU for address %" PRIx64 "\n", pc); ann_data_stat.no_cuinfo++; return -1; @@ -263,18 +270,19 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, offset = loc->offset; if (reg == DWARF_REG_PC) { - if (die_find_variable_by_addr(&cu_die, addr, &var_die, &offset)) { + if (die_find_variable_by_addr(&cu_die, dloc->var_addr, &var_die, + &offset)) { ret = check_variable(&var_die, type_die, offset, /*is_pointer=*/false); - loc->offset = offset; + dloc->type_offset = offset; goto out; } - if (var_name && die_find_variable_at(&cu_die, var_name, pc, - &var_die)) { - ret = check_variable(&var_die, type_die, 0, + if (dloc->var_name && + die_find_variable_at(&cu_die, dloc->var_name, pc, &var_die)) { + ret = check_variable(&var_die, type_die, dloc->type_offset, /*is_pointer=*/false); - /* loc->offset will be updated by the caller */ + /* dloc->type_offset was updated by the caller */ goto out; } } @@ -291,10 +299,11 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, dwarf_formblock(&attr, &block) == 0 && block.length == 1) { switch (*block.data) { case DW_OP_reg0 ... DW_OP_reg31: - fbreg = *block.data - DW_OP_reg0; + fbreg = dloc->fbreg = *block.data - DW_OP_reg0; break; case DW_OP_call_frame_cfa: - if (die_get_cfa(di->dbg, pc, &fbreg, + dloc->fb_cfa = true; + if (die_get_cfa(dloc->di->dbg, pc, &fbreg, &fb_offset) < 0) fbreg = -1; break; @@ -312,7 +321,7 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, /* Search from the inner-most scope to the outer */ for (i = nr_scopes - 1; i >= 0; i--) { if (reg == DWARF_REG_PC) { - if (!die_find_variable_by_addr(&scopes[i], addr, + if (!die_find_variable_by_addr(&scopes[i], dloc->var_addr, &var_die, &offset)) continue; } else { @@ -325,7 +334,7 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, /* Found a variable, see if it's correct */ ret = check_variable(&var_die, type_die, offset, reg != DWARF_REG_PC && !is_fbreg); - loc->offset = offset; + dloc->type_offset = offset; goto out; } @@ -344,50 +353,46 @@ static int find_data_type_die(struct debuginfo *di, u64 pc, u64 addr, /** * find_data_type - Return a data type at the location - * @ms: map and symbol at the location - * @ip: instruction address of the memory access - * @loc: instruction operand location - * @addr: data address of the memory access - * @var_name: global variable name + * @dloc: data location * * This functions searches the debug information of the binary to get the data - * type it accesses. The exact location is expressed by (@ip, reg, offset) - * for pointer variables or (@ip, @addr) for global variables. Note that global - * variables might update the @loc->offset after finding the start of the variable. - * If it cannot find a global variable by address, it tried to fine a declaration - * of the variable using @var_name. In that case, @loc->offset won't be updated. + * type it accesses. The exact location is expressed by (ip, reg, offset) + * for pointer variables or (ip, addr) for global variables. Note that global + * variables might update the @dloc->type_offset after finding the start of the + * variable. If it cannot find a global variable by address, it tried to find + * a declaration of the variable using var_name. In that case, @dloc->offset + * won't be updated. * * It return %NULL if not found. */ -struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip, - struct annotated_op_loc *loc, u64 addr, - const char *var_name) +struct annotated_data_type *find_data_type(struct data_loc_info *dloc) { struct annotated_data_type *result = NULL; - struct dso *dso = map__dso(ms->map); - struct debuginfo *di; + struct dso *dso = map__dso(dloc->ms->map); Dwarf_Die type_die; - u64 pc; - di = debuginfo__new(dso->long_name); - if (di == NULL) { + dloc->di = debuginfo__new(dso->long_name); + if (dloc->di == NULL) { pr_debug("cannot get the debug info\n"); return NULL; } /* - * IP is a relative instruction address from the start of the map, as - * it can be randomized/relocated, it needs to translate to PC which is - * a file address for DWARF processing. + * The type offset is the same as instruction offset by default. + * But when finding a global variable, the offset won't be valid. */ - pc = map__rip_2objdump(ms->map, ip); - if (find_data_type_die(di, pc, addr, var_name, loc, &type_die) < 0) + if (dloc->var_name == NULL) + dloc->type_offset = dloc->op->offset; + + dloc->fbreg = -1; + + if (find_data_type_die(dloc, &type_die) < 0) goto out; result = dso__findnew_data_type(dso, &type_die); out: - debuginfo__delete(di); + debuginfo__delete(dloc->di); return result; } diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index 1b0db8e8c40e..ad6493ea2c8e 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -8,6 +8,7 @@ #include struct annotated_op_loc; +struct debuginfo; struct evsel; struct map_symbol; @@ -72,6 +73,35 @@ struct annotated_data_type { extern struct annotated_data_type unknown_type; extern struct annotated_data_type stackop_type; +/** + * struct data_loc_info - Data location information + * @ms: Map and Symbol info + * @ip: Instruction address + * @var_addr: Data address (for global variables) + * @var_name: Variable name (for global variables) + * @op: Instruction operand location (regs and offset) + * @di: Debug info + * @fbreg: Frame base register + * @fb_cfa: Whether the frame needs to check CFA + * @type_offset: Final offset in the type + */ +struct data_loc_info { + /* These are input field, should be filled by caller */ + struct map_symbol *ms; + u64 ip; + u64 var_addr; + const char *var_name; + struct annotated_op_loc *op; + + /* These are used internally */ + struct debuginfo *di; + int fbreg; + bool fb_cfa; + + /* This is for the result */ + int type_offset; +}; + /** * struct annotated_data_stat - Debug statistics * @total: Total number of entry @@ -106,9 +136,7 @@ extern struct annotated_data_stat ann_data_stat; #ifdef HAVE_DWARF_SUPPORT /* Returns data type at the location (ip, reg, offset) */ -struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip, - struct annotated_op_loc *loc, u64 addr, - const char *var_name); +struct annotated_data_type *find_data_type(struct data_loc_info *dloc); /* Update type access histogram at the given offset */ int annotated_data_type__update_samples(struct annotated_data_type *adt, @@ -121,9 +149,7 @@ void annotated_data_type__tree_delete(struct rb_root *root); #else /* HAVE_DWARF_SUPPORT */ static inline struct annotated_data_type * -find_data_type(struct map_symbol *ms __maybe_unused, u64 ip __maybe_unused, - struct annotated_op_loc *loc __maybe_unused, - u64 addr __maybe_unused, const char *var_name __maybe_unused) +find_data_type(struct data_loc_info *dloc __maybe_unused) { return NULL; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ac002d907d81..a15ff6758210 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3816,9 +3816,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) struct annotated_op_loc *op_loc; struct annotated_data_type *mem_type; struct annotated_item_stat *istat; - u64 ip = he->ip, addr = 0; - const char *var_name = NULL; - int var_offset; + u64 ip = he->ip; int i; ann_data_stat.total++; @@ -3871,51 +3869,53 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) } for_each_insn_op_loc(&loc, i, op_loc) { + struct data_loc_info dloc = { + .ms = ms, + /* Recalculate IP for LOCK prefix or insn fusion */ + .ip = ms->sym->start + dl->al.offset, + .op = op_loc, + }; + if (!op_loc->mem_ref) continue; /* Recalculate IP because of LOCK prefix or insn fusion */ ip = ms->sym->start + dl->al.offset; - var_offset = op_loc->offset; - /* PC-relative addressing */ if (op_loc->reg1 == DWARF_REG_PC) { struct addr_location al; struct symbol *var; u64 map_addr; - addr = annotate_calc_pcrel(ms, ip, op_loc->offset, dl); + dloc.var_addr = annotate_calc_pcrel(ms, ip, op_loc->offset, dl); /* Kernel symbols might be relocated */ - map_addr = addr + map__reloc(ms->map); + map_addr = dloc.var_addr + map__reloc(ms->map); addr_location__init(&al); var = thread__find_symbol_fb(he->thread, he->cpumode, map_addr, &al); if (var) { - var_name = var->name; + dloc.var_name = var->name; /* Calculate type offset from the start of variable */ - var_offset = map_addr - map__unmap_ip(al.map, var->start); + dloc.type_offset = map_addr - map__unmap_ip(al.map, var->start); } addr_location__exit(&al); } - mem_type = find_data_type(ms, ip, op_loc, addr, var_name); + mem_type = find_data_type(&dloc); if (mem_type) istat->good++; else istat->bad++; - if (mem_type && var_name) - op_loc->offset = var_offset; - if (symbol_conf.annotate_data_sample) { annotated_data_type__update_samples(mem_type, evsel, - op_loc->offset, + dloc.type_offset, he->stat.nr_events, he->stat.period); } - he->mem_type_off = op_loc->offset; + he->mem_type_off = dloc.type_offset; return mem_type; } From patchwork Tue Mar 19 05:50:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596136 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 21F397D3E8; Tue, 19 Mar 2024 05:51:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827482; cv=none; b=ron7YJNsd7ZWknpq77UjI/IXbFEvPTWLRr/vzBUsDVN08mrUmnFRvjDSpHhMujY7N+e2fX5M5Dp/+nJervCHOp8e8obzEiagOlGc7l79vwlAxp6dTyBJ1L+s3jgNPdLRwwiRm2t3ngsnjyddozsf7/XpBFBMNB2Tr6AVziBHDpY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827482; c=relaxed/simple; bh=beUl6blEtLFpiy/dZzX6/DRoESkELbLAoD5QdQPI8fs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Vkf0ZQhVguYysFwcq5Ee7evJVtDTyG0Zvilb58Q6BcjJQM6Len0PvG8YO96m3FDZwKh3H1rUBLReYstL/7wp5p9TXv4BOpTd8+yyvZzcnQ9RcKyqZddzpZMLoWRYhfkFiy84AH+UiShxVhjovB0aqtym3FVJyuExON9tptd/Buw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JE+qAQRk; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JE+qAQRk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 43926C433C7; Tue, 19 Mar 2024 05:51:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827481; bh=beUl6blEtLFpiy/dZzX6/DRoESkELbLAoD5QdQPI8fs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JE+qAQRk1t6zUqCpj9UupatFfd0/m40ZqYWI9u1EiGQT8BqQuKCYAJAtv8U5/WTSR hOLrlFq21tTQ3JnBdChH4PxNkJM4Fozxu/C+DzW1AbhiAqXROIHMI8ZEywMvboRO1N /encjUbnP7BM6yxjmnUdTOxyGxRkle0i0hUtfXeoLwYzqV3i4U/rC6/ZU1nd9R0S7I MUnjgPZrRaWufy791pbZVYAXExTvLLKsfic/SX5gKjZK2HArXZoofjyuCzMy49goB8 +vs3yBPd4arX8dEzuffI73/QhcK9Wfq/ZaDbVPLvcJkZV2TKSZufC2gkhzwvzBGblf JWIJ8FzdgS9aQ== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 07/23] perf annotate: Add annotate_get_basic_blocks() Date: Mon, 18 Mar 2024 22:50:59 -0700 Message-ID: <20240319055115.4063940-8-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The annotate_get_basic_blocks() is to find a list of basic blocks from the source instruction to the destination instruction in a function. It'll be used to find variables in a scope. Use BFS (Breadth First Search) to find a shortest path to carry the variable/register state minimally. Also change find_disasm_line() to be used in annotate_get_basic_blocks() and add 'allow_update' argument to control if it can update the IP. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate.c | 222 ++++++++++++++++++++++++++++++++++++- tools/perf/util/annotate.h | 16 +++ 2 files changed, 235 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a15ff6758210..aa005c13ff67 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3714,7 +3714,8 @@ static void symbol__ensure_annotate(struct map_symbol *ms, struct evsel *evsel) } } -static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip) +static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip, + bool allow_update) { struct disasm_line *dl; struct annotation *notes; @@ -3727,7 +3728,8 @@ static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip) * llvm-objdump places "lock" in a separate line and * in that case, we want to get the next line. */ - if (!strcmp(dl->ins.name, "lock") && *dl->ops.raw == '\0') { + if (!strcmp(dl->ins.name, "lock") && + *dl->ops.raw == '\0' && allow_update) { ip++; continue; } @@ -3843,7 +3845,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) * Get a disasm to extract the location from the insn. * This is too slow... */ - dl = find_disasm_line(ms->sym, ip); + dl = find_disasm_line(ms->sym, ip, /*allow_update=*/true); if (dl == NULL) { ann_data_stat.no_insn++; return NULL; @@ -3937,3 +3939,217 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) istat->bad++; return NULL; } + +/* Basic block traversal (BFS) data structure */ +struct basic_block_data { + struct list_head queue; + struct list_head visited; +}; + +/* + * During the traversal, it needs to know the parent block where the current + * block block started from. Note that single basic block can be parent of + * two child basic blocks (in case of condition jump). + */ +struct basic_block_link { + struct list_head node; + struct basic_block_link *parent; + struct annotated_basic_block *bb; +}; + +/* Check any of basic block in the list already has the offset */ +static bool basic_block_has_offset(struct list_head *head, s64 offset) +{ + struct basic_block_link *link; + + list_for_each_entry(link, head, node) { + s64 begin_offset = link->bb->begin->al.offset; + s64 end_offset = link->bb->end->al.offset; + + if (begin_offset <= offset && offset <= end_offset) + return true; + } + return false; +} + +static bool is_new_basic_block(struct basic_block_data *bb_data, + struct disasm_line *dl) +{ + s64 offset = dl->al.offset; + + if (basic_block_has_offset(&bb_data->visited, offset)) + return false; + if (basic_block_has_offset(&bb_data->queue, offset)) + return false; + return true; +} + +/* Add a basic block starting from dl and link it to the parent */ +static int add_basic_block(struct basic_block_data *bb_data, + struct basic_block_link *parent, + struct disasm_line *dl) +{ + struct annotated_basic_block *bb; + struct basic_block_link *link; + + if (dl == NULL) + return -1; + + if (!is_new_basic_block(bb_data, dl)) + return 0; + + bb = zalloc(sizeof(*bb)); + if (bb == NULL) + return -1; + + bb->begin = dl; + bb->end = dl; + INIT_LIST_HEAD(&bb->list); + + link = malloc(sizeof(*link)); + if (link == NULL) { + free(bb); + return -1; + } + + link->bb = bb; + link->parent = parent; + list_add_tail(&link->node, &bb_data->queue); + return 0; +} + +/* Returns true when it finds the target in the current basic block */ +static bool process_basic_block(struct basic_block_data *bb_data, + struct basic_block_link *link, + struct symbol *sym, u64 target) +{ + struct disasm_line *dl, *next_dl, *last_dl; + struct annotation *notes = symbol__annotation(sym); + bool found = false; + + dl = link->bb->begin; + /* Check if it's already visited */ + if (basic_block_has_offset(&bb_data->visited, dl->al.offset)) + return false; + + last_dl = list_last_entry(¬es->src->source, + struct disasm_line, al.node); + + list_for_each_entry_from(dl, ¬es->src->source, al.node) { + /* Found the target instruction */ + if (sym->start + dl->al.offset == target) { + found = true; + break; + } + /* End of the function, finish the block */ + if (dl == last_dl) + break; + /* 'return' instruction finishes the block */ + if (dl->ins.ops == &ret_ops) + break; + /* normal instructions are part of the basic block */ + if (dl->ins.ops != &jump_ops) + continue; + /* jump to a different function, tail call or return */ + if (dl->ops.target.outside) + break; + /* jump instruction creates new basic block(s) */ + next_dl = find_disasm_line(sym, sym->start + dl->ops.target.offset, + /*allow_update=*/false); + add_basic_block(bb_data, link, next_dl); + + /* + * FIXME: determine conditional jumps properly. + * Conditional jumps create another basic block with the + * next disasm line. + */ + if (!strstr(dl->ins.name, "jmp")) { + next_dl = list_next_entry(dl, al.node); + add_basic_block(bb_data, link, next_dl); + } + break; + + } + link->bb->end = dl; + return found; +} + +/* + * It founds a target basic block, build a proper linked list of basic blocks + * by following the link recursively. + */ +static void link_found_basic_blocks(struct basic_block_link *link, + struct list_head *head) +{ + while (link) { + struct basic_block_link *parent = link->parent; + + list_move(&link->bb->list, head); + list_del(&link->node); + free(link); + + link = parent; + } +} + +static void delete_basic_blocks(struct basic_block_data *bb_data) +{ + struct basic_block_link *link, *tmp; + + list_for_each_entry_safe(link, tmp, &bb_data->queue, node) { + list_del(&link->node); + free(link->bb); + free(link); + } + + list_for_each_entry_safe(link, tmp, &bb_data->visited, node) { + list_del(&link->node); + free(link->bb); + free(link); + } +} + +/** + * annotate_get_basic_blocks - Get basic blocks for given address range + * @sym: symbol to annotate + * @src: source address + * @dst: destination address + * @head: list head to save basic blocks + * + * This function traverses disasm_lines from @src to @dst and save them in a + * list of annotated_basic_block to @head. It uses BFS to find the shortest + * path between two. The basic_block_link is to maintain parent links so + * that it can build a list of blocks from the start. + */ +int annotate_get_basic_blocks(struct symbol *sym, s64 src, s64 dst, + struct list_head *head) +{ + struct basic_block_data bb_data = { + .queue = LIST_HEAD_INIT(bb_data.queue), + .visited = LIST_HEAD_INIT(bb_data.visited), + }; + struct basic_block_link *link; + struct disasm_line *dl; + int ret = -1; + + dl = find_disasm_line(sym, src, /*allow_update=*/false); + if (dl == NULL) + return -1; + + if (add_basic_block(&bb_data, /*parent=*/NULL, dl) < 0) + return -1; + + /* Find shortest path from src to dst using BFS */ + while (!list_empty(&bb_data.queue)) { + link = list_first_entry(&bb_data.queue, struct basic_block_link, node); + + if (process_basic_block(&bb_data, link, sym, dst)) { + link_found_basic_blocks(link, head); + ret = 0; + break; + } + list_move(&link->node, &bb_data.visited); + } + delete_basic_blocks(&bb_data); + return ret; +} diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 13cc659e508c..0928663fddee 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -561,4 +561,20 @@ extern struct list_head ann_insn_stat; u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset, struct disasm_line *dl); +/** + * struct annotated_basic_block - Basic block of instructions + * @list: List node + * @begin: start instruction in the block + * @end: end instruction in the block + */ +struct annotated_basic_block { + struct list_head list; + struct disasm_line *begin; + struct disasm_line *end; +}; + +/* Get a list of basic blocks from src to dst addresses */ +int annotate_get_basic_blocks(struct symbol *sym, s64 src, s64 dst, + struct list_head *head); + #endif /* __PERF_ANNOTATE_H */ From patchwork Tue Mar 19 05:51:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596137 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF1477D41B; Tue, 19 Mar 2024 05:51:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827482; cv=none; b=uEaTcrrNUbWmeoXqpCCzv0lZLltqu+R9VeCkAzZz0lx8p6FtAfhzVXUUEzPT5nxkjWgQ6pjKbm6Cba9UzjHoN/cvtRxzE21ygkwAOImwtK4HkvHhKEd0m0LtUlWP5o4o0tKFrwCE0szvxb9e7fZf1b12JNTLQ/nc7K0TBALUQWo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827482; c=relaxed/simple; bh=ek6tyO55YdT1JBe57BgyHQSsS0HIXVRzIrOiaUCJ7Rs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=l6RCy11FB4Wpz1YdpqIycmzcjPijznvu4398PaA1Vs086H1/qUZLg9THGVQ7pXxABul8SlzL4+Z2nrcG5FbWKa4+/Jd3NhWqHkZt9E1QubZUiovrWGrHIxDv9K00EqQZO3WjNRQn4tGGnWu4sYqdSHCTEzX7F8uwfysaAca1hqw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UsrZ/AVi; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UsrZ/AVi" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D8FE4C43601; Tue, 19 Mar 2024 05:51:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827482; bh=ek6tyO55YdT1JBe57BgyHQSsS0HIXVRzIrOiaUCJ7Rs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UsrZ/AViHFVoq9A7uDh/gzfcOtJNEFoQ/bRR4QNJdM3Hq4LKCIeZMsNB5PgvHjVUi nm2bKuZNZpVNxSu1hKRvpHWWGJ/TA2tzePiF+6H2iQVXTstyOk9UQ5xiFjcfwpHIZ0 ddtJLwJESmqjAS8gGPM9XQykf9qnHXSZkXDo5UhDM++xXqwDaD4YNf4XjCFqovmCqI OQHlpP4da9MdH/S8EwVikZoWMyJ1MKVtjMqcZ62TDguZ9cklX7JRw8X7wVbdNHWt+F gzSt2Cerft2hEMBOQOzgXK0JhzLbnHjz9lvlcAjNRc8sLaWcm5zPePj4RVfpF0+MLU WqUMQMDZf27Ug== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 08/23] perf annotate-data: Add debug messages Date: Mon, 18 Mar 2024 22:51:00 -0700 Message-ID: <20240319055115.4063940-9-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add a new debug option "type-profile" to enable the detailed info during the type analysis especially for instruction tracking. You can use this before the command name like 'report' or 'annotate'. $ perf --debug type-profile annotate --data-type Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate-data.c | 74 +++++++++++++++++++++++++++++---- tools/perf/util/debug.c | 3 ++ tools/perf/util/debug.h | 1 + 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index ff81d164aa57..f482ccfdaa91 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -23,6 +23,29 @@ #include "symbol.h" #include "symbol_conf.h" +#define pr_debug_dtp(fmt, ...) \ +do { \ + if (debug_type_profile) \ + pr_info(fmt, ##__VA_ARGS__); \ + else \ + pr_debug3(fmt, ##__VA_ARGS__); \ +} while (0) + +static void pr_debug_type_name(Dwarf_Die *die) +{ + struct strbuf sb; + char *str; + + if (!debug_type_profile && verbose < 3) + return; + + strbuf_init(&sb, 32); + die_get_typename_from_type(die, &sb); + str = strbuf_detach(&sb, NULL); + pr_info(" type=%s (die:%lx)\n", str, (long)dwarf_dieoffset(die)); + free(str); +} + /* * Compare type name and size to maintain them in a tree. * I'm not sure if DWARF would have information of a single type in many @@ -201,7 +224,7 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset, /* Get the type of the variable */ if (die_get_real_type(var_die, type_die) == NULL) { - pr_debug("variable has no type\n"); + pr_debug_dtp("variable has no type\n"); ann_data_stat.no_typeinfo++; return -1; } @@ -215,7 +238,7 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset, if ((dwarf_tag(type_die) != DW_TAG_pointer_type && dwarf_tag(type_die) != DW_TAG_array_type) || die_get_real_type(type_die, type_die) == NULL) { - pr_debug("no pointer or no type\n"); + pr_debug_dtp("no pointer or no type\n"); ann_data_stat.no_typeinfo++; return -1; } @@ -223,14 +246,15 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset, /* Get the size of the actual type */ if (dwarf_aggregate_size(type_die, &size) < 0) { - pr_debug("type size is unknown\n"); + pr_debug_dtp("type size is unknown\n"); ann_data_stat.invalid_size++; return -1; } /* Minimal sanity check */ if ((unsigned)offset >= size) { - pr_debug("offset: %d is bigger than size: %" PRIu64 "\n", offset, size); + pr_debug_dtp("offset: %d is bigger than size: %"PRIu64"\n", + offset, size); ann_data_stat.bad_offset++; return -1; } @@ -251,6 +275,19 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) int fb_offset = 0; bool is_fbreg = false; u64 pc; + char buf[64]; + + if (dloc->op->multi_regs) + snprintf(buf, sizeof(buf), " or reg%d", dloc->op->reg2); + else if (dloc->op->reg1 == DWARF_REG_PC) + snprintf(buf, sizeof(buf), " (PC)"); + else + buf[0] = '\0'; + + pr_debug_dtp("-----------------------------------------------------------\n"); + pr_debug_dtp("%s [%"PRIx64"] for reg%d%s offset=%#x in %s\n", + __func__, dloc->ip - dloc->ms->sym->start, + dloc->op->reg1, buf, dloc->op->offset, dloc->ms->sym->name); /* * IP is a relative instruction address from the start of the map, as @@ -261,7 +298,7 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) /* Get a compile_unit for this address */ if (!find_cu_die(dloc->di, pc, &cu_die)) { - pr_debug("cannot find CU for address %" PRIx64 "\n", pc); + pr_debug_dtp("cannot find CU for address %"PRIx64"\n", pc); ann_data_stat.no_cuinfo++; return -1; } @@ -269,12 +306,17 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) reg = loc->reg1; offset = loc->offset; + pr_debug_dtp("CU die offset: %#lx\n", (long)dwarf_dieoffset(&cu_die)); + if (reg == DWARF_REG_PC) { if (die_find_variable_by_addr(&cu_die, dloc->var_addr, &var_die, &offset)) { ret = check_variable(&var_die, type_die, offset, /*is_pointer=*/false); dloc->type_offset = offset; + + pr_debug_dtp("found PC-rel by addr=%#"PRIx64" offset=%#x\n", + dloc->var_addr, offset); goto out; } @@ -310,6 +352,9 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) default: break; } + + pr_debug_dtp("frame base: cfa=%d fbreg=%d\n", + dloc->fb_cfa, fbreg); } } @@ -334,6 +379,19 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) /* Found a variable, see if it's correct */ ret = check_variable(&var_die, type_die, offset, reg != DWARF_REG_PC && !is_fbreg); + if (ret == 0) { + pr_debug_dtp("found \"%s\" in scope=%d/%d (die: %#lx) ", + dwarf_diename(&var_die), i+1, nr_scopes, + (long)dwarf_dieoffset(&scopes[i])); + if (reg == DWARF_REG_PC) + pr_debug_dtp("%#x(PC) offset=%#x", loc->offset, offset); + else if (reg == DWARF_REG_FB || is_fbreg) + pr_debug_dtp("%#x(reg%d) stack fb_offset=%#x offset=%#x", + loc->offset, reg, fb_offset, offset); + else + pr_debug_dtp("%#x(reg%d)", loc->offset, reg); + pr_debug_type_name(type_die); + } dloc->type_offset = offset; goto out; } @@ -343,8 +401,10 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) goto retry; } - if (ret < 0) + if (ret < 0) { + pr_debug_dtp("no variable found\n"); ann_data_stat.no_var++; + } out: free(scopes); @@ -373,7 +433,7 @@ struct annotated_data_type *find_data_type(struct data_loc_info *dloc) dloc->di = debuginfo__new(dso->long_name); if (dloc->di == NULL) { - pr_debug("cannot get the debug info\n"); + pr_debug_dtp("cannot get the debug info\n"); return NULL; } diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index c39ee0fcb8cf..d633d15329fa 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -41,6 +41,7 @@ static int redirect_to_stderr; int debug_data_convert; static FILE *_debug_file; bool debug_display_time; +int debug_type_profile; FILE *debug_file(void) { @@ -231,6 +232,7 @@ static struct sublevel_option debug_opts[] = { { .name = "data-convert", .value_ptr = &debug_data_convert }, { .name = "perf-event-open", .value_ptr = &debug_peo_args }, { .name = "kmaps", .value_ptr = &debug_kmaps }, + { .name = "type-profile", .value_ptr = &debug_type_profile }, { .name = NULL, } }; @@ -270,6 +272,7 @@ int perf_quiet_option(void) redirect_to_stderr = 0; debug_peo_args = 0; debug_kmaps = 0; + debug_type_profile = 0; return 0; } diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 35a7a5ae762e..a4026d1fd6a3 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -14,6 +14,7 @@ extern int debug_peo_args; extern bool quiet, dump_trace; extern int debug_ordered_events; extern int debug_data_convert; +extern int debug_type_profile; #ifndef pr_fmt #define pr_fmt(fmt) fmt From patchwork Tue Mar 19 05:51:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596138 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6B7137E11A; Tue, 19 Mar 2024 05:51:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827483; cv=none; b=bW7I/ISBKCJQ54STIbytHHGKacG3Cu4sMjBGjEJyB97RO+CtRK7bvMYbJXAu+G0Ay+xGELq5JDHoVpACyInGHiXtKpXXUF2xBhignemtA/yEcd3xTG+aCNiD20jQoOy/uq0s7JfA9JTe5iJ21WV3PUxPd1afIgsczFt+OxCGJZw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827483; c=relaxed/simple; bh=fhNxtapKIkDbH8Uy3IBe7yLRd7fJcDuZbr6w/rFDzOE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dAJLxqCyZmYfqLCNsNrVtS5uZ0UZabDaedDafZC+Jn/YVEDHu+O+OtP9GjFDokjJkwSL4Ctv97AUU8zugB0AvJ45zF93buq0A22EsYwrmOZSqfBQ4HL1rVBtg/AsCHGCBYHmsWahzhqV3pyzJGNXTJbKxvaBPS/2rfR6hFvAUYU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=F8WlFryv; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="F8WlFryv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 800F0C4166B; Tue, 19 Mar 2024 05:51:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827483; bh=fhNxtapKIkDbH8Uy3IBe7yLRd7fJcDuZbr6w/rFDzOE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=F8WlFryvloQB6nFyuVKy8qHQRe0r09HTuv2hYho3RoicNQa0+e5KpMKAxaFTHmq7K jNSDzniIqHRpdxZBX/c0cslX0GeBqiLnOEwu4jpx3NTinJtj8hY2E3eJFNWPy4PuC0 UoSBXA9liL+q5Orv3Df0S0jHaFJxhsBXSCWO19OmTEFASWX47HtMrFLJveCozdbRGF 44XunPCDniU4rCLU6bZx9NuN6ym2XN3jF2zQgMD9ZpVaE+cgcF2p69SV6hPjNQWhVD vxHX3FQRQuNIkxYCkJE0iYf9Di5lPTQHMCj42BT9VXy1HFgME4uQxNOQwH/5v0uotr /3LEaDw1vvXNQ== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 09/23] perf annotate-data: Maintain variable type info Date: Mon, 18 Mar 2024 22:51:01 -0700 Message-ID: <20240319055115.4063940-10-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 As it collected basic block and variable information in each scope, it now can build a state table to find matching variable at the location. The struct type_state is to keep the type info saved in each register and stack slot. The update_var_state() updates the table when it finds variables in the current address. It expects die_collect_vars() filled a list of variables with type info and starting address. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 173 ++++++++++++++++++++++++++++++++ tools/perf/util/dwarf-aux.c | 4 + 2 files changed, 177 insertions(+) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index f482ccfdaa91..8eaa06f1cee5 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -46,6 +46,62 @@ static void pr_debug_type_name(Dwarf_Die *die) free(str); } +/* Type information in a register, valid when ok is true */ +struct type_state_reg { + Dwarf_Die type; + bool ok; +}; + +/* Type information in a stack location, dynamically allocated */ +struct type_state_stack { + struct list_head list; + Dwarf_Die type; + int offset; + int size; + bool compound; +}; + +/* FIXME: This should be arch-dependent */ +#define TYPE_STATE_MAX_REGS 16 + +/* + * State table to maintain type info in each register and stack location. + * It'll be updated when new variable is allocated or type info is moved + * to a new location (register or stack). As it'd be used with the + * shortest path of basic blocks, it only maintains a single table. + */ +struct type_state { + struct type_state_reg regs[TYPE_STATE_MAX_REGS]; + struct list_head stack_vars; +}; + +static bool has_reg_type(struct type_state *state, int reg) +{ + return (unsigned)reg < ARRAY_SIZE(state->regs); +} + +/* These declarations will be remove once they are changed to static */ +void init_type_state(struct type_state *state, struct arch *arch __maybe_unused); +void exit_type_state(struct type_state *state); +void update_var_state(struct type_state *state, struct data_loc_info *dloc, + u64 addr, u64 insn_offset, struct die_var_type *var_types); + +void init_type_state(struct type_state *state, struct arch *arch __maybe_unused) +{ + memset(state, 0, sizeof(*state)); + INIT_LIST_HEAD(&state->stack_vars); +} + +void exit_type_state(struct type_state *state) +{ + struct type_state_stack *stack, *tmp; + + list_for_each_entry_safe(stack, tmp, &state->stack_vars, list) { + list_del(&stack->list); + free(stack); + } +} + /* * Compare type name and size to maintain them in a tree. * I'm not sure if DWARF would have information of a single type in many @@ -262,6 +318,123 @@ static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset, return 0; } +static struct type_state_stack *find_stack_state(struct type_state *state, + int offset) +{ + struct type_state_stack *stack; + + list_for_each_entry(stack, &state->stack_vars, list) { + if (offset == stack->offset) + return stack; + + if (stack->compound && stack->offset < offset && + offset < stack->offset + stack->size) + return stack; + } + return NULL; +} + +static void set_stack_state(struct type_state_stack *stack, int offset, + Dwarf_Die *type_die) +{ + int tag; + Dwarf_Word size; + + if (dwarf_aggregate_size(type_die, &size) < 0) + size = 0; + + tag = dwarf_tag(type_die); + + stack->type = *type_die; + stack->size = size; + stack->offset = offset; + + switch (tag) { + case DW_TAG_structure_type: + case DW_TAG_union_type: + stack->compound = true; + break; + default: + stack->compound = false; + break; + } +} + +static struct type_state_stack *findnew_stack_state(struct type_state *state, + int offset, Dwarf_Die *type_die) +{ + struct type_state_stack *stack = find_stack_state(state, offset); + + if (stack) { + set_stack_state(stack, offset, type_die); + return stack; + } + + stack = malloc(sizeof(*stack)); + if (stack) { + set_stack_state(stack, offset, type_die); + list_add(&stack->list, &state->stack_vars); + } + return stack; +} + +/** + * update_var_state - Update type state using given variables + * @state: type state table + * @dloc: data location info + * @addr: instruction address to match with variable + * @insn_offset: instruction offset (for debug) + * @var_types: list of variables with type info + * + * This function fills the @state table using @var_types info. Each variable + * is used only at the given location and updates an entry in the table. + */ +void update_var_state(struct type_state *state, struct data_loc_info *dloc, + u64 addr, u64 insn_offset, struct die_var_type *var_types) +{ + Dwarf_Die mem_die; + struct die_var_type *var; + int fbreg = dloc->fbreg; + int fb_offset = 0; + + if (dloc->fb_cfa) { + if (die_get_cfa(dloc->di->dbg, addr, &fbreg, &fb_offset) < 0) + fbreg = -1; + } + + for (var = var_types; var != NULL; var = var->next) { + if (var->addr != addr) + continue; + /* Get the type DIE using the offset */ + if (!dwarf_offdie(dloc->di->dbg, var->die_off, &mem_die)) + continue; + + if (var->reg == DWARF_REG_FB) { + findnew_stack_state(state, var->offset, &mem_die); + + pr_debug_dtp("var [%"PRIx64"] -%#x(stack) type=", + insn_offset, -var->offset); + pr_debug_type_name(&mem_die); + } else if (var->reg == fbreg) { + findnew_stack_state(state, var->offset - fb_offset, &mem_die); + + pr_debug_dtp("var [%"PRIx64"] -%#x(stack) type=", + insn_offset, -var->offset + fb_offset); + pr_debug_type_name(&mem_die); + } else if (has_reg_type(state, var->reg) && var->offset == 0) { + struct type_state_reg *reg; + + reg = &state->regs[var->reg]; + reg->type = mem_die; + reg->ok = true; + + pr_debug_dtp("var [%"PRIx64"] reg%d type=", + insn_offset, var->reg); + pr_debug_type_name(&mem_die); + } + } +} + /* The result will be saved in @type_die */ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) { diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 9080119a258c..41dbbb25b256 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -9,6 +9,7 @@ #include #include "debug.h" #include "dwarf-aux.h" +#include "dwarf-regs.h" #include "strbuf.h" #include "string2.h" @@ -1190,6 +1191,8 @@ static int reg_from_dwarf_op(Dwarf_Op *op) case DW_OP_regx: case DW_OP_bregx: return op->number; + case DW_OP_fbreg: + return DWARF_REG_FB; default: break; } @@ -1203,6 +1206,7 @@ static int offset_from_dwarf_op(Dwarf_Op *op) case DW_OP_regx: return 0; case DW_OP_breg0 ... DW_OP_breg31: + case DW_OP_fbreg: return op->number; case DW_OP_bregx: return op->number2; From patchwork Tue Mar 19 05:51:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596139 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 030C67E583; Tue, 19 Mar 2024 05:51:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827484; cv=none; b=BNn9MajwNHkp7u1tq5v5WdKAjaj8p95/82LJOa5GewM2njNcNJltxVoaVeRtI3/2PCb2nZ9eVjr6kJnt6D2Zb3pWrN4rEph0/dvV+QBQvoMjPTWy4qlWnRSIx1me4CDGbl0IzqF6C1I9Tqivggm0JNGpBNXHUu8HnIaT6W+yWZs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827484; c=relaxed/simple; bh=4LofnhBbDvtFowCiRDglvw22DbDrZ65v42pKGJKRikM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ks3NNuvM3Q6QClouqgfTb/XCFOAao3aCRrfZET7UhDdH0PRHVTq30/aI+Z8HP+BbygYUbzq0AQsE/be6cxN+wMZaBSH98eJVnqNTj6QIBm7Sk7KW/OeN3uUMt7rQrJy/5QmEpTm8KQaqOx0DT9Ia1vKR2Hn6CLLSlubi8drMK00= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=iM1ZVht4; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="iM1ZVht4" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 262B7C4166A; Tue, 19 Mar 2024 05:51:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827483; bh=4LofnhBbDvtFowCiRDglvw22DbDrZ65v42pKGJKRikM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iM1ZVht4BxqYAzOY6yQuh8lRg3YrjtT8IXT+Yde4vEJ9yvzL6uBFt3KXbc5WDslX7 /4sFxgM/cpjsKiaYhdJEeSsqN512nG+rfMSmogvr7aMMyjKsWawtWm5GgZuIWu3Ba4 ytsn38kFOVKBBmrAJ13U4PT7TJjBLlFSK8xrGb23M2onpcB1tn3xJ9qTZEn7mx7B6G of4kbJ9d96ChGEWa2QyYc+T1yZOm1MHMyWVA7Zy/aASkQDAgtbI6Han5Izj2gO/F/r o4B5fzy53oU3MCEddJuKCByCC1eyzoDvXcO/4RonkZ1uh8gTiSqmi7GoXkiDgGGJPG 8x4Mm0UuLj5BA== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 10/23] perf annotate-data: Add update_insn_state() Date: Mon, 18 Mar 2024 22:51:02 -0700 Message-ID: <20240319055115.4063940-11-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The update_insn_state() function is to update the type state table after processing each instruction. For now, it handles MOV (on x86) insn to transfer type info from the source location to the target. The location can be a register or a stack slot. Check carefully when memory reference happens and fetch the type correctly. It basically ignores write to a memory since it doesn't change the type info. One exception is writes to (new) stack slots for register spilling. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 161 +++++++++++++++++++++++++++++++- tools/perf/util/annotate-data.h | 2 + tools/perf/util/annotate.c | 1 + 3 files changed, 161 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 8eaa06f1cee5..592437b6c097 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -71,7 +71,9 @@ struct type_state_stack { * shortest path of basic blocks, it only maintains a single table. */ struct type_state { + /* state of general purpose registers */ struct type_state_reg regs[TYPE_STATE_MAX_REGS]; + /* state of stack location */ struct list_head stack_vars; }; @@ -85,6 +87,8 @@ void init_type_state(struct type_state *state, struct arch *arch __maybe_unused) void exit_type_state(struct type_state *state); void update_var_state(struct type_state *state, struct data_loc_info *dloc, u64 addr, u64 insn_offset, struct die_var_type *var_types); +void update_insn_state(struct type_state *state, struct data_loc_info *dloc, + struct disasm_line *dl); void init_type_state(struct type_state *state, struct arch *arch __maybe_unused) { @@ -412,13 +416,13 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, if (var->reg == DWARF_REG_FB) { findnew_stack_state(state, var->offset, &mem_die); - pr_debug_dtp("var [%"PRIx64"] -%#x(stack) type=", + pr_debug_dtp("var [%"PRIx64"] -%#x(stack)", insn_offset, -var->offset); pr_debug_type_name(&mem_die); } else if (var->reg == fbreg) { findnew_stack_state(state, var->offset - fb_offset, &mem_die); - pr_debug_dtp("var [%"PRIx64"] -%#x(stack) type=", + pr_debug_dtp("var [%"PRIx64"] -%#x(stack)", insn_offset, -var->offset + fb_offset); pr_debug_type_name(&mem_die); } else if (has_reg_type(state, var->reg) && var->offset == 0) { @@ -428,13 +432,164 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, reg->type = mem_die; reg->ok = true; - pr_debug_dtp("var [%"PRIx64"] reg%d type=", + pr_debug_dtp("var [%"PRIx64"] reg%d", insn_offset, var->reg); pr_debug_type_name(&mem_die); } } } +static void update_insn_state_x86(struct type_state *state, + struct data_loc_info *dloc, + struct disasm_line *dl) +{ + struct annotated_insn_loc loc; + struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE]; + struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET]; + struct type_state_reg *tsr; + Dwarf_Die type_die; + u32 insn_offset = dl->al.offset; + int fbreg = dloc->fbreg; + int fboff = 0; + + if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0) + return; + + if (strncmp(dl->ins.name, "mov", 3)) + return; + + if (dloc->fb_cfa) { + u64 ip = dloc->ms->sym->start + dl->al.offset; + u64 pc = map__rip_2objdump(dloc->ms->map, ip); + + if (die_get_cfa(dloc->di->dbg, pc, &fbreg, &fboff) < 0) + fbreg = -1; + } + + /* Case 1. register to register transfers */ + if (!src->mem_ref && !dst->mem_ref) { + if (!has_reg_type(state, dst->reg1)) + return; + + tsr = &state->regs[dst->reg1]; + if (!has_reg_type(state, src->reg1) || + !state->regs[src->reg1].ok) { + tsr->ok = false; + return; + } + + tsr->type = state->regs[src->reg1].type; + tsr->ok = true; + + pr_debug_dtp("mov [%x] reg%d -> reg%d", + insn_offset, src->reg1, dst->reg1); + pr_debug_type_name(&tsr->type); + } + /* Case 2. memory to register transers */ + if (src->mem_ref && !dst->mem_ref) { + int sreg = src->reg1; + + if (!has_reg_type(state, dst->reg1)) + return; + + tsr = &state->regs[dst->reg1]; + +retry: + /* Check stack variables with offset */ + if (sreg == fbreg) { + struct type_state_stack *stack; + int offset = src->offset - fboff; + + stack = find_stack_state(state, offset); + if (stack == NULL) { + tsr->ok = false; + return; + } else if (!stack->compound) { + tsr->type = stack->type; + tsr->ok = true; + } else if (die_get_member_type(&stack->type, + offset - stack->offset, + &type_die)) { + tsr->type = type_die; + tsr->ok = true; + } else { + tsr->ok = false; + return; + } + + pr_debug_dtp("mov [%x] -%#x(stack) -> reg%d", + insn_offset, -offset, dst->reg1); + pr_debug_type_name(&tsr->type); + } + /* And then dereference the pointer if it has one */ + else if (has_reg_type(state, sreg) && state->regs[sreg].ok && + die_deref_ptr_type(&state->regs[sreg].type, + src->offset, &type_die)) { + tsr->type = type_die; + tsr->ok = true; + + pr_debug_dtp("mov [%x] %#x(reg%d) -> reg%d", + insn_offset, src->offset, sreg, dst->reg1); + pr_debug_type_name(&tsr->type); + } + /* Or try another register if any */ + else if (src->multi_regs && sreg == src->reg1 && + src->reg1 != src->reg2) { + sreg = src->reg2; + goto retry; + } + /* It failed to get a type info, mark it as invalid */ + else { + tsr->ok = false; + } + } + /* Case 3. register to memory transfers */ + if (!src->mem_ref && dst->mem_ref) { + if (!has_reg_type(state, src->reg1) || + !state->regs[src->reg1].ok) + return; + + /* Check stack variables with offset */ + if (dst->reg1 == fbreg) { + struct type_state_stack *stack; + int offset = dst->offset - fboff; + + stack = find_stack_state(state, offset); + if (stack) { + /* + * The source register is likely to hold a type + * of member if it's a compound type. Do not + * update the stack variable type since we can + * get the member type later by using the + * die_get_member_type(). + */ + if (!stack->compound) + set_stack_state(stack, offset, + &state->regs[src->reg1].type); + } else { + findnew_stack_state(state, offset, + &state->regs[src->reg1].type); + } + + pr_debug_dtp("mov [%x] reg%d -> -%#x(stack)", + insn_offset, src->reg1, -offset); + pr_debug_type_name(&state->regs[src->reg1].type); + } + /* + * Ignore other transfers since it'd set a value in a struct + * and won't change the type. + */ + } + /* Case 4. memory to memory transfers (not handled for now) */ +} + +void update_insn_state(struct type_state *state, struct data_loc_info *dloc, + struct disasm_line *dl) +{ + if (arch__is(dloc->arch, "x86")) + update_insn_state_x86(state, dloc, dl); +} + /* The result will be saved in @type_die */ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) { diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index ad6493ea2c8e..7324cafe2c7b 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -75,6 +75,7 @@ extern struct annotated_data_type stackop_type; /** * struct data_loc_info - Data location information + * @arch: CPU architecture info * @ms: Map and Symbol info * @ip: Instruction address * @var_addr: Data address (for global variables) @@ -87,6 +88,7 @@ extern struct annotated_data_type stackop_type; */ struct data_loc_info { /* These are input field, should be filled by caller */ + struct arch *arch; struct map_symbol *ms; u64 ip; u64 var_addr; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index aa005c13ff67..9777df5dc2e3 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3872,6 +3872,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) for_each_insn_op_loc(&loc, i, op_loc) { struct data_loc_info dloc = { + .arch = arch, .ms = ms, /* Recalculate IP for LOCK prefix or insn fusion */ .ip = ms->sym->start + dl->al.offset, From patchwork Tue Mar 19 05:51:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596140 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 540717E763; Tue, 19 Mar 2024 05:51:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827484; cv=none; b=Sr9vPcXJINBS53FHOk8vVgWfQZLNlK1cHXmKXTiRApgfGWMdXayPR2ZqK9B/ft8cCS8Ml+QB+QivGuK17lGGTe6ufskEM3u4gqazeDYSlUEZf9I6bpZ4L5el0rZSkGTXq2snU/embiflMuq047+W58y/l746NEBqBqQOjXnK/0g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827484; c=relaxed/simple; bh=Mu8hDHjCGFj2JC2y9XQ5SBu3a6veNJkuzAWS61C+LNk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=k/DFTRRhnT9dvOeTk0CXLmvFffhhxcfNiMXzYli2//M2TggbJqHTAndsYUHaOLF8ZwtG1zhaxiMJpP8tsM28y0LxHDeWkwUSjnVfNRrRe2VAJ4cc9HRSqy7JOH5qPX3v2yZg/DoOSWR10Nui6ykUvo0aiXEC2Bo/BTACVGQCPK0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ohu+3VVm; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ohu+3VVm" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BC975C433B1; Tue, 19 Mar 2024 05:51:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827484; bh=Mu8hDHjCGFj2JC2y9XQ5SBu3a6veNJkuzAWS61C+LNk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ohu+3VVmsGfHRmpbF8wbfqzG2OIrK0Lwq7S2VoC8NWsZL2m5UIu6+VilnG6I9csCz aWBgBGOXX9GVqi2IIzYznP70xET8Cmsgve0LiEbBT6z1hmiNKG3MX5kl997azklkQN W9JrCqHQBOXp205AkKV18BmDMrQih9Flm9j4B41IO5ZjCxOtlRBffBmHsuuTQt0ZJz SVgHLa1BJYTE8kykNPkI/VP/JGof4mDL6F/ZU8MXsmNrRVrodNRAPJrC1t724mQmd0 BT0MVrKEVK2gebg5aR3wXgw279TBDWiWx7a5ebCLpcSZ9CRPkGq/owBIOVUzAXkOrd 6jcuUAuZ3Ugmg== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 11/23] perf annotate-data: Add get_global_var_type() Date: Mon, 18 Mar 2024 22:51:03 -0700 Message-ID: <20240319055115.4063940-12-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Accessing global variable is common when it tracks execution later. Factor out the common code into a function for later use. It adds thread and cpumode to struct data_loc_info to find (global) symbols if needed. Also remove var_name as it's retrieved in the helper function. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 62 +++++++++++++++++++++++++-------- tools/perf/util/annotate-data.h | 7 ++-- tools/perf/util/annotate.c | 21 +++-------- 3 files changed, 57 insertions(+), 33 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 592437b6c097..3b661e693410 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -22,6 +22,7 @@ #include "strbuf.h" #include "symbol.h" #include "symbol_conf.h" +#include "thread.h" #define pr_debug_dtp(fmt, ...) \ do { \ @@ -382,6 +383,50 @@ static struct type_state_stack *findnew_stack_state(struct type_state *state, return stack; } +static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, + u64 ip, u64 var_addr, int *var_offset, + Dwarf_Die *type_die) +{ + u64 pc, mem_addr; + int offset; + bool is_pointer = false; + const char *var_name = NULL; + Dwarf_Die var_die; + struct addr_location al; + struct symbol *sym; + + /* Try to get the variable by address first */ + if (die_find_variable_by_addr(cu_die, var_addr, &var_die, &offset) && + check_variable(&var_die, type_die, offset, is_pointer) == 0) { + *var_offset = offset; + return true; + } + + /* Kernel symbols might be relocated */ + mem_addr = var_addr + map__reloc(dloc->ms->map); + + addr_location__init(&al); + sym = thread__find_symbol_fb(dloc->thread, dloc->cpumode, + mem_addr, &al); + if (sym) { + var_name = sym->name; + /* Calculate type offset from the start of variable */ + *var_offset = mem_addr - map__unmap_ip(al.map, sym->start); + } + addr_location__exit(&al); + if (var_name == NULL) + return false; + + pc = map__rip_2objdump(dloc->ms->map, ip); + + /* Try to get the name of global variable */ + if (die_find_variable_at(cu_die, var_name, pc, &var_die) && + check_variable(&var_die, type_die, *var_offset, is_pointer) == 0) + return true; + + return false; +} + /** * update_var_state - Update type state using given variables * @state: type state table @@ -637,24 +682,14 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) pr_debug_dtp("CU die offset: %#lx\n", (long)dwarf_dieoffset(&cu_die)); if (reg == DWARF_REG_PC) { - if (die_find_variable_by_addr(&cu_die, dloc->var_addr, &var_die, - &offset)) { - ret = check_variable(&var_die, type_die, offset, - /*is_pointer=*/false); + if (get_global_var_type(&cu_die, dloc, dloc->ip, dloc->var_addr, + &offset, type_die)) { dloc->type_offset = offset; pr_debug_dtp("found PC-rel by addr=%#"PRIx64" offset=%#x\n", dloc->var_addr, offset); goto out; } - - if (dloc->var_name && - die_find_variable_at(&cu_die, dloc->var_name, pc, &var_die)) { - ret = check_variable(&var_die, type_die, dloc->type_offset, - /*is_pointer=*/false); - /* dloc->type_offset was updated by the caller */ - goto out; - } } /* Get a list of nested scopes - i.e. (inlined) functions and blocks. */ @@ -769,8 +804,7 @@ struct annotated_data_type *find_data_type(struct data_loc_info *dloc) * The type offset is the same as instruction offset by default. * But when finding a global variable, the offset won't be valid. */ - if (dloc->var_name == NULL) - dloc->type_offset = dloc->op->offset; + dloc->type_offset = dloc->op->offset; dloc->fbreg = -1; diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index 7324cafe2c7b..acfbd1748d02 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -11,6 +11,7 @@ struct annotated_op_loc; struct debuginfo; struct evsel; struct map_symbol; +struct thread; /** * struct annotated_member - Type of member field @@ -76,10 +77,11 @@ extern struct annotated_data_type stackop_type; /** * struct data_loc_info - Data location information * @arch: CPU architecture info + * @thread: Thread info * @ms: Map and Symbol info * @ip: Instruction address * @var_addr: Data address (for global variables) - * @var_name: Variable name (for global variables) + * @cpumode: CPU execution mode * @op: Instruction operand location (regs and offset) * @di: Debug info * @fbreg: Frame base register @@ -89,10 +91,11 @@ extern struct annotated_data_type stackop_type; struct data_loc_info { /* These are input field, should be filled by caller */ struct arch *arch; + struct thread *thread; struct map_symbol *ms; u64 ip; u64 var_addr; - const char *var_name; + u8 cpumode; struct annotated_op_loc *op; /* These are used internally */ diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 9777df5dc2e3..abb641aa8ec0 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3873,9 +3873,11 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) for_each_insn_op_loc(&loc, i, op_loc) { struct data_loc_info dloc = { .arch = arch, + .thread = he->thread, .ms = ms, /* Recalculate IP for LOCK prefix or insn fusion */ .ip = ms->sym->start + dl->al.offset, + .cpumode = he->cpumode, .op = op_loc, }; @@ -3887,23 +3889,8 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) /* PC-relative addressing */ if (op_loc->reg1 == DWARF_REG_PC) { - struct addr_location al; - struct symbol *var; - u64 map_addr; - - dloc.var_addr = annotate_calc_pcrel(ms, ip, op_loc->offset, dl); - /* Kernel symbols might be relocated */ - map_addr = dloc.var_addr + map__reloc(ms->map); - - addr_location__init(&al); - var = thread__find_symbol_fb(he->thread, he->cpumode, - map_addr, &al); - if (var) { - dloc.var_name = var->name; - /* Calculate type offset from the start of variable */ - dloc.type_offset = map_addr - map__unmap_ip(al.map, var->start); - } - addr_location__exit(&al); + dloc.var_addr = annotate_calc_pcrel(ms, dloc.ip, + op_loc->offset, dl); } mem_type = find_data_type(&dloc); From patchwork Tue Mar 19 05:51:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596141 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E993D7CF0F; Tue, 19 Mar 2024 05:51:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827485; cv=none; b=lWvV/kueXZU+HoMQnGOBJxoFGcH0+p3GPgwivLD/3phf3zXob+LN8n36MCiN4Ep6tMnvnosdhrV8EF6xaO2+X4m8DJc5qWRzeWHaahjEuZdcAJIVTTtCd34Sx2T7mH0BycXZ0vX0/O8DeplqHCEWm+VseTanRXNDY4f7BpMHWcg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827485; c=relaxed/simple; bh=mf4B7dqQYwBHEG3EOUsWTWvUmMNcxn199ikuZuyHXX8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=o4qK6TIcNLcxiwPga/MlDeGAeVghAo5XvvwK3K0q2Fl067ktReu84DRnXNpwjAnkASwtXtri1xXc7Hyd2I1uaVbOlDQv40nJAONnIwUNiNGU/0xtyOHDDuBDOiqoYWiTaSBK1lSqg1IK/H9F9eFGVPujv1IyFJv4WhQSbolu2Dk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PtntBRFh; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PtntBRFh" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5D482C433F1; Tue, 19 Mar 2024 05:51:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827484; bh=mf4B7dqQYwBHEG3EOUsWTWvUmMNcxn199ikuZuyHXX8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PtntBRFhqkLS5FmNGg+r5hCM/LibLByTtcRTYcUZS4WhOEBtA6e1h9EC+UTF8bsk3 2BAs9ycu3t/noS9sFCgmj3Dk7/OnFa4YvDS44zv1optsRmoBG48nDordgE1bBBtM7+ CON6Tazc+SSp1/iXmc0zphTvnKSZ3QxuY5LEd5eDioMb1wFaYamqBCqnp2j4E1Sk5A 6FIDni12uTX/TtFwBpIMjB/H//f6XYvtewyTpR1UvEBkcMc3cljr/VhxOeMRgIF2Yb tLp7KFfnhCqD2klAv2K0xR3/gHQZNgt0MIwti/fPEfFBzcfRaulxon78tlwQAmyKip mTB8uVqXvXV9A== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 12/23] perf annotate-data: Handle global variable access Date: Mon, 18 Mar 2024 22:51:04 -0700 Message-ID: <20240319055115.4063940-13-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 When updating the instruction states, it also needs to handle global variable accesses. Same as it does for PC-relative addressing, it can look up the type by address (if it's defined in the same file), or by name after finding the symbol by address (for declarations). Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 46 ++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 3b661e693410..2cc9f56e3eea 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -89,7 +89,7 @@ void exit_type_state(struct type_state *state); void update_var_state(struct type_state *state, struct data_loc_info *dloc, u64 addr, u64 insn_offset, struct die_var_type *var_types); void update_insn_state(struct type_state *state, struct data_loc_info *dloc, - struct disasm_line *dl); + Dwarf_Die *cu_die, struct disasm_line *dl); void init_type_state(struct type_state *state, struct arch *arch __maybe_unused) { @@ -485,7 +485,7 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, } static void update_insn_state_x86(struct type_state *state, - struct data_loc_info *dloc, + struct data_loc_info *dloc, Dwarf_Die *cu_die, struct disasm_line *dl) { struct annotated_insn_loc loc; @@ -577,6 +577,29 @@ static void update_insn_state_x86(struct type_state *state, insn_offset, src->offset, sreg, dst->reg1); pr_debug_type_name(&tsr->type); } + /* Or check if it's a global variable */ + else if (sreg == DWARF_REG_PC) { + struct map_symbol *ms = dloc->ms; + u64 ip = ms->sym->start + dl->al.offset; + u64 addr; + int offset; + + addr = annotate_calc_pcrel(ms, ip, src->offset, dl); + + if (!get_global_var_type(cu_die, dloc, ip, addr, &offset, + &type_die) || + !die_get_member_type(&type_die, offset, &type_die)) { + tsr->ok = false; + return; + } + + tsr->type = type_die; + tsr->ok = true; + + pr_debug_dtp("mov [%x] global addr=%"PRIx64" -> reg%d", + insn_offset, addr, dst->reg1); + pr_debug_type_name(&type_die); + } /* Or try another register if any */ else if (src->multi_regs && sreg == src->reg1 && src->reg1 != src->reg2) { @@ -628,11 +651,26 @@ static void update_insn_state_x86(struct type_state *state, /* Case 4. memory to memory transfers (not handled for now) */ } +/** + * update_insn_state - Update type state for an instruction + * @state: type state table + * @dloc: data location info + * @cu_die: compile unit debug entry + * @dl: disasm line for the instruction + * + * This function updates the @state table for the target operand of the + * instruction at @dl if it transfers the type like MOV on x86. Since it + * tracks the type, it won't care about the values like in arithmetic + * instructions like ADD/SUB/MUL/DIV and INC/DEC. + * + * Note that ops->reg2 is only available when both mem_ref and multi_regs + * are true. + */ void update_insn_state(struct type_state *state, struct data_loc_info *dloc, - struct disasm_line *dl) + Dwarf_Die *cu_die, struct disasm_line *dl) { if (arch__is(dloc->arch, "x86")) - update_insn_state_x86(state, dloc, dl); + update_insn_state_x86(state, dloc, cu_die, dl); } /* The result will be saved in @type_die */ From patchwork Tue Mar 19 05:51:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596142 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8B85A7EF03; Tue, 19 Mar 2024 05:51:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827485; cv=none; b=OXM54cGJZ8RQ6WuFs2/11Uo+uQNvXY/Hh5BCvIBJmZ33Ga/dn6Yuy+k9b9PwptC4UEe2A6fjQI/9t2ZZ9mJ6H37ZPm3cio5fNP+FcOkQa6v8vb1VcOtbPfPMPnP4lKFx2fcSo2WtutxbSGGgxyFtfGt2nHS1EeCcyJsIUCLV7Aw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827485; c=relaxed/simple; bh=6+RHQY3XONtH+zacbKS8+bLnxBwh7xxtzvp9uABp6QI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rT4cC5poQySdRHZGDMcmwIiwwocFdy0Pn3GQx2HaSpDSTdtlSOUmrFUAZg8SL0u1/EFv2sCjBXMXBLqL+arfHEXp2Yfvhs0ytlflJ84B5m+ebFSAkmMdGtBbEPd3CHrc0cfikEesbFrhKG7lSb2U4L+UHxx9CMVwCh22UNSxrFw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=D3o6RMm3; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="D3o6RMm3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F27C5C433C7; Tue, 19 Mar 2024 05:51:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827485; bh=6+RHQY3XONtH+zacbKS8+bLnxBwh7xxtzvp9uABp6QI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=D3o6RMm363CFM8XMMnxgojZ/s4jm/zeDImpaoQeoqRQkorSZDAA7M+nKuoTENMofp oVPMQ+vnrYIYngohZ6/CkZxKkgVu0V8R9cLyjWcPiFXU1GIGUHNR4013KrR9oSjR4S LTTkIHKgoe89OasdapraWM1ITGbDSoSIT9mE0a9sH74Bo0SaSYCeupHO3xkyKkR91o 6OzTtFirh+SlOhZnXe4W1WEG3Y8Dsnr1+Bln9YMB3WPN/+nftdfcb/YDiFsUusnadk YFZiHSpAXGrmy0csSFvzZUiEbuzPAK7ftjAgdPXXyujLKo3Kka853TxGPOBLjw13du nVD4360InYHTQ== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 13/23] perf annotate-data: Handle call instructions Date: Mon, 18 Mar 2024 22:51:05 -0700 Message-ID: <20240319055115.4063940-14-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 When updating instruction states, the call instruction should play a role since it changes the register states. For simplicity, mark some registers as caller-saved registers (should be arch-dependent), and invalidate them all after a function call. If the function returns something, the designated register (ret_reg) will have the type info. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 54 +++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 2cc9f56e3eea..6bcf22e523cb 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -47,10 +47,14 @@ static void pr_debug_type_name(Dwarf_Die *die) free(str); } -/* Type information in a register, valid when ok is true */ +/* + * Type information in a register, valid when @ok is true. + * The @caller_saved registers are invalidated after a function call. + */ struct type_state_reg { Dwarf_Die type; bool ok; + bool caller_saved; }; /* Type information in a stack location, dynamically allocated */ @@ -76,6 +80,8 @@ struct type_state { struct type_state_reg regs[TYPE_STATE_MAX_REGS]; /* state of stack location */ struct list_head stack_vars; + /* return value register */ + int ret_reg; }; static bool has_reg_type(struct type_state *state, int reg) @@ -91,10 +97,23 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, void update_insn_state(struct type_state *state, struct data_loc_info *dloc, Dwarf_Die *cu_die, struct disasm_line *dl); -void init_type_state(struct type_state *state, struct arch *arch __maybe_unused) +void init_type_state(struct type_state *state, struct arch *arch) { memset(state, 0, sizeof(*state)); INIT_LIST_HEAD(&state->stack_vars); + + if (arch__is(arch, "x86")) { + state->regs[0].caller_saved = true; + state->regs[1].caller_saved = true; + state->regs[2].caller_saved = true; + state->regs[4].caller_saved = true; + state->regs[5].caller_saved = true; + state->regs[8].caller_saved = true; + state->regs[9].caller_saved = true; + state->regs[10].caller_saved = true; + state->regs[11].caller_saved = true; + state->ret_reg = 0; + } } void exit_type_state(struct type_state *state) @@ -500,6 +519,37 @@ static void update_insn_state_x86(struct type_state *state, if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0) return; + if (ins__is_call(&dl->ins)) { + struct symbol *func = dl->ops.target.sym; + + if (func == NULL) + return; + + /* __fentry__ will preserve all registers */ + if (!strcmp(func->name, "__fentry__")) + return; + + pr_debug_dtp("call [%x] %s\n", insn_offset, func->name); + + /* Otherwise invalidate caller-saved registers after call */ + for (unsigned i = 0; i < ARRAY_SIZE(state->regs); i++) { + if (state->regs[i].caller_saved) + state->regs[i].ok = false; + } + + /* Update register with the return type (if any) */ + if (die_find_func_rettype(cu_die, func->name, &type_die)) { + tsr = &state->regs[state->ret_reg]; + tsr->type = type_die; + tsr->ok = true; + + pr_debug_dtp("call [%x] return -> reg%d", + insn_offset, state->ret_reg); + pr_debug_type_name(&type_die); + } + return; + } + if (strncmp(dl->ins.name, "mov", 3)) return; From patchwork Tue Mar 19 05:51:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596143 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0BDEE7F7C1; Tue, 19 Mar 2024 05:51:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827487; cv=none; b=mxZtdfEtubj7xlpITcuyOEfXpy+r/nsqBaB43Ikr8pjnCGN3Vcsq2XTytVwsx1zaOKq7j46Z4IfEDd7o7d06OBi/E9rsYAtl4b5Ca8z4oaMsdyzT8ZqYJzN0kEx3gUSB0veM9zg24c5jsYUv7Nj+VuN8ofe+Ta7tT69h2LryOpM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827487; c=relaxed/simple; bh=61VgKV31vYUBRqV9qo2hI10KmXR//3S4gszy882fliQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ja81ylFSkFVeF/imS9gKkkV/YSNWz/xOGEHN8iYMz71ZCS0ZYhEyqVorwIXggrUGzS0yidn6d3ZE3MsLX2enID04DblGg82fA8DY0tGk7Irtr52XYkup+8vTk+fC/39gf0YOzDyAJTjIPwydaDrNaP2/cUUGCwnzi0JKuuQyn3o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=umhuJVF1; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="umhuJVF1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 93B82C43601; Tue, 19 Mar 2024 05:51:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827486; bh=61VgKV31vYUBRqV9qo2hI10KmXR//3S4gszy882fliQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=umhuJVF1TrukWwX4W8toYsh8simW7cVs5LfANlcSY4rJe8oE+iM71gf5/+ieAkRRU fI08EWBEqlqeGsnltQUpReQuGEhto9gGpo3Y00SKELgTtACcm1F9IWCm2MBwU2Q7gg Fcnc2YvmiBDp7pHCU5N1xIjC0fWjpp69VAksCUXOnjyYftcpAIMurb/AnTRHajHn1L xn2z1ygbE3XgbaPbH76HK1gVdqhg2ERRwQX2GINKyLqzglauVtElU8zNEhibzWNHMB WWA7vMXl+Xs8mWKUjFbRMXjHT/PLYpVw6PietBj7Fk47xPHRnHyGvysa6Ey6jekW9B HeyMZ7+HIhAbA== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 14/23] perf annotate-data: Implement instruction tracking Date: Mon, 18 Mar 2024 22:51:06 -0700 Message-ID: <20240319055115.4063940-15-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 If it failed to find a variable for the location directly, it might be due to a missing variable in the source code. For example, accessing pointer variables in a chain can result in the case like below: struct foo *foo = ...; int i = foo->bar->baz; The DWARF debug information is created for each variable so it'd have one for 'foo'. But there's no variable for 'foo->bar' and then it cannot know the type of 'bar' and 'baz'. The above source code can be compiled to the follow x86 instructions: mov 0x8(%rax), %rcx mov 0x4(%rcx), %rdx <=== PMU sample mov %rdx, -4(%rbp) Let's say 'foo' is located in the %rax and it has a pointer to struct foo. But perf sample is captured in the second instruction and there is no variable or type info for the %rcx. It'd be great if compiler could generate debug info for %rcx, but we should handle it on our side. So this patch implements the logic to iterate instructions and update the type table for each location. As it already collected a list of scopes including the target instruction, we can use it to construct the type table smartly. +---------------- scope[0] subprogram | | +-------------- scope[1] lexical_block | | | | +------------ scope[2] inlined_subroutine | | | | | | +---------- scope[3] inlined_subroutine | | | | | | | | +-------- scope[4] lexical_block | | | | | | | | | | *** target instruction ... Image the target instruction has 5 scopes, each scope will have its own variables and parameters. Then it can start with the innermost scope (4). So it'd search the shortest path from the start of scope[4] to the target address and build a list of basic blocks. Then it iterates the basic blocks with the variables in the scope and update the table. If it finds a type at the target instruction, then returns it. Otherwise, it moves to the upper scope[3]. Now it'd search the shortest path from the start of scope[3] to the start of scope[4]. Then connect it to the existing basic block list. Then it'd iterate the blocks with variables for both scopes. It can repeat this until it finds a type at the target instruction or reaches to the top scope[0]. As the basic blocks contain the shortest path, it won't worry about branches and can update the table simply. The final check will be done by find_matching_type() in the next patch. Signed-off-by: Namhyung Kim --- tools/perf/builtin-annotate.c | 1 + tools/perf/util/annotate-data.c | 223 ++++++++++++++++++++++++++++++-- tools/perf/util/annotate-data.h | 1 + 3 files changed, 211 insertions(+), 14 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 6c1cc797692d..f677671409b1 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -430,6 +430,7 @@ static void print_annotate_data_stat(struct annotated_data_stat *s) PRINT_STAT(no_typeinfo); PRINT_STAT(invalid_size); PRINT_STAT(bad_offset); + PRINT_STAT(insn_track); printf("\n"); #undef PRINT_STAT diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 6bcf22e523cb..13ba65693367 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -89,15 +89,7 @@ static bool has_reg_type(struct type_state *state, int reg) return (unsigned)reg < ARRAY_SIZE(state->regs); } -/* These declarations will be remove once they are changed to static */ -void init_type_state(struct type_state *state, struct arch *arch __maybe_unused); -void exit_type_state(struct type_state *state); -void update_var_state(struct type_state *state, struct data_loc_info *dloc, - u64 addr, u64 insn_offset, struct die_var_type *var_types); -void update_insn_state(struct type_state *state, struct data_loc_info *dloc, - Dwarf_Die *cu_die, struct disasm_line *dl); - -void init_type_state(struct type_state *state, struct arch *arch) +static void init_type_state(struct type_state *state, struct arch *arch) { memset(state, 0, sizeof(*state)); INIT_LIST_HEAD(&state->stack_vars); @@ -116,7 +108,7 @@ void init_type_state(struct type_state *state, struct arch *arch) } } -void exit_type_state(struct type_state *state) +static void exit_type_state(struct type_state *state) { struct type_state_stack *stack, *tmp; @@ -457,8 +449,8 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, * This function fills the @state table using @var_types info. Each variable * is used only at the given location and updates an entry in the table. */ -void update_var_state(struct type_state *state, struct data_loc_info *dloc, - u64 addr, u64 insn_offset, struct die_var_type *var_types) +static void update_var_state(struct type_state *state, struct data_loc_info *dloc, + u64 addr, u64 insn_offset, struct die_var_type *var_types) { Dwarf_Die mem_die; struct die_var_type *var; @@ -716,13 +708,207 @@ static void update_insn_state_x86(struct type_state *state, * Note that ops->reg2 is only available when both mem_ref and multi_regs * are true. */ -void update_insn_state(struct type_state *state, struct data_loc_info *dloc, - Dwarf_Die *cu_die, struct disasm_line *dl) +static void update_insn_state(struct type_state *state, struct data_loc_info *dloc, + Dwarf_Die *cu_die, struct disasm_line *dl) { if (arch__is(dloc->arch, "x86")) update_insn_state_x86(state, dloc, cu_die, dl); } +/* + * Prepend this_blocks (from the outer scope) to full_blocks, removing + * duplicate disasm line. + */ +static void prepend_basic_blocks(struct list_head *this_blocks, + struct list_head *full_blocks) +{ + struct annotated_basic_block *first_bb, *last_bb; + + last_bb = list_last_entry(this_blocks, typeof(*last_bb), list); + first_bb = list_first_entry(full_blocks, typeof(*first_bb), list); + + if (list_empty(full_blocks)) + goto out; + + /* Last insn in this_blocks should be same as first insn in full_blocks */ + if (last_bb->end != first_bb->begin) { + pr_debug("prepend basic blocks: mismatched disasm line %"PRIx64" -> %"PRIx64"\n", + last_bb->end->al.offset, first_bb->begin->al.offset); + goto out; + } + + /* Is the basic block have only one disasm_line? */ + if (last_bb->begin == last_bb->end) { + list_del(&last_bb->list); + free(last_bb); + goto out; + } + + /* Point to the insn before the last when adding this block to full_blocks */ + last_bb->end = list_prev_entry(last_bb->end, al.node); + +out: + list_splice(this_blocks, full_blocks); +} + +static void delete_basic_blocks(struct list_head *basic_blocks) +{ + struct annotated_basic_block *bb, *tmp; + + list_for_each_entry_safe(bb, tmp, basic_blocks, list) { + list_del(&bb->list); + free(bb); + } +} + +/* Make sure all variables have a valid start address */ +static void fixup_var_address(struct die_var_type *var_types, u64 addr) +{ + while (var_types) { + /* + * Some variables have no address range meaning it's always + * available in the whole scope. Let's adjust the start + * address to the start of the scope. + */ + if (var_types->addr == 0) + var_types->addr = addr; + + var_types = var_types->next; + } +} + +static void delete_var_types(struct die_var_type *var_types) +{ + while (var_types) { + struct die_var_type *next = var_types->next; + + free(var_types); + var_types = next; + } +} + +/* It's at the target address, check if it has a matching type */ +static bool find_matching_type(struct type_state *state __maybe_unused, + struct data_loc_info *dloc __maybe_unused, + int reg __maybe_unused, + Dwarf_Die *type_die __maybe_unused) +{ + /* TODO */ + return false; +} + +/* Iterate instructions in basic blocks and update type table */ +static bool find_data_type_insn(struct data_loc_info *dloc, int reg, + struct list_head *basic_blocks, + struct die_var_type *var_types, + Dwarf_Die *cu_die, Dwarf_Die *type_die) +{ + struct type_state state; + struct symbol *sym = dloc->ms->sym; + struct annotation *notes = symbol__annotation(sym); + struct annotated_basic_block *bb; + bool found = false; + + init_type_state(&state, dloc->arch); + + list_for_each_entry(bb, basic_blocks, list) { + struct disasm_line *dl = bb->begin; + + pr_debug_dtp("bb: [%"PRIx64" - %"PRIx64"]\n", + bb->begin->al.offset, bb->end->al.offset); + + list_for_each_entry_from(dl, ¬es->src->source, al.node) { + u64 this_ip = sym->start + dl->al.offset; + u64 addr = map__rip_2objdump(dloc->ms->map, this_ip); + + /* Update variable type at this address */ + update_var_state(&state, dloc, addr, dl->al.offset, var_types); + + if (this_ip == dloc->ip) { + found = find_matching_type(&state, dloc, reg, + type_die); + goto out; + } + + /* Update type table after processing the instruction */ + update_insn_state(&state, dloc, cu_die, dl); + if (dl == bb->end) + break; + } + } + +out: + exit_type_state(&state); + return found; +} + +/* + * Construct a list of basic blocks for each scope with variables and try to find + * the data type by updating a type state table through instructions. + */ +static int find_data_type_block(struct data_loc_info *dloc, int reg, + Dwarf_Die *cu_die, Dwarf_Die *scopes, + int nr_scopes, Dwarf_Die *type_die) +{ + LIST_HEAD(basic_blocks); + struct die_var_type *var_types = NULL; + u64 src_ip, dst_ip, prev_dst_ip; + int ret = -1; + + /* TODO: other architecture support */ + if (!arch__is(dloc->arch, "x86")) + return -1; + + prev_dst_ip = dst_ip = dloc->ip; + for (int i = nr_scopes - 1; i >= 0; i--) { + Dwarf_Addr base, start, end; + LIST_HEAD(this_blocks); + + if (dwarf_ranges(&scopes[i], 0, &base, &start, &end) < 0) + break; + + pr_debug_dtp("scope: [%d/%d] (die:%lx)\n", + i + 1, nr_scopes, (long)dwarf_dieoffset(&scopes[i])); + src_ip = map__objdump_2rip(dloc->ms->map, start); + +again: + /* Get basic blocks for this scope */ + if (annotate_get_basic_blocks(dloc->ms->sym, src_ip, dst_ip, + &this_blocks) < 0) { + /* Try previous block if they are not connected */ + if (prev_dst_ip != dst_ip) { + dst_ip = prev_dst_ip; + goto again; + } + + pr_debug_dtp("cannot find a basic block from %"PRIx64" to %"PRIx64"\n", + src_ip - dloc->ms->sym->start, + dst_ip - dloc->ms->sym->start); + continue; + } + prepend_basic_blocks(&this_blocks, &basic_blocks); + + /* Get variable info for this scope and add to var_types list */ + die_collect_vars(&scopes[i], &var_types); + fixup_var_address(var_types, start); + + /* Find from start of this scope to the target instruction */ + if (find_data_type_insn(dloc, reg, &basic_blocks, var_types, + cu_die, type_die)) { + ret = 0; + break; + } + + /* Go up to the next scope and find blocks to the start */ + prev_dst_ip = dst_ip; + dst_ip = src_ip; + } + + delete_basic_blocks(&basic_blocks); + delete_var_types(var_types); + return ret; +} + /* The result will be saved in @type_die */ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) { @@ -847,6 +1033,15 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) goto out; } + if (reg != DWARF_REG_PC) { + ret = find_data_type_block(dloc, reg, &cu_die, scopes, + nr_scopes, type_die); + if (ret == 0) { + ann_data_stat.insn_track++; + goto out; + } + } + if (loc->multi_regs && reg == loc->reg1 && loc->reg1 != loc->reg2) { reg = loc->reg2; goto retry; diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index acfbd1748d02..ae0f87aed804 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -135,6 +135,7 @@ struct annotated_data_stat { int no_typeinfo; int invalid_size; int bad_offset; + int insn_track; }; extern struct annotated_data_stat ann_data_stat; From patchwork Tue Mar 19 05:51:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596144 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0BE167F7C2; Tue, 19 Mar 2024 05:51:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827487; cv=none; b=EEB8U/4e3ok3HX5w3pqjJP23ulx5CVus1tMgyYZzmYASBaaqvckTfN+ujsZBO0nSzixChnOc1HSehhPsAXeycdmrWBTtRDTtnd4bZLr411wj0qGnSzSxgo51oVqK+5le0nmH47+2AB43Edxl6wQ3Rd6a7ddBnYhcqpWQENYYGUA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827487; c=relaxed/simple; bh=QLyOSfT8f1zHgXyW3/7xJapPDD+hyj+Y2KOoSnTTUs4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=U+DUcln8KBj8sgBwIj94HZCuNAow+ilicr5c4TuNPJy+AcaLN90W5EujsVOoQvXRP/9o3Ho9aW9tF8atHhmSacyusCTYfIKwowPfHasx6lV9WZBDt4Kp4lfnMmdK98G2IfhYSZVw7bnOaK54kKE2Mnebj6tSopmiDc0en+sb6kc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=CmHLe6hS; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="CmHLe6hS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 36E9BC433B1; Tue, 19 Mar 2024 05:51:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827486; bh=QLyOSfT8f1zHgXyW3/7xJapPDD+hyj+Y2KOoSnTTUs4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CmHLe6hSMentoh66Ns63Ow8SJ319+tSJ5SCofEnzoYJpYnbqad4sc5tlYLMlM2FhR yawE2ROfAXRvHUkzQjozN9FWLx2clQOi42acR01FJi1VPvMEqjlCHTrnh0hzDM5MyC TkkN0gfLoPsIDq2lSdMXEK1VfeDIOViDGew47V8b21vXdsRQV+CBRRsihHYzufum2X FcxIfTFnA6rd1vIgKrLUvewylHe+ejPbTdIJHTClx3Merjt5uSH18gN8eShL0wgTdx twudnPQLHM+S4dI6ZwGNWkNZpyjelOcQegeO7n5xK0CmTdGxLyx9R5unyRBQqA31Aw scQnTbr0DDYDg== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 15/23] perf annotate-data: Check register state for type Date: Mon, 18 Mar 2024 22:51:07 -0700 Message-ID: <20240319055115.4063940-16-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 As instruction tracking updates the type state for each register, check the final type info for the target register at the given instruction. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 88 ++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 13ba65693367..f5329a78a97d 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -788,12 +788,83 @@ static void delete_var_types(struct die_var_type *var_types) } /* It's at the target address, check if it has a matching type */ -static bool find_matching_type(struct type_state *state __maybe_unused, - struct data_loc_info *dloc __maybe_unused, - int reg __maybe_unused, - Dwarf_Die *type_die __maybe_unused) +static bool check_matching_type(struct type_state *state, + struct data_loc_info *dloc, int reg, + Dwarf_Die *type_die) { - /* TODO */ + Dwarf_Word size; + u32 insn_offset = dloc->ip - dloc->ms->sym->start; + + pr_debug_dtp("chk [%x] reg%d offset=%#x ok=%d", + insn_offset, reg, dloc->op->offset, state->regs[reg].ok); + + if (state->regs[reg].ok) { + int tag = dwarf_tag(&state->regs[reg].type); + + pr_debug_dtp("\n"); + + /* + * Normal registers should hold a pointer (or array) to + * dereference a memory location. + */ + if (tag != DW_TAG_pointer_type && tag != DW_TAG_array_type) + return false; + + /* Remove the pointer and get the target type */ + if (die_get_real_type(&state->regs[reg].type, type_die) == NULL) + return false; + + dloc->type_offset = dloc->op->offset; + + /* Get the size of the actual type */ + if (dwarf_aggregate_size(type_die, &size) < 0 || + (unsigned)dloc->type_offset >= size) + return false; + + return true; + } + + if (reg == dloc->fbreg) { + struct type_state_stack *stack; + + pr_debug_dtp(" fbreg\n"); + + stack = find_stack_state(state, dloc->type_offset); + if (stack == NULL) + return false; + + *type_die = stack->type; + /* Update the type offset from the start of slot */ + dloc->type_offset -= stack->offset; + + return true; + } + + if (dloc->fb_cfa) { + struct type_state_stack *stack; + u64 pc = map__rip_2objdump(dloc->ms->map, dloc->ip); + int fbreg, fboff; + + pr_debug_dtp(" cfa\n"); + + if (die_get_cfa(dloc->di->dbg, pc, &fbreg, &fboff) < 0) + fbreg = -1; + + if (reg != fbreg) + return false; + + stack = find_stack_state(state, dloc->type_offset - fboff); + if (stack == NULL) + return false; + + *type_die = stack->type; + /* Update the type offset from the start of slot */ + dloc->type_offset -= fboff + stack->offset; + + return true; + } + + pr_debug_dtp("\n"); return false; } @@ -825,8 +896,8 @@ static bool find_data_type_insn(struct data_loc_info *dloc, int reg, update_var_state(&state, dloc, addr, dl->al.offset, var_types); if (this_ip == dloc->ip) { - found = find_matching_type(&state, dloc, reg, - type_die); + found = check_matching_type(&state, dloc, reg, + type_die); goto out; } @@ -896,6 +967,9 @@ static int find_data_type_block(struct data_loc_info *dloc, int reg, if (find_data_type_insn(dloc, reg, &basic_blocks, var_types, cu_die, type_die)) { ret = 0; + pr_debug_dtp("found by insn track: %#x(reg%d) type-offset=%#x", + dloc->op->offset, reg, dloc->type_offset); + pr_debug_type_name(type_die); break; } From patchwork Tue Mar 19 05:51:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596145 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9B3407F7ED; Tue, 19 Mar 2024 05:51:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827487; cv=none; b=tAX8vuN6/M5NGkOnyzOi3kOgQ8z9NMeB3hGYvBhUG5j3R7eaj9TD0zxKsFGplAPlgkZYOCMqebG9wU/Wjx9Iji4GK78cKcN25M7uTkpBz4Wj4OrY96DhfnrIXuG+ztwktRzFQ3oRcnrvd5DcVyQZMT7KULgMhrHGxjYmPrFHL6I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827487; c=relaxed/simple; bh=jI51wNRC8ThpORG4FB43LJXCrP24HAJo4LwhgE6X6a0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iBlkjpBh5ERW7fSwQCwEAE0+OyNVNh6D1m3s6zZ9WN8dpA5nUupe2V9U1FluR0k2TBtSMnAB6oG2f3thwmKbxJHGSOKrwU1omGS/6g0tmKKCrFSJ7Zedkv0KGD4/Z6w/bVuhX1OSC4pcRU14IOeTV4E7zS0LPHqr/etw2Q5z13Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=E2bnM4BR; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="E2bnM4BR" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D07E1C43141; Tue, 19 Mar 2024 05:51:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827487; bh=jI51wNRC8ThpORG4FB43LJXCrP24HAJo4LwhgE6X6a0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=E2bnM4BRrtGgEDVsxYbo5orCye0x5wVSUgu8HgO3sFRe7tvsS25eX7eP5JFlv0+/o kBV82VbDcS+DGoQLniXj6Md1Wc8bZhs0/0NX5EYoasHJo1wrBWDRfipBXBGZ47kz2Z l10HbUAcAJu6gKpPF71zomRnSvAvT/LEUdyNIK2d0UtBi2b5BnJMJ4jwdUdrUTJ0/X yA4EGp3xfABR6E4Pu1WdqS3JRhQIbG/DvfWYhr3fhBr2+hzfEkNxnAlLFbm6TUmfJs cgFHFbItXHZQpVhb7fBIc5wxV5aihLktl6k7J29TW/eXGJtHWuExw+goZWRtk+JFaT 8UGsj7+IBpc7Q== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 16/23] perf annotate: Parse x86 segment register location Date: Mon, 18 Mar 2024 22:51:08 -0700 Message-ID: <20240319055115.4063940-17-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add a segment field in the struct annotated_insn_loc and save it for the segment based addressing like %gs:0x28. For simplicity it now handles %gs register only. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate.c | 36 ++++++++++++++++++++++++++++++++---- tools/perf/util/annotate.h | 15 +++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index abb641aa8ec0..3aa3a3b987ad 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -94,6 +94,7 @@ struct arch { char skip_functions_char; char register_char; char memory_ref_char; + char imm_char; } objdump; }; @@ -211,6 +212,7 @@ static struct arch architectures[] = { .comment_char = '#', .register_char = '%', .memory_ref_char = '(', + .imm_char = '$', }, }, { @@ -3585,6 +3587,12 @@ static int extract_reg_offset(struct arch *arch, const char *str, * %gs:0x18(%rbx). In that case it should skip the part. */ if (*str == arch->objdump.register_char) { + if (arch__is(arch, "x86")) { + /* FIXME: Handle other segment registers */ + if (!strncmp(str, "%gs:", 4)) + op_loc->segment = INSN_SEG_X86_GS; + } + while (*str && !isdigit(*str) && *str != arch->objdump.memory_ref_char) str++; @@ -3681,12 +3689,32 @@ int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl, op_loc->multi_regs = multi_regs; extract_reg_offset(arch, insn_str, op_loc); } else { - char *s = strdup(insn_str); + char *s, *p = NULL; + + if (arch__is(arch, "x86")) { + /* FIXME: Handle other segment registers */ + if (!strncmp(insn_str, "%gs:", 4)) { + op_loc->segment = INSN_SEG_X86_GS; + op_loc->offset = strtol(insn_str + 4, + &p, 0); + if (p && p != insn_str + 4) + op_loc->imm = true; + continue; + } + } + + s = strdup(insn_str); + if (s == NULL) + return -1; - if (s) { + if (*s == arch->objdump.register_char) op_loc->reg1 = get_dwarf_regnum(s, 0); - free(s); + else if (*s == arch->objdump.imm_char) { + op_loc->offset = strtol(s + 1, &p, 0); + if (p && p != s + 1) + op_loc->imm = true; } + free(s); } } @@ -3881,7 +3909,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) .op = op_loc, }; - if (!op_loc->mem_ref) + if (!op_loc->mem_ref && op_loc->segment == INSN_SEG_NONE) continue; /* Recalculate IP because of LOCK prefix or insn fusion */ diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 0928663fddee..14980b65f812 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -511,15 +511,19 @@ int annotate_check_args(void); * @reg1: First register in the operand * @reg2: Second register in the operand * @offset: Memory access offset in the operand + * @segment: Segment selector register * @mem_ref: Whether the operand accesses memory * @multi_regs: Whether the second register is used + * @imm: Whether the operand is an immediate value (in offset) */ struct annotated_op_loc { int reg1; int reg2; int offset; + u8 segment; bool mem_ref; bool multi_regs; + bool imm; }; enum annotated_insn_ops { @@ -529,6 +533,17 @@ enum annotated_insn_ops { INSN_OP_MAX, }; +enum annotated_x86_segment { + INSN_SEG_NONE = 0, + + INSN_SEG_X86_CS, + INSN_SEG_X86_DS, + INSN_SEG_X86_ES, + INSN_SEG_X86_FS, + INSN_SEG_X86_GS, + INSN_SEG_X86_SS, +}; + /** * struct annotated_insn_loc - Location info of instruction * @ops: Array of location info for source and target operands From patchwork Tue Mar 19 05:51:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596146 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1620B7FBAF; Tue, 19 Mar 2024 05:51:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827488; cv=none; b=tGuQ7JLrjw+XUkwQg6kG/WFaPnbo3T/hy40h07Fzy7WMOxsVxmubh6OCjqHF6+0beQcfuKMD7CAMfo9GLdedtbUgkNgDig2AmQHQM7ELDm622E7U+ykKsMHuf+gnKBe6N3kfyoQUh0f7gUGbXbe9aBxs2NAR92iJNkiBEqyzy3o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827488; c=relaxed/simple; bh=uJSdghEGLKMsHLGxhc9BRL8wS6WYTQdxoEBPQ8UAYQ0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GoHNcoF+GmZjO9h3Iiii7PgUqe3fWH3gykKzeZVTCFHHgFsMgG3oA6u5gB8K9BXCPHRfmFrk/Txzk4gnTgACe/BYT5qI8Ke6CqgU0PaYC+lzzgUgonF3aSVhEP9IemxYTeekYC8WuDjuYSePOWVj0qOdwzxrHrITa3KRgLlupio= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=hInb/Drm; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="hInb/Drm" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 74F2AC43390; Tue, 19 Mar 2024 05:51:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827487; bh=uJSdghEGLKMsHLGxhc9BRL8wS6WYTQdxoEBPQ8UAYQ0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hInb/DrmioxpC/1b7/UzJjjH3S6SZXRm5+NvXmMkdpP7JdiNPwPzW/CgECrt99GvY WmuldXyzJMwtk40n/QQ2ONF2418mBqW7Zw0e7oLN0rkSB254XqIlWXDm0ABEP/OKU1 6NV/YUeVNRoYlNJSYqtTMkii+8SKg338p+T2k8KZgm55W56DJdGSIfI92ByX2KowqZ M2m4bASKV0mDFFcA8HjVusbUrJ3e+Il9HH66nCq+yr0DerAksUJyT/N/NBzQqyiD6Q Jfye6q9ShAs8WdQZVBPQswKw1RpDun2pud2Maco9073Hvo9oQSfnUCZuhVWlqeExX6 7zVJjx58hK0FA== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 17/23] perf annotate-data: Handle this-cpu variables in kernel Date: Mon, 18 Mar 2024 22:51:09 -0700 Message-ID: <20240319055115.4063940-18-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 On x86, the kernel gets the current task using the current macro like below: #define current get_current() static __always_inline struct task_struct *get_current(void) { return this_cpu_read_stable(pcpu_hot.current_task); } So it returns the current_task field of struct pcpu_hot which is the first member. On my build, it's located at 0x32940. $ nm vmlinux | grep pcpu_hot 0000000000032940 D pcpu_hot And the current macro generates the instructions like below: mov %gs:0x32940, %rcx So the %gs segment register points to the beginning of the per-cpu region of this cpu and it points the variable with a constant. Let's update the instruction location info to have a segment register and handle %gs in kernel to look up a global variable. Pretend it as a global variable by changing the register number to DWARF_REG_PC. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 21 +++++++++++++++++++-- tools/perf/util/annotate.c | 7 +++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index f5329a78a97d..d57622ddd5d3 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -790,7 +790,7 @@ static void delete_var_types(struct die_var_type *var_types) /* It's at the target address, check if it has a matching type */ static bool check_matching_type(struct type_state *state, struct data_loc_info *dloc, int reg, - Dwarf_Die *type_die) + Dwarf_Die *cu_die, Dwarf_Die *type_die) { Dwarf_Word size; u32 insn_offset = dloc->ip - dloc->ms->sym->start; @@ -864,6 +864,23 @@ static bool check_matching_type(struct type_state *state, return true; } + if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) { + u64 addr; + int offset; + + if (dloc->op->segment == INSN_SEG_X86_GS && dloc->op->imm) { + pr_debug_dtp(" this-cpu var\n"); + + addr = dloc->op->offset; + + if (get_global_var_type(cu_die, dloc, dloc->ip, addr, + &offset, type_die)) { + dloc->type_offset = offset; + return true; + } + } + } + pr_debug_dtp("\n"); return false; } @@ -897,7 +914,7 @@ static bool find_data_type_insn(struct data_loc_info *dloc, int reg, if (this_ip == dloc->ip) { found = check_matching_type(&state, dloc, reg, - type_die); + cu_die, type_die); goto out; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3aa3a3b987ad..e4121acb4f88 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3921,6 +3921,13 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) op_loc->offset, dl); } + /* This CPU access in kernel - pretend PC-relative addressing */ + if (map__dso(ms->map)->kernel && arch__is(arch, "x86") && + op_loc->segment == INSN_SEG_X86_GS && op_loc->imm) { + dloc.var_addr = op_loc->offset; + op_loc->reg1 = DWARF_REG_PC; + } + mem_type = find_data_type(&dloc); if (mem_type) istat->good++; From patchwork Tue Mar 19 05:51:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596147 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A5FB87FBDA; Tue, 19 Mar 2024 05:51:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827488; cv=none; b=S06hQFiZOLqlYPAoJ/dfqXxEKrnAo2yCGbChRc7sbjiuSST2suJ4tDu0o79noAo97lZcDGvbCdoJqoqZ4NZ45hUp1+igxAFxI+vhTWX4chK6aQk8v0lHWbfkhhjW2XhJhGXtmeN2qxDHHYCZBm0KW8q1Dtj5hohkByRhI/nhOvU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827488; c=relaxed/simple; bh=QJ4b60uS7SiZLvE/zbDFsQPiZ25HBF3r++1i4MMpgTA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tZT+vrU+pPWOKZcIkctBxT+qFH3K5MoZ+hQzk/6y6DeirJzERi7AE2orKfMA6vMBr6gCYQDbGQeV3hrFhFKtmULC2w5h8C7l0j4Lg23jkPA8BGZ+KwnenAS4pHRmrmn51UE6TcxTiOGk5DSETwTOBj8Q2lM1vx19RnxU0jThwDI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PYZ2Wykl; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PYZ2Wykl" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 16DEFC433B1; Tue, 19 Mar 2024 05:51:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827488; bh=QJ4b60uS7SiZLvE/zbDFsQPiZ25HBF3r++1i4MMpgTA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PYZ2Wyklr7jGA4Sm0WPc83O20209o9s4aDfl3HgrXKIkf2MviUUypU4oFm0vVvDNo ROSF97my3G2XcFfXGrpEzSo7e5ZLYsqBjN6bPXVoFoWq5BdpkUL1xqCxuioDJRYLCZ b4++XkS9k+wo+hxW2pjPuVCj95K2pbZ8k5DgBhcLHpW9FdQtVLl4/kdpWmPqfk25Gt PTjxRV1VFHtMrJ10kNExh8Pce7Ke/loo+J3rDMWcKAjNtBuTzGOk0Q8mmLUl5KKHxJ nneWuQo9IPtlV5/eJZ7gkFHKLUKl4AhXthVrptZ/iA/WT3p75T53N1kogNdBdSe3XK kZQfH7bFL2wtA== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 18/23] perf annotate-data: Track instructions with a this-cpu variable Date: Mon, 18 Mar 2024 22:51:10 -0700 Message-ID: <20240319055115.4063940-19-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Like global variables, this per-cpu variables should be tracked correctly. Factor our get_global_var_type() to handle both global and per-cpu (for this cpu) variables in the same manner. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index d57622ddd5d3..48fea0c716ef 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -553,12 +553,41 @@ static void update_insn_state_x86(struct type_state *state, fbreg = -1; } - /* Case 1. register to register transfers */ + /* Case 1. register to register or segment:offset to register transfers */ if (!src->mem_ref && !dst->mem_ref) { if (!has_reg_type(state, dst->reg1)) return; tsr = &state->regs[dst->reg1]; + if (map__dso(dloc->ms->map)->kernel && + src->segment == INSN_SEG_X86_GS && src->imm) { + u64 ip = dloc->ms->sym->start + dl->al.offset; + u64 var_addr; + int offset; + + /* + * In kernel, %gs points to a per-cpu region for the + * current CPU. Access with a constant offset should + * be treated as a global variable access. + */ + var_addr = src->offset; + + if (!get_global_var_type(cu_die, dloc, ip, var_addr, + &offset, &type_die) || + !die_get_member_type(&type_die, offset, &type_die)) { + tsr->ok = false; + return; + } + + tsr->type = type_die; + tsr->ok = true; + + pr_debug_dtp("mov [%x] this-cpu addr=%#"PRIx64" -> reg%d", + insn_offset, var_addr, dst->reg1); + pr_debug_type_name(&tsr->type); + return; + } + if (!has_reg_type(state, src->reg1) || !state->regs[src->reg1].ok) { tsr->ok = false; From patchwork Tue Mar 19 05:51:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596148 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4B51C80040; Tue, 19 Mar 2024 05:51:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827489; cv=none; b=GLH1CStxagl9kMn/27M3eVSD00iVzMQP+V8pJexzQwibn+w0OtRYSOVPP+S6ZyZlljEFlVNrUZPeGzGQOhbzW/+rzkvWfqk32QEWmuBsp50OZ5Uw+Y7t7rGEyu/L7c5dVVZ/KP0XVcYMJnP0Qt736cxEt+lZg/LmfVGwRA8bT2I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827489; c=relaxed/simple; bh=mXS6jZaY9ZevJvSn0rjXLeTwQiYVcVb4HE7VvVhes5s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=h3FoVnjI+8kkDZdyY/ufL/sSQ5vMHfKk/53GvweOGQv2PrxE0rNtXp41nXMIl4gnDa2neEvhgGQ/S6zN9xaw5uftPRwQhvgLqx38gfX6IDqCL8A8CyjwzId1RilwMiyhlqSWQVx8hXPOPYyzvSH2dVp8qnPmc5U8T08KeJ6o6vE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PEYDajNV; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PEYDajNV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B14E0C43143; Tue, 19 Mar 2024 05:51:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827489; bh=mXS6jZaY9ZevJvSn0rjXLeTwQiYVcVb4HE7VvVhes5s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PEYDajNVlF40m8sxwEojId+ch02VazFOjYamaxiFLrMuIHYwKNykx1Sih/vrmQ9zG LjOlfgmvxC/h/WOea7W5qsr4dOOW0/Vim/1cmNBjloqVPCGjpBuMWUi3cQ+X2+RF66 Tvvm578PKMzXa3OGfd/zual8/NsrIcxTLHLvKgehCTiqMaPJYtk74JvX2TCla+72XY fYWXDnSAn8CF30sh6oglfusO5bCY40ClSE0XnYBMtliXHLHnGJDgV45P8Vf18T9aon ABlWI5eZeAVXRyet9YT9Khg3Vkq9u+UVzqidlQ4g1ga0KH/UbIyzlVTpl6+iM+CKuV DT7N2Twjr7Jig== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 19/23] perf annotate-data: Support general per-cpu access Date: Mon, 18 Mar 2024 22:51:11 -0700 Message-ID: <20240319055115.4063940-20-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This is to support per-cpu variable access often without a matching DWARF entry. For some reason, I cannot find debug info of per-cpu variables sometimes. They have more complex pattern to calculate the address of per-cpu variables like below. 2b7d: mov -0x1e0(%rbp),%rax ; rax = cpu 2b84: mov -0x7da0f7e0(,%rax,8),%rcx ; rcx = __per_cpu_offset[cpu] * 2b8c: mov 0x34870(%rcx),%rax ; *(__per_cpu_offset[cpu] + 0x34870) Let's assume the rax register has a number for a CPU at 2b7d. The next instruction is to get the per-cpu offset' for that cpu. The offset -0x7da0f7e0 is 0xffffffff825f0820 in u64 which is the address of the '__per_cpu_offset' array in my system. So it'd get the actual offset of that CPU's per-cpu region and save it to the rcx register. Then, at 2b8c, accesses using rcx can be handled same as the global variable access. To handle this case, it should check if the offset of the instruction matches to the address of '__per_cpu_offset'. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 213 +++++++++++++++++++++++++------- 1 file changed, 169 insertions(+), 44 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 48fea0c716ef..83b5aa00f01c 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -24,6 +24,12 @@ #include "symbol_conf.h" #include "thread.h" +enum type_state_kind { + TSR_KIND_INVALID = 0, + TSR_KIND_TYPE, + TSR_KIND_PERCPU_BASE, +}; + #define pr_debug_dtp(fmt, ...) \ do { \ if (debug_type_profile) \ @@ -32,7 +38,7 @@ do { \ pr_debug3(fmt, ##__VA_ARGS__); \ } while (0) -static void pr_debug_type_name(Dwarf_Die *die) +static void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) { struct strbuf sb; char *str; @@ -40,6 +46,18 @@ static void pr_debug_type_name(Dwarf_Die *die) if (!debug_type_profile && verbose < 3) return; + switch (kind) { + case TSR_KIND_INVALID: + pr_info("\n"); + return; + case TSR_KIND_PERCPU_BASE: + pr_info(" percpu base\n"); + return; + case TSR_KIND_TYPE: + default: + break; + } + strbuf_init(&sb, 32); die_get_typename_from_type(die, &sb); str = strbuf_detach(&sb, NULL); @@ -53,8 +71,10 @@ static void pr_debug_type_name(Dwarf_Die *die) */ struct type_state_reg { Dwarf_Die type; + u32 imm_value; bool ok; bool caller_saved; + u8 kind; }; /* Type information in a stack location, dynamically allocated */ @@ -64,6 +84,7 @@ struct type_state_stack { int offset; int size; bool compound; + u8 kind; }; /* FIXME: This should be arch-dependent */ @@ -82,6 +103,8 @@ struct type_state { struct list_head stack_vars; /* return value register */ int ret_reg; + /* stack pointer register */ + int stack_reg; }; static bool has_reg_type(struct type_state *state, int reg) @@ -105,6 +128,7 @@ static void init_type_state(struct type_state *state, struct arch *arch) state->regs[10].caller_saved = true; state->regs[11].caller_saved = true; state->ret_reg = 0; + state->stack_reg = 7; } } @@ -350,7 +374,7 @@ static struct type_state_stack *find_stack_state(struct type_state *state, return NULL; } -static void set_stack_state(struct type_state_stack *stack, int offset, +static void set_stack_state(struct type_state_stack *stack, int offset, u8 kind, Dwarf_Die *type_die) { int tag; @@ -364,6 +388,7 @@ static void set_stack_state(struct type_state_stack *stack, int offset, stack->type = *type_die; stack->size = size; stack->offset = offset; + stack->kind = kind; switch (tag) { case DW_TAG_structure_type: @@ -377,34 +402,60 @@ static void set_stack_state(struct type_state_stack *stack, int offset, } static struct type_state_stack *findnew_stack_state(struct type_state *state, - int offset, Dwarf_Die *type_die) + int offset, u8 kind, + Dwarf_Die *type_die) { struct type_state_stack *stack = find_stack_state(state, offset); if (stack) { - set_stack_state(stack, offset, type_die); + set_stack_state(stack, offset, kind, type_die); return stack; } stack = malloc(sizeof(*stack)); if (stack) { - set_stack_state(stack, offset, type_die); + set_stack_state(stack, offset, kind, type_die); list_add(&stack->list, &state->stack_vars); } return stack; } +static bool get_global_var_info(struct data_loc_info *dloc, u64 addr, + const char **var_name, int *var_offset) +{ + struct addr_location al; + struct symbol *sym; + u64 mem_addr; + + /* Kernel symbols might be relocated */ + mem_addr = addr + map__reloc(dloc->ms->map); + + addr_location__init(&al); + sym = thread__find_symbol_fb(dloc->thread, dloc->cpumode, + mem_addr, &al); + if (sym) { + *var_name = sym->name; + /* Calculate type offset from the start of variable */ + *var_offset = mem_addr - map__unmap_ip(al.map, sym->start); + } else { + *var_name = NULL; + } + addr_location__exit(&al); + if (*var_name == NULL) + return false; + + return true; +} + static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, u64 ip, u64 var_addr, int *var_offset, Dwarf_Die *type_die) { - u64 pc, mem_addr; + u64 pc; int offset; bool is_pointer = false; - const char *var_name = NULL; + const char *var_name; Dwarf_Die var_die; - struct addr_location al; - struct symbol *sym; /* Try to get the variable by address first */ if (die_find_variable_by_addr(cu_die, var_addr, &var_die, &offset) && @@ -413,19 +464,7 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, return true; } - /* Kernel symbols might be relocated */ - mem_addr = var_addr + map__reloc(dloc->ms->map); - - addr_location__init(&al); - sym = thread__find_symbol_fb(dloc->thread, dloc->cpumode, - mem_addr, &al); - if (sym) { - var_name = sym->name; - /* Calculate type offset from the start of variable */ - *var_offset = mem_addr - map__unmap_ip(al.map, sym->start); - } - addr_location__exit(&al); - if (var_name == NULL) + if (!get_global_var_info(dloc, var_addr, &var_name, var_offset)) return false; pc = map__rip_2objdump(dloc->ms->map, ip); @@ -470,27 +509,30 @@ static void update_var_state(struct type_state *state, struct data_loc_info *dlo continue; if (var->reg == DWARF_REG_FB) { - findnew_stack_state(state, var->offset, &mem_die); + findnew_stack_state(state, var->offset, TSR_KIND_TYPE, + &mem_die); pr_debug_dtp("var [%"PRIx64"] -%#x(stack)", insn_offset, -var->offset); - pr_debug_type_name(&mem_die); + pr_debug_type_name(&mem_die, TSR_KIND_TYPE); } else if (var->reg == fbreg) { - findnew_stack_state(state, var->offset - fb_offset, &mem_die); + findnew_stack_state(state, var->offset - fb_offset, + TSR_KIND_TYPE, &mem_die); pr_debug_dtp("var [%"PRIx64"] -%#x(stack)", insn_offset, -var->offset + fb_offset); - pr_debug_type_name(&mem_die); + pr_debug_type_name(&mem_die, TSR_KIND_TYPE); } else if (has_reg_type(state, var->reg) && var->offset == 0) { struct type_state_reg *reg; reg = &state->regs[var->reg]; reg->type = mem_die; + reg->kind = TSR_KIND_TYPE; reg->ok = true; pr_debug_dtp("var [%"PRIx64"] reg%d", insn_offset, var->reg); - pr_debug_type_name(&mem_die); + pr_debug_type_name(&mem_die, TSR_KIND_TYPE); } } } @@ -533,11 +575,12 @@ static void update_insn_state_x86(struct type_state *state, if (die_find_func_rettype(cu_die, func->name, &type_die)) { tsr = &state->regs[state->ret_reg]; tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; tsr->ok = true; pr_debug_dtp("call [%x] return -> reg%d", insn_offset, state->ret_reg); - pr_debug_type_name(&type_die); + pr_debug_type_name(&type_die, tsr->kind); } return; } @@ -580,11 +623,12 @@ static void update_insn_state_x86(struct type_state *state, } tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; tsr->ok = true; pr_debug_dtp("mov [%x] this-cpu addr=%#"PRIx64" -> reg%d", insn_offset, var_addr, dst->reg1); - pr_debug_type_name(&tsr->type); + pr_debug_type_name(&tsr->type, tsr->kind); return; } @@ -595,11 +639,12 @@ static void update_insn_state_x86(struct type_state *state, } tsr->type = state->regs[src->reg1].type; + tsr->kind = state->regs[src->reg1].kind; tsr->ok = true; pr_debug_dtp("mov [%x] reg%d -> reg%d", insn_offset, src->reg1, dst->reg1); - pr_debug_type_name(&tsr->type); + pr_debug_type_name(&tsr->type, tsr->kind); } /* Case 2. memory to register transers */ if (src->mem_ref && !dst->mem_ref) { @@ -622,11 +667,13 @@ static void update_insn_state_x86(struct type_state *state, return; } else if (!stack->compound) { tsr->type = stack->type; + tsr->kind = stack->kind; tsr->ok = true; } else if (die_get_member_type(&stack->type, offset - stack->offset, &type_die)) { tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; tsr->ok = true; } else { tsr->ok = false; @@ -635,18 +682,20 @@ static void update_insn_state_x86(struct type_state *state, pr_debug_dtp("mov [%x] -%#x(stack) -> reg%d", insn_offset, -offset, dst->reg1); - pr_debug_type_name(&tsr->type); + pr_debug_type_name(&tsr->type, tsr->kind); } /* And then dereference the pointer if it has one */ else if (has_reg_type(state, sreg) && state->regs[sreg].ok && + state->regs[sreg].kind == TSR_KIND_TYPE && die_deref_ptr_type(&state->regs[sreg].type, src->offset, &type_die)) { tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; tsr->ok = true; pr_debug_dtp("mov [%x] %#x(reg%d) -> reg%d", insn_offset, src->offset, sreg, dst->reg1); - pr_debug_type_name(&tsr->type); + pr_debug_type_name(&tsr->type, tsr->kind); } /* Or check if it's a global variable */ else if (sreg == DWARF_REG_PC) { @@ -665,11 +714,37 @@ static void update_insn_state_x86(struct type_state *state, } tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; tsr->ok = true; pr_debug_dtp("mov [%x] global addr=%"PRIx64" -> reg%d", insn_offset, addr, dst->reg1); - pr_debug_type_name(&type_die); + pr_debug_type_name(&type_die, tsr->kind); + } + /* And check percpu access with base register */ + else if (has_reg_type(state, sreg) && + state->regs[sreg].kind == TSR_KIND_PERCPU_BASE) { + u64 ip = dloc->ms->sym->start + dl->al.offset; + int offset; + + /* + * In kernel, %gs points to a per-cpu region for the + * current CPU. Access with a constant offset should + * be treated as a global variable access. + */ + if (get_global_var_type(cu_die, dloc, ip, src->offset, + &offset, &type_die) && + die_get_member_type(&type_die, offset, &type_die)) { + tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; + tsr->ok = true; + + pr_debug_dtp("mov [%x] percpu %#x(reg%d) -> reg%d type=", + insn_offset, src->offset, sreg, dst->reg1); + pr_debug_type_name(&tsr->type, tsr->kind); + } else { + tsr->ok = false; + } } /* Or try another register if any */ else if (src->multi_regs && sreg == src->reg1 && @@ -677,8 +752,22 @@ static void update_insn_state_x86(struct type_state *state, sreg = src->reg2; goto retry; } - /* It failed to get a type info, mark it as invalid */ else { + int offset; + const char *var_name = NULL; + + /* it might be per-cpu variable (in kernel) access */ + if (src->offset < 0) { + if (get_global_var_info(dloc, (s64)src->offset, + &var_name, &offset) && + !strcmp(var_name, "__per_cpu_offset")) { + tsr->kind = TSR_KIND_PERCPU_BASE; + + pr_debug_dtp("mov [%x] percpu base reg%d\n", + insn_offset, dst->reg1); + } + } + tsr->ok = false; } } @@ -693,6 +782,8 @@ static void update_insn_state_x86(struct type_state *state, struct type_state_stack *stack; int offset = dst->offset - fboff; + tsr = &state->regs[src->reg1]; + stack = find_stack_state(state, offset); if (stack) { /* @@ -703,16 +794,16 @@ static void update_insn_state_x86(struct type_state *state, * die_get_member_type(). */ if (!stack->compound) - set_stack_state(stack, offset, - &state->regs[src->reg1].type); + set_stack_state(stack, offset, tsr->kind, + &tsr->type); } else { - findnew_stack_state(state, offset, - &state->regs[src->reg1].type); + findnew_stack_state(state, offset, tsr->kind, + &tsr->type); } pr_debug_dtp("mov [%x] reg%d -> -%#x(stack)", insn_offset, src->reg1, -offset); - pr_debug_type_name(&state->regs[src->reg1].type); + pr_debug_type_name(&tsr->type, tsr->kind); } /* * Ignore other transfers since it'd set a value in a struct @@ -824,10 +915,11 @@ static bool check_matching_type(struct type_state *state, Dwarf_Word size; u32 insn_offset = dloc->ip - dloc->ms->sym->start; - pr_debug_dtp("chk [%x] reg%d offset=%#x ok=%d", - insn_offset, reg, dloc->op->offset, state->regs[reg].ok); + pr_debug_dtp("chk [%x] reg%d offset=%#x ok=%d kind=%d", + insn_offset, reg, dloc->op->offset, + state->regs[reg].ok, state->regs[reg].kind); - if (state->regs[reg].ok) { + if (state->regs[reg].ok && state->regs[reg].kind == TSR_KIND_TYPE) { int tag = dwarf_tag(&state->regs[reg].type); pr_debug_dtp("\n"); @@ -893,10 +985,25 @@ static bool check_matching_type(struct type_state *state, return true; } + if (state->regs[reg].kind == TSR_KIND_PERCPU_BASE) { + u64 var_addr = dloc->op->offset; + int var_offset; + + pr_debug_dtp(" percpu var\n"); + + if (get_global_var_type(cu_die, dloc, dloc->ip, var_addr, + &var_offset, type_die)) { + dloc->type_offset = var_offset; + return true; + } + return false; + } + if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) { u64 addr; int offset; + /* Direct this-cpu access like "%gs:0x34740" */ if (dloc->op->segment == INSN_SEG_X86_GS && dloc->op->imm) { pr_debug_dtp(" this-cpu var\n"); @@ -907,6 +1014,24 @@ static bool check_matching_type(struct type_state *state, dloc->type_offset = offset; return true; } + return false; + } + + /* Access to per-cpu base like "-0x7dcf0500(,%rdx,8)" */ + if (dloc->op->offset < 0 && reg != state->stack_reg) { + const char *var_name = NULL; + + addr = (s64) dloc->op->offset; + + if (get_global_var_info(dloc, addr, &var_name, &offset) && + !strcmp(var_name, "__per_cpu_offset") && offset == 0 && + get_global_var_type(cu_die, dloc, dloc->ip, addr, + &offset, type_die)) { + pr_debug_dtp(" percpu base\n"); + + dloc->type_offset = offset; + return true; + } } } @@ -1015,7 +1140,7 @@ static int find_data_type_block(struct data_loc_info *dloc, int reg, ret = 0; pr_debug_dtp("found by insn track: %#x(reg%d) type-offset=%#x", dloc->op->offset, reg, dloc->type_offset); - pr_debug_type_name(type_die); + pr_debug_type_name(type_die, TSR_KIND_TYPE); break; } @@ -1147,7 +1272,7 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) loc->offset, reg, fb_offset, offset); else pr_debug_dtp("%#x(reg%d)", loc->offset, reg); - pr_debug_type_name(type_die); + pr_debug_type_name(type_die, TSR_KIND_TYPE); } dloc->type_offset = offset; goto out; From patchwork Tue Mar 19 05:51:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596149 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EAFEC8060D; Tue, 19 Mar 2024 05:51:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827490; cv=none; b=DOY34xHJZy4qKlGExHIoJLB5NGMvFC1N6v685jpjM7VHC30Eq7wbiEZxekZv3N/fYfECBovanCcnh1grviEGAQsGy64uokPbuJuApOnUHLKqca5ZRfCcYXS0idv8Ln7NIMRfR1dIqXNiS8h54HO4A7UAu8+A47kGnjxTmnSumjU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827490; c=relaxed/simple; bh=kniRyKinD1XPWhOm9ZuYt3pPTPJOSx3a2pFJaSgowl8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JrhmYXINSGKnjbo3v6vRna0UEePer6vkAOzKgdwhEVPiFlgz1GvviYd7Evj7r9t4isqFkTipocAW3qYF26gx/FqbFtn8ftwgC7hMQ5X0vX8mQ+3gGFRroRor/hPLlC7y3mAoONSEo+bj+A3lWZP8/MCo6fLUyMLdvH/1UR5hQl0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=G6xsYcfM; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="G6xsYcfM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 55D7EC43390; Tue, 19 Mar 2024 05:51:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827489; bh=kniRyKinD1XPWhOm9ZuYt3pPTPJOSx3a2pFJaSgowl8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=G6xsYcfMSYrJvL7S9JnkGu7ihFsS2cFDbUIYj76eotVKTgjDVlIq9adodJKgf+1wW MKaOHriq8M3LWEXkVP7cEXnS4in+9y1XnIwWhH/lE+RPwViZweeiBJxLj3mwChynaK BPg1L9t2Hdmd17xOsoIBgpxscwLN8qnHEgIMx2lpUhOBIqcgL6Qf1GmIe0zZlexmBZ +Ptyx/ZqhbV/8GIgwvKYigDKLAcWiEu0ww6qJc8WvQshB9XnjRrGEJeKXmV1wNlXIE d6gNIYKqQGyufkVHTT+mFbMf9kQqPAfQDazEG/h0IDhyn/onh2CrUFe7cX3JpTrBrl 86y5XdQSIc0fA== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 20/23] perf annotate-data: Handle ADD instructions Date: Mon, 18 Mar 2024 22:51:12 -0700 Message-ID: <20240319055115.4063940-21-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 There are different patterns for percpu variable access using a constant value added to the base.  2aeb:  mov    -0x7da0f7e0(,%rax,8),%r14 # r14 = __per_cpu_offset[cpu]  2af3:  mov    $0x34740,%rax # rax = address of runqueues * 2afa:  add    %rax,%r14 # r14 = &per_cpu(runqueues, cpu)  2bfd:  cmpl   $0x0,0x10(%r14) # cpu_rq(cpu)->has_blocked_load  2b03:  je     0x2b36 At the first instruction, r14 has the __per_cpu_offset. And then rax has an immediate value and then added to r14 to calculate the address of a per-cpu variable. So it needs to track the immediate values and ADD instructions. Similar but a little different case is to use "this_cpu_off" instead of "__per_cpu_offset" for the current CPU. This time the variable address comes with PC-rel addressing. 89: mov $0x34740,%rax # rax = address of runqueues * 90: add %gs:0x7f015f60(%rip),%rax # 19a78 98: incl 0xd8c(%rax) # cpu_rq(cpu)->sched_count Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 107 +++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 83b5aa00f01c..bd10a576cfbf 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -28,6 +28,8 @@ enum type_state_kind { TSR_KIND_INVALID = 0, TSR_KIND_TYPE, TSR_KIND_PERCPU_BASE, + TSR_KIND_CONST, + TSR_KIND_POINTER, }; #define pr_debug_dtp(fmt, ...) \ @@ -53,6 +55,13 @@ static void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) case TSR_KIND_PERCPU_BASE: pr_info(" percpu base\n"); return; + case TSR_KIND_CONST: + pr_info(" constant\n"); + return; + case TSR_KIND_POINTER: + pr_info(" pointer"); + /* it also prints the type info */ + break; case TSR_KIND_TYPE: default: break; @@ -393,7 +402,7 @@ static void set_stack_state(struct type_state_stack *stack, int offset, u8 kind, switch (tag) { case DW_TAG_structure_type: case DW_TAG_union_type: - stack->compound = true; + stack->compound = (kind != TSR_KIND_POINTER); break; default: stack->compound = false; @@ -585,6 +594,58 @@ static void update_insn_state_x86(struct type_state *state, return; } + if (!strncmp(dl->ins.name, "add", 3)) { + u64 imm_value = -1ULL; + int offset; + const char *var_name = NULL; + struct map_symbol *ms = dloc->ms; + u64 ip = ms->sym->start + dl->al.offset; + + if (!has_reg_type(state, dst->reg1)) + return; + + tsr = &state->regs[dst->reg1]; + + if (src->imm) + imm_value = src->offset; + else if (has_reg_type(state, src->reg1) && + state->regs[src->reg1].kind == TSR_KIND_CONST) + imm_value = state->regs[src->reg1].imm_value; + else if (src->reg1 == DWARF_REG_PC) { + u64 var_addr = annotate_calc_pcrel(dloc->ms, ip, + src->offset, dl); + + if (get_global_var_info(dloc, var_addr, + &var_name, &offset) && + !strcmp(var_name, "this_cpu_off") && + tsr->kind == TSR_KIND_CONST) { + tsr->kind = TSR_KIND_PERCPU_BASE; + imm_value = tsr->imm_value; + } + } + else + return; + + if (tsr->kind != TSR_KIND_PERCPU_BASE) + return; + + if (get_global_var_type(cu_die, dloc, ip, imm_value, &offset, + &type_die) && offset == 0) { + /* + * This is not a pointer type, but it should be treated + * as a pointer. + */ + tsr->type = type_die; + tsr->kind = TSR_KIND_POINTER; + tsr->ok = true; + + pr_debug_dtp("add [%x] percpu %#"PRIx64" -> reg%d", + insn_offset, imm_value, dst->reg1); + pr_debug_type_name(&tsr->type, tsr->kind); + } + return; + } + if (strncmp(dl->ins.name, "mov", 3)) return; @@ -632,6 +693,16 @@ static void update_insn_state_x86(struct type_state *state, return; } + if (src->imm) { + tsr->kind = TSR_KIND_CONST; + tsr->imm_value = src->offset; + tsr->ok = true; + + pr_debug_dtp("mov [%x] imm=%#x -> reg%d\n", + insn_offset, tsr->imm_value, dst->reg1); + return; + } + if (!has_reg_type(state, src->reg1) || !state->regs[src->reg1].ok) { tsr->ok = false; @@ -739,13 +810,26 @@ static void update_insn_state_x86(struct type_state *state, tsr->kind = TSR_KIND_TYPE; tsr->ok = true; - pr_debug_dtp("mov [%x] percpu %#x(reg%d) -> reg%d type=", + pr_debug_dtp("mov [%x] percpu %#x(reg%d) -> reg%d", insn_offset, src->offset, sreg, dst->reg1); pr_debug_type_name(&tsr->type, tsr->kind); } else { tsr->ok = false; } } + /* And then dereference the calculated pointer if it has one */ + else if (has_reg_type(state, sreg) && state->regs[sreg].ok && + state->regs[sreg].kind == TSR_KIND_POINTER && + die_get_member_type(&state->regs[sreg].type, + src->offset, &type_die)) { + tsr->type = type_die; + tsr->kind = TSR_KIND_TYPE; + tsr->ok = true; + + pr_debug_dtp("mov [%x] pointer %#x(reg%d) -> reg%d", + insn_offset, src->offset, sreg, dst->reg1); + pr_debug_type_name(&tsr->type, tsr->kind); + } /* Or try another register if any */ else if (src->multi_regs && sreg == src->reg1 && src->reg1 != src->reg2) { @@ -999,6 +1083,25 @@ static bool check_matching_type(struct type_state *state, return false; } + if (state->regs[reg].ok && state->regs[reg].kind == TSR_KIND_POINTER) { + pr_debug_dtp(" percpu ptr\n"); + + /* + * It's actaully pointer but the address was calculated using + * some arithmetic. So it points to the actual type already. + */ + *type_die = state->regs[reg].type; + + dloc->type_offset = dloc->op->offset; + + /* Get the size of the actual type */ + if (dwarf_aggregate_size(type_die, &size) < 0 || + (unsigned)dloc->type_offset >= size) + return false; + + return true; + } + if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) { u64 addr; int offset; From patchwork Tue Mar 19 05:51:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596150 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8973B80637; Tue, 19 Mar 2024 05:51:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827490; cv=none; b=J1OdMLFaaVhNJT9Ui2ndyUNbSXazklMwVfhphehxjgixEL9TBOInEofcgpieyicEcT5Gy79Gz9i+yR0ZDGw+0jtMIbtMSL3RXPrvd9/rjBta58gaGKFHl6U83fU3w/hzjU9fPbfEnA41Lh7hb9cG80gh1yoj8UYyOkp55gBk/Uk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827490; c=relaxed/simple; bh=/JGap4Y9xwXTO8JArBzhog8K1/fRwK77w+sFtNgYcGA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AqIokfdHKxRIUDE5h0rgSkVxPb9LzMvl2bJ9gqGhNAqcynI4JOIF+AgtiBGya/0Idr2h0/LVvb6XgA9+zRFVt02uxypfzTpb8MpTWP1S8//w4ovbGPZGfhrp8f3hziVCuXF1WdjsN+ce+RaH445sAddMkCzxDP62w9bl1A4g2CA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=KvlOHNZU; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="KvlOHNZU" Received: by smtp.kernel.org (Postfix) with ESMTPSA id ED039C433B2; Tue, 19 Mar 2024 05:51:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827490; bh=/JGap4Y9xwXTO8JArBzhog8K1/fRwK77w+sFtNgYcGA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KvlOHNZUM6VJvVdD/A2qsN9TS31Hqzq87keTkHjIVjM4gAf/5CY57+BeCXNyudI4d xoWk+WpqXIxzKFxuSUk64SzMC86MmM2dUQ45WvjGndGVlY/VX9TIRv7Zwwsa3r/5jZ 1Dp3hVFYHAJMsMiGFx1A8d5WXrAu90QNAhELOwN9L2D1C0mhYGTl48kGboQ12yUTU3 ibCfyuY1GYq5j1lFtIuJfrYaTY1nCp/c9biVXcTvZ9e4f1BeI5H35YfZsiBz/PU3Vn Rvq5QzNls305NqXgZu4kUYsNBg6i8OO1U2GOVwPPIeZdIlbMmlektA5pH1dzfOsqzs RvTb0hbTVj9Kw== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 21/23] perf annotate-data: Add stack canary type Date: Mon, 18 Mar 2024 22:51:13 -0700 Message-ID: <20240319055115.4063940-22-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 When the stack protector is enabled, compiler would generate code to check stack overflow with a special value called 'stack carary' at runtime. On x86_64, GCC hard-codes the stack canary as %gs:40. While there's a definition of fixed_percpu_data in asm/processor.h, it seems that the header is not included everywhere and many places it cannot find the type info. As it's in the well-known location (at %gs:40), let's add a pseudo stack canary type to handle it specially. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 46 +++++++++++++++++++++++++++++++++ tools/perf/util/annotate-data.h | 1 + tools/perf/util/annotate.c | 25 ++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index bd10a576cfbf..633fe125fcd8 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -30,6 +30,7 @@ enum type_state_kind { TSR_KIND_PERCPU_BASE, TSR_KIND_CONST, TSR_KIND_POINTER, + TSR_KIND_CANARY, }; #define pr_debug_dtp(fmt, ...) \ @@ -62,6 +63,9 @@ static void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) pr_info(" pointer"); /* it also prints the type info */ break; + case TSR_KIND_CANARY: + pr_info(" stack canary\n"); + return; case TSR_KIND_TYPE: default: break; @@ -676,6 +680,15 @@ static void update_insn_state_x86(struct type_state *state, */ var_addr = src->offset; + if (var_addr == 40) { + tsr->kind = TSR_KIND_CANARY; + tsr->ok = true; + + pr_debug_dtp("mov [%x] stack canary -> reg%d\n", + insn_offset, dst->reg1); + return; + } + if (!get_global_var_type(cu_die, dloc, ip, var_addr, &offset, &type_die) || !die_get_member_type(&type_die, offset, &type_die)) { @@ -991,6 +1004,16 @@ static void delete_var_types(struct die_var_type *var_types) } } +/* should match to is_stack_canary() in util/annotate.c */ +static void setup_stack_canary(struct data_loc_info *dloc) +{ + if (arch__is(dloc->arch, "x86")) { + dloc->op->segment = INSN_SEG_X86_GS; + dloc->op->imm = true; + dloc->op->offset = 40; + } +} + /* It's at the target address, check if it has a matching type */ static bool check_matching_type(struct type_state *state, struct data_loc_info *dloc, int reg, @@ -1038,6 +1061,11 @@ static bool check_matching_type(struct type_state *state, if (stack == NULL) return false; + if (stack->kind == TSR_KIND_CANARY) { + setup_stack_canary(dloc); + return false; + } + *type_die = stack->type; /* Update the type offset from the start of slot */ dloc->type_offset -= stack->offset; @@ -1062,6 +1090,11 @@ static bool check_matching_type(struct type_state *state, if (stack == NULL) return false; + if (stack->kind == TSR_KIND_CANARY) { + setup_stack_canary(dloc); + return false; + } + *type_die = stack->type; /* Update the type offset from the start of slot */ dloc->type_offset -= fboff + stack->offset; @@ -1102,6 +1135,19 @@ static bool check_matching_type(struct type_state *state, return true; } + if (state->regs[reg].ok && state->regs[reg].kind == TSR_KIND_CANARY) { + pr_debug_dtp(" stack canary\n"); + + /* + * This is a saved value of the stack canary which will be handled + * in the outer logic when it returns failure here. Pretend it's + * from the stack canary directly. + */ + setup_stack_canary(dloc); + + return false; + } + if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) { u64 addr; int offset; diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index ae0f87aed804..1b5a152163b5 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -73,6 +73,7 @@ struct annotated_data_type { extern struct annotated_data_type unknown_type; extern struct annotated_data_type stackop_type; +extern struct annotated_data_type canary_type; /** * struct data_loc_info - Data location information diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e4121acb4f88..64e54ff1aa1d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -118,6 +118,13 @@ struct annotated_data_type stackop_type = { }, }; +struct annotated_data_type canary_type = { + .self = { + .type_name = (char *)"(stack canary)", + .children = LIST_HEAD_INIT(canary_type.self.children), + }, +}; + static int arch__grow_instructions(struct arch *arch) { struct ins *new_instructions; @@ -3803,6 +3810,18 @@ static bool is_stack_operation(struct arch *arch, struct disasm_line *dl) return false; } +static bool is_stack_canary(struct arch *arch, struct annotated_op_loc *loc) +{ + /* On x86_64, %gs:40 is used for stack canary */ + if (arch__is(arch, "x86")) { + if (loc->segment == INSN_SEG_X86_GS && loc->imm && + loc->offset == 40) + return true; + } + + return false; +} + u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset, struct disasm_line *dl) { @@ -3929,6 +3948,12 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) } mem_type = find_data_type(&dloc); + + if (mem_type == NULL && is_stack_canary(arch, op_loc)) { + mem_type = &canary_type; + dloc.type_offset = 0; + } + if (mem_type) istat->good++; else From patchwork Tue Mar 19 05:51:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596151 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6A89780C1D; Tue, 19 Mar 2024 05:51:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827491; cv=none; b=DGV7/pUNTO+1Onr3Arh6dUSreAXHXMw/jmpKWIK3StisbDC6uPK3EWgf6P2AUkB9E7uZz9b3r5CA0oJHE+mOCFvzmg4ARAPG21C9OqZebAQawln/EgPtDDtffzd1MB9WyZ5Bm1H3SrymEHQGcXg+Ee5IYG7HvH67SwtKWkBjXQo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827491; c=relaxed/simple; bh=naVgs0IaGcSuV0neyN2FEHTQAFcy2q0bj4mSjLjwK7U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sr6MRbi+LFDO2x3Kzr1Tk7trui8vkmtkc+mrkLU+Aq49iZ5nqc3Bwoc2tPsx60whxZ5GPn+ujviTCTb9MW4pn3khjqG50OQDxASbB510AjLfe1JXxvKpvauMkOWIka7xgAoahn3rfyWXtgQSwjc1Mk4oP+cmy+uzkmWWX9JpsdM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=SGFHIoyq; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="SGFHIoyq" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8D427C433F1; Tue, 19 Mar 2024 05:51:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827491; bh=naVgs0IaGcSuV0neyN2FEHTQAFcy2q0bj4mSjLjwK7U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SGFHIoyqyhu0lvfxer4tVFf0p+VItIrqaN1eu7eSvQysIe2WOLF34E1cSD2H4XWDz fiCoCzl5nDOXGtoQevHcPBtCMsSnnteekgalQtoLY8gjnpjS000wbgwmeZIyf1Ng6m xAXl3VzM/Mw1JisljIcoscYYdCi3mIn/bviOuUuvCnhQopnYB2Vims8suGAovXrex4 /r09/YxAObKfMnnLiy42/4G+HQuni/yAk2Colaper27l1X6eYb/Fgpa5cP3Le8kDr9 5xtrsXV7u7p/txKOVH2o7r6XpkfijCtMCHvkWXXnMb/oTq8RfzmmhLH4CAy1UbuzXA 67/C92jNY0wvw== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 22/23] perf annotate-data: Add a cache for global variable types Date: Mon, 18 Mar 2024 22:51:14 -0700 Message-ID: <20240319055115.4063940-23-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 They are often searched by many different places. Let's add a cache for them to reduce the duplicate DWARF access. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 107 +++++++++++++++++++++++++++++++- tools/perf/util/annotate-data.h | 7 +++ tools/perf/util/dso.c | 2 + tools/perf/util/dso.h | 6 +- 4 files changed, 118 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 633fe125fcd8..4b3184b7c799 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -433,6 +433,91 @@ static struct type_state_stack *findnew_stack_state(struct type_state *state, return stack; } +/* Maintain a cache for quick global variable lookup */ +struct global_var_entry { + struct rb_node node; + char *name; + u64 start; + u64 end; + u64 die_offset; +}; + +static int global_var_cmp(const void *_key, const struct rb_node *node) +{ + const u64 addr = (uintptr_t)_key; + struct global_var_entry *gvar; + + gvar = rb_entry(node, struct global_var_entry, node); + + if (gvar->start <= addr && addr < gvar->end) + return 0; + return gvar->start > addr ? -1 : 1; +} + +static bool global_var_less(struct rb_node *node_a, const struct rb_node *node_b) +{ + struct global_var_entry *gvar_a, *gvar_b; + + gvar_a = rb_entry(node_a, struct global_var_entry, node); + gvar_b = rb_entry(node_b, struct global_var_entry, node); + + return gvar_a->start < gvar_b->start; +} + +static struct global_var_entry *global_var__find(struct data_loc_info *dloc, u64 addr) +{ + struct dso *dso = map__dso(dloc->ms->map); + struct rb_node *node; + + node = rb_find((void *)addr, &dso->global_vars, global_var_cmp); + if (node == NULL) + return NULL; + + return rb_entry(node, struct global_var_entry, node); +} + +static bool global_var__add(struct data_loc_info *dloc, u64 addr, + const char *name, Dwarf_Die *type_die) +{ + struct dso *dso = map__dso(dloc->ms->map); + struct global_var_entry *gvar; + Dwarf_Word size; + + if (dwarf_aggregate_size(type_die, &size) < 0) + return false; + + gvar = malloc(sizeof(*gvar)); + if (gvar == NULL) + return false; + + gvar->name = strdup(name); + if (gvar->name == NULL) { + free(gvar); + return false; + } + + gvar->start = addr; + gvar->end = addr + size; + gvar->die_offset = dwarf_dieoffset(type_die); + + rb_add(&gvar->node, &dso->global_vars, global_var_less); + return true; +} + +void global_var_type__tree_delete(struct rb_root *root) +{ + struct global_var_entry *gvar; + + while (!RB_EMPTY_ROOT(root)) { + struct rb_node *node = rb_first(root); + + rb_erase(node, root); + gvar = rb_entry(node, struct global_var_entry, node); + free(gvar->name); + free(gvar); + } +} + static bool get_global_var_info(struct data_loc_info *dloc, u64 addr, const char **var_name, int *var_offset) { @@ -467,14 +552,25 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, u64 pc; int offset; bool is_pointer = false; - const char *var_name; + const char *var_name = NULL; + struct global_var_entry *gvar; Dwarf_Die var_die; + gvar = global_var__find(dloc, var_addr); + if (gvar) { + if (!dwarf_offdie(dloc->di->dbg, gvar->die_offset, type_die)) + return false; + + *var_offset = var_addr - gvar->start; + return true; + } + /* Try to get the variable by address first */ if (die_find_variable_by_addr(cu_die, var_addr, &var_die, &offset) && check_variable(&var_die, type_die, offset, is_pointer) == 0) { + var_name = dwarf_diename(&var_die); *var_offset = offset; - return true; + goto ok; } if (!get_global_var_info(dloc, var_addr, &var_name, var_offset)) @@ -485,9 +581,14 @@ static bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc, /* Try to get the name of global variable */ if (die_find_variable_at(cu_die, var_name, pc, &var_die) && check_variable(&var_die, type_die, *var_offset, is_pointer) == 0) - return true; + goto ok; return false; + +ok: + /* The address should point to the start of the variable */ + global_var__add(dloc, var_addr - *var_offset, var_name, type_die); + return true; } /** diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index 1b5a152163b5..fe1e53d6e8c7 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -153,6 +153,9 @@ int annotated_data_type__update_samples(struct annotated_data_type *adt, /* Release all data type information in the tree */ void annotated_data_type__tree_delete(struct rb_root *root); +/* Release all global variable information in the tree */ +void global_var_type__tree_delete(struct rb_root *root); + #else /* HAVE_DWARF_SUPPORT */ static inline struct annotated_data_type * @@ -175,6 +178,10 @@ static inline void annotated_data_type__tree_delete(struct rb_root *root __maybe { } +static inline void global_var_type__tree_delete(struct rb_root *root __maybe_unused) +{ +} + #endif /* HAVE_DWARF_SUPPORT */ #endif /* _PERF_ANNOTATE_DATA_H */ diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 22fd5fa806ed..6e2a7198b382 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -1329,6 +1329,7 @@ struct dso *dso__new_id(const char *name, struct dso_id *id) dso->inlined_nodes = RB_ROOT_CACHED; dso->srclines = RB_ROOT_CACHED; dso->data_types = RB_ROOT; + dso->global_vars = RB_ROOT; dso->data.fd = -1; dso->data.status = DSO_DATA_STATUS_UNKNOWN; dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; @@ -1373,6 +1374,7 @@ void dso__delete(struct dso *dso) dso->symbol_names_len = 0; zfree(&dso->symbol_names); annotated_data_type__tree_delete(&dso->data_types); + global_var_type__tree_delete(&dso->global_vars); if (dso->short_name_allocated) { zfree((char **)&dso->short_name); diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index ce9f3849a773..2cdcd1e2ef8b 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -154,7 +154,8 @@ struct dso { size_t symbol_names_len; struct rb_root_cached inlined_nodes; struct rb_root_cached srclines; - struct rb_root data_types; + struct rb_root data_types; + struct rb_root global_vars; struct { u64 addr; @@ -411,4 +412,7 @@ int dso__strerror_load(struct dso *dso, char *buf, size_t buflen); void reset_fd_limit(void); +u64 dso__find_global_type(struct dso *dso, u64 addr); +u64 dso__findnew_global_type(struct dso *dso, u64 addr, u64 offset); + #endif /* __PERF_DSO */ From patchwork Tue Mar 19 05:51:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13596152 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C107E811FF; Tue, 19 Mar 2024 05:51:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827491; cv=none; b=ETW6qY7MsCaRkM+vNnqGJOnuDz71E5LYcB25DmaSjbp5/qsg10fOG7ih2HlsmFsi/0C2bU740BVAfrILF7vkgR+2672VcYCYB0z2czl7JVSBZ+c9RL1Q2XVZuGl86vjxpSQKJlpfZ9X8Rm4DuFJQif6ZftBPbGJAYKUX5yAeQgc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710827491; c=relaxed/simple; bh=f0mkHRNlUfGGLDB2E7rhqWdLV4QOlURXTjK0Hu1VgTU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gw3qKQRxGFbW43YBG+npqiW7RWC3jxZvcln5XDGgVFC5UjLW9sOrLdjemOvEQEIUGkaZxYGKBBrN9+YegFJJ8oBHvrRjV7LZqXFgAlQCNzp77I2VfUpASWBosBm2gmIEVQFMCW5slELpCPTXQMRrUn0mLfAtp+rIwlVlvK1ASAs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YKSPRxKI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YKSPRxKI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 31797C43390; Tue, 19 Mar 2024 05:51:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1710827491; bh=f0mkHRNlUfGGLDB2E7rhqWdLV4QOlURXTjK0Hu1VgTU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YKSPRxKIml4/bAUNwcRs6ey1cie9/DKFrfy+I+UGDM6/T+iBL9P0Ivd6iH37xz836 kDFLEEt+LW1vTYND17xwDsGH41bXZV3WbYmMhYWQeJwTEVoF+dZ8TAZqkLBQqhLwav UL8vGpyIO3fiaUOJdlJ26/koRZJFWH8x3BU/g+r3xr4yPO3d/FWex4QNzIm/GMX4r1 gPMPX6bbkXZU7s4102iaPBHtyrIQ6n9CQ8uMntsm8/m6tIEkX5b9G9y62x3iyYJUIb k9P0wyJUIQ0o1dKurkTQ1m75U1gE7tG9tHlXwt2q75zV9SXD+zec+Tqa73xR/RMhst AvphRzbgFo37g== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org, Linus Torvalds , Stephane Eranian , Masami Hiramatsu , linux-toolchains@vger.kernel.org, linux-trace-devel@vger.kernel.org Subject: [PATCH 23/23] perf annotate-data: Do not retry for invalid types Date: Mon, 18 Mar 2024 22:51:15 -0700 Message-ID: <20240319055115.4063940-24-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.291.gc1ea87d7ee-goog In-Reply-To: <20240319055115.4063940-1-namhyung@kernel.org> References: <20240319055115.4063940-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-trace-devel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 In some cases, it was able to find a type or location info (for per-cpu variable) but cannot match because of invalid offset or missing global information. In those cases, it's meaningless to go to the outer scope and retry because there will be no additional information. Let's change the return type of find_matching_type() and bail out if it returns -1 for the cases. Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 83 +++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 35 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 4b3184b7c799..de035db9d9b4 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -1115,10 +1115,15 @@ static void setup_stack_canary(struct data_loc_info *dloc) } } -/* It's at the target address, check if it has a matching type */ -static bool check_matching_type(struct type_state *state, - struct data_loc_info *dloc, int reg, - Dwarf_Die *cu_die, Dwarf_Die *type_die) +/* + * It's at the target address, check if it has a matching type. + * It returns 1 if found, 0 if not or -1 if not found but no need to + * repeat the search. The last case is for per-cpu variables which + * are similar to global variables and no additional info is needed. + */ +static int check_matching_type(struct type_state *state, + struct data_loc_info *dloc, int reg, + Dwarf_Die *cu_die, Dwarf_Die *type_die) { Dwarf_Word size; u32 insn_offset = dloc->ip - dloc->ms->sym->start; @@ -1137,20 +1142,20 @@ static bool check_matching_type(struct type_state *state, * dereference a memory location. */ if (tag != DW_TAG_pointer_type && tag != DW_TAG_array_type) - return false; + return -1; /* Remove the pointer and get the target type */ if (die_get_real_type(&state->regs[reg].type, type_die) == NULL) - return false; + return -1; dloc->type_offset = dloc->op->offset; /* Get the size of the actual type */ if (dwarf_aggregate_size(type_die, &size) < 0 || (unsigned)dloc->type_offset >= size) - return false; + return -1; - return true; + return 1; } if (reg == dloc->fbreg) { @@ -1160,18 +1165,18 @@ static bool check_matching_type(struct type_state *state, stack = find_stack_state(state, dloc->type_offset); if (stack == NULL) - return false; + return 0; if (stack->kind == TSR_KIND_CANARY) { setup_stack_canary(dloc); - return false; + return -1; } *type_die = stack->type; /* Update the type offset from the start of slot */ dloc->type_offset -= stack->offset; - return true; + return 1; } if (dloc->fb_cfa) { @@ -1185,22 +1190,22 @@ static bool check_matching_type(struct type_state *state, fbreg = -1; if (reg != fbreg) - return false; + return 0; stack = find_stack_state(state, dloc->type_offset - fboff); if (stack == NULL) - return false; + return 0; if (stack->kind == TSR_KIND_CANARY) { setup_stack_canary(dloc); - return false; + return -1; } *type_die = stack->type; /* Update the type offset from the start of slot */ dloc->type_offset -= fboff + stack->offset; - return true; + return 1; } if (state->regs[reg].kind == TSR_KIND_PERCPU_BASE) { @@ -1212,9 +1217,10 @@ static bool check_matching_type(struct type_state *state, if (get_global_var_type(cu_die, dloc, dloc->ip, var_addr, &var_offset, type_die)) { dloc->type_offset = var_offset; - return true; + return 1; } - return false; + /* No need to retry per-cpu (global) variables */ + return -1; } if (state->regs[reg].ok && state->regs[reg].kind == TSR_KIND_POINTER) { @@ -1231,9 +1237,9 @@ static bool check_matching_type(struct type_state *state, /* Get the size of the actual type */ if (dwarf_aggregate_size(type_die, &size) < 0 || (unsigned)dloc->type_offset >= size) - return false; + return -1; - return true; + return 1; } if (state->regs[reg].ok && state->regs[reg].kind == TSR_KIND_CANARY) { @@ -1246,7 +1252,7 @@ static bool check_matching_type(struct type_state *state, */ setup_stack_canary(dloc); - return false; + return -1; } if (map__dso(dloc->ms->map)->kernel && arch__is(dloc->arch, "x86")) { @@ -1262,9 +1268,9 @@ static bool check_matching_type(struct type_state *state, if (get_global_var_type(cu_die, dloc, dloc->ip, addr, &offset, type_die)) { dloc->type_offset = offset; - return true; + return 1; } - return false; + return -1; } /* Access to per-cpu base like "-0x7dcf0500(,%rdx,8)" */ @@ -1280,26 +1286,28 @@ static bool check_matching_type(struct type_state *state, pr_debug_dtp(" percpu base\n"); dloc->type_offset = offset; - return true; + return 1; } + pr_debug_dtp(" negative offset\n"); + return -1; } } pr_debug_dtp("\n"); - return false; + return 0; } /* Iterate instructions in basic blocks and update type table */ -static bool find_data_type_insn(struct data_loc_info *dloc, int reg, - struct list_head *basic_blocks, - struct die_var_type *var_types, - Dwarf_Die *cu_die, Dwarf_Die *type_die) +static int find_data_type_insn(struct data_loc_info *dloc, int reg, + struct list_head *basic_blocks, + struct die_var_type *var_types, + Dwarf_Die *cu_die, Dwarf_Die *type_die) { struct type_state state; struct symbol *sym = dloc->ms->sym; struct annotation *notes = symbol__annotation(sym); struct annotated_basic_block *bb; - bool found = false; + int ret = 0; init_type_state(&state, dloc->arch); @@ -1317,8 +1325,8 @@ static bool find_data_type_insn(struct data_loc_info *dloc, int reg, update_var_state(&state, dloc, addr, dl->al.offset, var_types); if (this_ip == dloc->ip) { - found = check_matching_type(&state, dloc, reg, - cu_die, type_die); + ret = check_matching_type(&state, dloc, reg, + cu_die, type_die); goto out; } @@ -1331,7 +1339,7 @@ static bool find_data_type_insn(struct data_loc_info *dloc, int reg, out: exit_type_state(&state); - return found; + return ret; } /* @@ -1355,6 +1363,7 @@ static int find_data_type_block(struct data_loc_info *dloc, int reg, for (int i = nr_scopes - 1; i >= 0; i--) { Dwarf_Addr base, start, end; LIST_HEAD(this_blocks); + int found; if (dwarf_ranges(&scopes[i], 0, &base, &start, &end) < 0) break; @@ -1385,15 +1394,19 @@ static int find_data_type_block(struct data_loc_info *dloc, int reg, fixup_var_address(var_types, start); /* Find from start of this scope to the target instruction */ - if (find_data_type_insn(dloc, reg, &basic_blocks, var_types, - cu_die, type_die)) { - ret = 0; + found = find_data_type_insn(dloc, reg, &basic_blocks, var_types, + cu_die, type_die); + if (found > 0) { pr_debug_dtp("found by insn track: %#x(reg%d) type-offset=%#x", dloc->op->offset, reg, dloc->type_offset); pr_debug_type_name(type_die, TSR_KIND_TYPE); + ret = 0; break; } + if (found < 0) + break; + /* Go up to the next scope and find blocks to the start */ prev_dst_ip = dst_ip; dst_ip = src_ip;