From patchwork Fri Feb 16 23:54: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: 13560919 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 0F5D2148FFF; Fri, 16 Feb 2024 23:54: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=1708127666; cv=none; b=sSfOLrH/Q3vWR6FE3Ej63oSZ2Pnpkhgv9iU7ZOXQcgr4K9RL17gzTTE4vo1hb5BpdlPahCdu/nKdHskEU51fcEoNvlo5oyuVMAVv1isEp3ZVKxU3a6rP1l3c5hAWchoxs058/uWrOMw1SDTORS6bo6UXQ5+jJ3TnscpSleJ4yl4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127666; c=relaxed/simple; bh=Qw5in8yXru6XDR/MkCtSi5udF5OsSGUvfaaiz1BQ/Vc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CpsXbPZG4elA9E0BSn+0Iaxmh+S3FO6MLvIJQkn9q1fivkFGqQ6rOoMk3NkSPAZrZOSjBizdNhxL4264pHcPNERtzA5oWifWxfNIVsItgc5bHvbbdO+JDd5QfH7X+RohpmA+zVKC7L27e8CMPMnJ1wcWkfX1/QcyzXDCLhk3H14= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lrFcSa2m; 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="lrFcSa2m" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2151BC433C7; Fri, 16 Feb 2024 23:54:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127665; bh=Qw5in8yXru6XDR/MkCtSi5udF5OsSGUvfaaiz1BQ/Vc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lrFcSa2mRpoWSX/v9+yZiSyZX8U54mmS1u1B7ANszJyVkrCyL0oxTOXL0Vu94WFqT QYm4QgDfKMlQ3UPjrHvUCtRN2dmb8tQgha8RkZ/8PXUnMm6113IP7ZRtg+1ewWqDY/ Nb0OsPevP437xNFMXGlOQ5CV6ksbYFw80KPnOzNL+RpnxmlVhnsQvRHs0BS+qLy14v jFXjLF+R1omwAtzj+MHh1nV5lEdncpiJP8ZepuNhipnnvi37Al2HElIP9YalSxDdjb 6B4cqH5ung2S5x5pdMf2G8eFi5NRF4dw+g7o0af8+EeIm8vDImvAGQ7SLWGE/Jf5ve 7jOnr+a7lTTaA== 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/14] perf dwarf-aux: Add die_collect_vars() Date: Fri, 16 Feb 2024 15:54:10 -0800 Message-ID: <20240216235423.2343167-2-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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 --- 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 2791126069b4..f878014c9e27 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 @@ -1479,41 +1513,69 @@ Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc, *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 85dd527ae1f7..efafd3a1f5b6 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 */ @@ -150,6 +159,9 @@ Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc, 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, @@ -178,6 +190,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 Fri Feb 16 23:54: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: 13560920 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 9D33514A087; Fri, 16 Feb 2024 23:54: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=1708127666; cv=none; b=SlMN+7P0tQSoyssMlmYxOqnILdmZuSWBQhMr2SArT2ktWbI0bg3nrGOQYjoT4lpawg3DoQkhRtIa2xkwNGfu1gRl/8mLtq2fUP8+9LzaKJz5tn8fr4BqdYjlOeGL+37LrN8WN+XIVmz8ETEGa36K9FYv1IOV4XqQsyfj+sbNrSE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127666; c=relaxed/simple; bh=yYo85dqmUvjj/MYrq9h8iGZJuhDhkkgQ/jmNNXT6JHI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QLLYHfcGHi/7+GJ+ktNHyGybeqRXUlelqH+MFBFYvwRyaC2rW1s9I767dsEoSPnYW2nb/up/PIzXfpNiK7Fpmz5ziR18q2jwR+P/dRn0PK+X85WVLObs6+J1f4puYrIw73dsJtv4g+jDZquR+vQWxfhchrryFKdEmhJUQiHKAIo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dj2OBKlc; 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="dj2OBKlc" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B49C7C43394; Fri, 16 Feb 2024 23:54:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127666; bh=yYo85dqmUvjj/MYrq9h8iGZJuhDhkkgQ/jmNNXT6JHI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dj2OBKlcSEHwerRQs2FFVXSo6SZ6FtK8rSto1WrOtbZ+DRGo7gvzjEgf50D/MllDs 5no8ezrgD4kYDpItCLEUmRWCuup70QLmll33UzE5yvC88O2T3HJ5Qr0ltfjKqgx7IY Eloy+ilGt8jAkBiPaH1fj9biz6DrrdVD6LkRFKJjgCz0BWrBGeri51KAbkml/MH/xk IoXRitUwiy4h5ex4OWRSle21pi0eqxjhhJbfexoCQAKOaGE2UIJZOgymU7R0IVZui2 TmIokKkbNus2S1f3r/lF8bs1lXwGv2YNHg/y3KXJX5oS+5J9HXzoTR9zuIUHSCdpFi wZpVpp2LwYxRw== 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/14] perf dwarf-aux: Handle type transfer for memory access Date: Fri, 16 Feb 2024 15:54:11 -0800 Message-ID: <20240216235423.2343167-3-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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 f878014c9e27..39851ff1d5c4 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1841,3 +1841,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 efafd3a1f5b6..ad4d7322fcbf 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 Fri Feb 16 23:54:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13560921 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 5483A14A0A4; Fri, 16 Feb 2024 23:54: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=1708127667; cv=none; b=AzgSA6yA7gpHlg2x78KlHEMaikMCwuu4gJRu3A929UvBN39aus1QoMIkKUNIbjcCJWI7dWbWtGsbZCv0pent4aRBrxGoK6gnBOHYSwt80GUlCFLJAh3GnwChqOGIfduHwC6WoiCLyM5H6lXlm5ooy76Zc4F9EdE7Dx+KQqy3ugE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127667; c=relaxed/simple; bh=Uq6bNXvr4kGp89Uou2qipGFct50QoLkSBu5YLU+6QS8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KpBVrbhT4Z9cu2VRXQWNnE7iIebiZOP4yhwqLgPMu9iQnwuaGrrAU7Ky+Ecoe+tq7WxKPqEvGyRHe7fUCwG/+ELcUE2pM1AuejJKFwVZIozqMB1jTr8h8N0QfokdFAbzTCgZE6P+WZcbTjosYJmNR6AqR3fS23ZUjNAv1JHRITg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AlTzbRBJ; 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="AlTzbRBJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 58E70C43609; Fri, 16 Feb 2024 23:54:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127666; bh=Uq6bNXvr4kGp89Uou2qipGFct50QoLkSBu5YLU+6QS8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AlTzbRBJJKMD0yLEatSxoL9A/tszYeSYQG2kFNopP+lFyccWMaZHIKljKTUsRf4kn mFwIopH49aexvgyevJGeugdwz6+SwqxhxSCnSQXA/4AYR7ZnYVbbspM3pU0tExBOlI 214XGwiQHI2ShbW3vu+jtOJOjvy4CyQqbgecGn51JVK6Fs8o/IqDN8vKTtbt/uummH 3A1NgCwIl4s8yBzQUf4eSEsKsWblQmA7U7kK2O21cYy7uYHt6SxnQbDftRcT7tjaw0 /rijHWznuRd+t46QJ3zCdMeIM5h5SrUM3D2CR5G0iWLUfkS/dZ+Tx6hh55wy/eBpyd DVv1zR2hPjnbg== 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/14] perf annotate-data: Introduce struct data_loc_info Date: Fri, 16 Feb 2024 15:54:12 -0800 Message-ID: <20240216235423.2343167-4-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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 30c4d19fcf11..b8e60c42af8c 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, pc, addr, &var_die, &offset)) { + if (die_find_variable_by_addr(&cu_die, pc, 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], pc, addr, + if (!die_find_variable_by_addr(&scopes[i], pc, 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 107b264fa41e..cb5d4c517a4d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3788,9 +3788,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++; @@ -3843,51 +3841,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 Fri Feb 16 23:54: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: 13560922 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 A295014A0B9; Fri, 16 Feb 2024 23:54: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=1708127667; cv=none; b=hzUFPtSK3Bn6Ityx+tunkT8JtlP2jsoDvslFmxJTXcBQfekCiWQhb22mcWtkolJWVjiOaskpNF0pZ87GTo3kHcIqfIQ63HEH8XkgUqH++RF3gT7UpWHT7lrlU32+BU0Y1bMwMVLZYhtFIHcE9p4SdYEkvkPgMbC3TVH/sw4ETUA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127667; c=relaxed/simple; bh=guWfSQhoX6jlJEUVpGGsH55EWxqQ6WRn1lYxZhtk0g8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=k73XK9EYw1hXDnbYYKaACthaV50Zdx2n8ZIZoSQE50KHi9NFXdRokJJr6fMsyHzxPpU7EX3WeJmk2fgG1DN7POF4dEUgbS3R/6y/2QccmKXLI+kX/byLKkPeZdW8YgMRCtOItK74Raq5zkAo7Vd9f/ZYjZQPml5pLKdncXbTdGQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Av659Inu; 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="Av659Inu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 02993C433F1; Fri, 16 Feb 2024 23:54:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127667; bh=guWfSQhoX6jlJEUVpGGsH55EWxqQ6WRn1lYxZhtk0g8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Av659InuKBIH1peQ3YSR4o7AnooIKjsn5U5brRDHW2BxnmzLmyEYHRjWN/G/R0gqH 4z5eRT5M6R7PRIpVHrUPsdL3S/CBBec1qaDdpWVfFSkLghSe4AVPFhxPwzvAufO9Yk niXrX9ColBgpzW4dR0Y3J7g3OWJaQkMddGl3b2UBfkAMzmVOwxrKGGujeRvtoEXqUS QlbT4dkBiQTMVvkjhShC4wTvMKDiYb+2byX4uyusPIvrxYd+DfzVd1TEDGWRRb3SI5 RB9mD6BzGIZApNhG/7MmMoNikvMPbCq422jevP+EpoCZtsqSxUZqeyMYrUvgTTdeUE DH6+I4D32Rg4Q== 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/14] perf map: Add map__objdump_2rip() Date: Fri, 16 Feb 2024 15:54:13 -0800 Message-ID: <20240216235423.2343167-5-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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 Fri Feb 16 23:54: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: 13560923 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 9793514A4F3; Fri, 16 Feb 2024 23:54: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=1708127668; cv=none; b=frS1Xanpp6sFM++bMnVjWW2jdBA7B6fnjAPxuDOxKINPaKwenUKgU0tIYCSJnoQRHNd6ILHMUrW+w/qF7fI1xHTUzGjxNzX6DLQcMVGPINqf70fMF9vyYIRfTAgm+SkaXmmsXCYArwhK4BxceJKKVqu0HTBoGv+uRL2BuO0HF5M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127668; c=relaxed/simple; bh=7EAn2Z7hh95QVpxT5LLVg3XrS1iSEiXohUgQ6njH8Hg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uJDdRo58u9MrQN2TEuECg/UKcq92Z17wCavTT/xBjy5lZMB24NXtHRoJ/Oh1gDgikMMaXsyYBXofRUAODvIYuxSYN8OZfC018B7x7tHh7QinzuU7H95ZoFcHyCwho4s1hxE529R7Q9U0cne8v9yOSUYAsgl8e/A2BhplWuTfwwA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZeLCMDV7; 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="ZeLCMDV7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9DC2AC433B1; Fri, 16 Feb 2024 23:54:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127668; bh=7EAn2Z7hh95QVpxT5LLVg3XrS1iSEiXohUgQ6njH8Hg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZeLCMDV7bHtdsFi8sCylsREmrW9tSE3m0vzGLdXQI0OC1VxfLN81/lMqFjVzT2DpS mQqvRLFyDJut08I1lYqvTfBqf2EyCzVPeC3B63aMK2CtBSILhAz/CwXEObNRhXAP6S Y6Pc3SqQOoLYjNx2VQzj0jV9euTr3TUgLqhWFCXpbxNZTlC48BBiN7IDqfPz9HHhWQ WMUSTki/oEvwNq3LcenYTN6m6tBCxXy8nv605+fn44WeeypIakSbvNzkTatIPh4toT HFN/Y76xhbe1W4AbXKR3eX2uPtVkAOGP+uZhxKiA1PD6UVw9EUx8CoCriP/JPFyG2x ej3V0tPVkmGIA== 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/14] perf annotate: Add annotate_get_basic_blocks() Date: Fri, 16 Feb 2024 15:54:14 -0800 Message-ID: <20240216235423.2343167-6-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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 cb5d4c517a4d..4ef14b3f49e4 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3686,7 +3686,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; @@ -3699,7 +3700,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; } @@ -3815,7 +3817,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; @@ -3909,3 +3911,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 94435607c958..83afbe294ab7 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -495,4 +495,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 Fri Feb 16 23:54: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: 13560924 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 DB52B14AD12; Fri, 16 Feb 2024 23:54: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=1708127669; cv=none; b=Ty1NDCaiK/y1UYbNrqzGE++F9y6l6Paix/P1MPEQG4OeJLMTKcCPCb/yfbEYMgUxe1GV7CACH87+licoM76alKEKYpFUArjS2yNq5hgnO8UdBLkNdSUzWk5rfQLkkC5gMQvT6gofuEG1XcviacPmE8+Wj1yNmr8LeubkfQ5WDVY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127669; c=relaxed/simple; bh=eSM/+Sxgv8mx5E2cIdXWdLARV/iN60h+68eiZpB+exQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NE+zryffkGHqm7RcjxVVcnxqx0nrCrMFWA3XZysWwUqKxyEmGS4i7KSfzoczN5n1GkXdMZ+nWaNeENAdWZd3DgTe5dFAS5lfOw9NA4OpV/tDHJp3Q1SOQUk8HJ0CKfw7oNYF4cQyFDhTLQiPFeqvAuq2lHUt/8DwNVgBjUFpOLE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=SZtMVSoT; 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="SZtMVSoT" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 414A3C43399; Fri, 16 Feb 2024 23:54:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127668; bh=eSM/+Sxgv8mx5E2cIdXWdLARV/iN60h+68eiZpB+exQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SZtMVSoT06QzBYligpAPGL6iZHXBO/ugGVASvjx5gb+i4i6s226UQu1/jJ9Q4MU4Z c67rEzQGPBbAvdvQoY9snrYXWTL/Hwt1jkgR2DnxvJY9jPAxVm2s2hSRgPQOl5sCim CciVu7/w49SU0wFrZBZT+AnL/OvpTHqiUdqnzfVrK8JknzVSsckzqvTsVsmdSxYWgC 5exoQu2H4Iw/sjoq7Cn1ks7k7wQ0SvIOrESF2KPATJJOOhvuu9vMSq7b0cK6khAnQX cl8LbC7IN9RO4MXaoQ5F4lTv5L5ClE0bVP7grRBN9agjd3lzkN94av0ED4HFKV/Co0 /v1jiQZJPi/+A== 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/14] perf annotate-data: Maintain variable type info Date: Fri, 16 Feb 2024 15:54:15 -0800 Message-ID: <20240216235423.2343167-7-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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 | 155 ++++++++++++++++++++++++++++++++ tools/perf/util/annotate-data.h | 29 ++++++ tools/perf/util/dwarf-aux.c | 4 + 3 files changed, 188 insertions(+) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index b8e60c42af8c..f8768c224bcc 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -23,6 +23,57 @@ #include "symbol.h" #include "symbol_conf.h" +/* Type information in a register, valid when ok is true */ +struct type_state_reg { + Dwarf_Die type; + bool ok; + bool scratch; +}; + +/* 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); +} + +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 @@ -238,6 +289,110 @@ 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 update + * @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, 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); + } else if (var->reg == fbreg) { + findnew_stack_state(state, var->offset - fb_offset, &mem_die); + } else if (has_reg_type(state, var->reg)) { + struct type_state_reg *reg; + + reg = &state->regs[var->reg]; + reg->type = mem_die; + reg->ok = true; + } + } +} + /* 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..7fbb9eb2e96f 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -8,9 +8,12 @@ #include struct annotated_op_loc; +struct arch; struct debuginfo; +struct die_var_type; struct evsel; struct map_symbol; +struct type_state; /** * struct annotated_member - Type of member field @@ -146,6 +149,16 @@ 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); +/* Initialize type state table */ +void init_type_state(struct type_state *state, struct arch *arch); + +/* Destroy type state table */ +void exit_type_state(struct type_state *state); + +/* Update type state table using variables */ +void update_var_state(struct type_state *state, struct data_loc_info *dloc, + u64 addr, struct die_var_type *var_types); + #else /* HAVE_DWARF_SUPPORT */ static inline struct annotated_data_type * @@ -168,6 +181,22 @@ static inline void annotated_data_type__tree_delete(struct rb_root *root __maybe { } +static inline void init_type_state(struct type_state *state __maybe_unused, + struct arch *arch __maybe_unused) +{ +} + +static inline void exit_type_state(struct type_state *state __maybe_unused) +{ +} + +static inline void update_var_state(struct type_state *state __maybe_unused, + struct data_loc_info *dloc __maybe_unused, + u64 addr __maybe_unused, + struct die_var_type *var_types __maybe_unused) +{ +} + #endif /* HAVE_DWARF_SUPPORT */ #endif /* _PERF_ANNOTATE_DATA_H */ diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 39851ff1d5c4..f88a8fb4a350 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" @@ -1147,6 +1148,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; } @@ -1160,6 +1163,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 Fri Feb 16 23:54:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13560925 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 8341714C589; Fri, 16 Feb 2024 23:54: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=1708127669; cv=none; b=RHkmJm6S2TY2v1iBpy/BFx/Uz2v+vVfH+YiyBc9ZKe4KaBJXXFFLtG7xVqmI8luheFsUwx1gmvURsjEqSvVjVbEOD62UxtcDsynzeKkrOHKCZJlsArTsxSyllhQ2rXu3vCOnN6yEdlABTJzKBanw9KP7wPvB11NeeNezHW/qyfM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127669; c=relaxed/simple; bh=LZgtF1cN7v1cB/kC9ZwKwA1r5hlpoAXLKbeHZPP2G0U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UJC0cpvEympnYR9A18alNglD4SRPF9xRE01XRxUi0l7A8GvYTiWKQVsvof5s/eXvxvAX0dvUAsP29dh7Vm0QOP2PJPVMRCoEB1TayTArL5lP1iDq1HrbftESOrHptcDzEJRVbxO15mQn1BJ0FINXjq+Vmeokb9V2TcLkYqhoYC0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VmV/yUso; 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="VmV/yUso" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D9398C43601; Fri, 16 Feb 2024 23:54:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127669; bh=LZgtF1cN7v1cB/kC9ZwKwA1r5hlpoAXLKbeHZPP2G0U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VmV/yUso96Fj3kVWMUAkerJtrZCGtaIcBw7PSCkIUOhF2zT46L1UnMFLl3gip/EPW wCh50zPJQN+0iqIPQ6cmxNCpBFenXGH5RdySTht69jo9nCXk7QSABgUrOiD0fCwOMC /bJuPvFb3QRLRoBsaP1vpeBhBd99BEbGbKV7eMZYNNfqeuVJgxDor3F9pdD0U5bRZo gTiY2IHIiCfiPcC1RZMgXUhHiOZ9DU0pq3pGaWyL8gQrRmRKN7EkmQdVaOpAC+ZgPV y+/I3P3DVR3ggOo6Mh0a/w6YFAZyhN6vnYcA3DctnyO+rlSC8RDrNKc+hIFPXzuY8N NtVb7IZsn8GOg== 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/14] perf annotate-data: Add update_insn_state() Date: Fri, 16 Feb 2024 15:54:16 -0800 Message-ID: <20240216235423.2343167-8-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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 | 128 +++++++++++++++++++++++++++++++- tools/perf/util/annotate-data.h | 13 ++++ tools/perf/util/annotate.c | 1 + 3 files changed, 140 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index f8768c224bcc..b1e921663452 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -27,7 +27,6 @@ struct type_state_reg { Dwarf_Die type; bool ok; - bool scratch; }; /* Type information in a stack location, dynamically allocated */ @@ -383,7 +382,7 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, findnew_stack_state(state, var->offset, &mem_die); } else if (var->reg == fbreg) { findnew_stack_state(state, var->offset - fb_offset, &mem_die); - } else if (has_reg_type(state, var->reg)) { + } else if (has_reg_type(state, var->reg) && var->offset == 0) { struct type_state_reg *reg; reg = &state->regs[var->reg]; @@ -393,6 +392,131 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, } } +/** + * update_insn_state - Update type state for an instruction + * @state: type state table + * @dloc: data location info + * @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) +{ + 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]; + Dwarf_Die type_die; + int fbreg = dloc->fbreg; + int fboff = 0; + + /* FIXME: remove x86 specific code and handle more instructions like LEA */ + if (!strstr(dl->ins.name, "mov")) + return; + + if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0) + 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; + + if (has_reg_type(state, src->reg1)) + state->regs[dst->reg1] = state->regs[src->reg1]; + else + state->regs[dst->reg1].ok = false; + } + /* 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; + +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 && die_get_member_type(&stack->type, + offset - stack->offset, + &type_die)) { + state->regs[dst->reg1].type = type_die; + state->regs[dst->reg1].ok = true; + } else + state->regs[dst->reg1].ok = false; + } + /* 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)) { + state->regs[dst->reg1].type = type_die; + state->regs[dst->reg1].ok = true; + } + /* 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 { + state->regs[dst->reg1].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); + } + } + /* + * 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) */ +} + /* 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 7fbb9eb2e96f..ff9acf6ea808 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -11,6 +11,7 @@ struct annotated_op_loc; struct arch; struct debuginfo; struct die_var_type; +struct disasm_line; struct evsel; struct map_symbol; struct type_state; @@ -78,6 +79,7 @@ extern struct annotated_data_type stackop_type; /** * struct data_loc_info - Data location information + * @arch: architecture info * @ms: Map and Symbol info * @ip: Instruction address * @var_addr: Data address (for global variables) @@ -90,6 +92,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; @@ -159,6 +162,10 @@ void exit_type_state(struct type_state *state); void update_var_state(struct type_state *state, struct data_loc_info *dloc, u64 addr, struct die_var_type *var_types); +/* Update type state table for an instruction */ +void update_insn_state(struct type_state *state, struct data_loc_info *dloc, + struct disasm_line *dl); + #else /* HAVE_DWARF_SUPPORT */ static inline struct annotated_data_type * @@ -197,6 +204,12 @@ static inline void update_var_state(struct type_state *state __maybe_unused, { } +static inline void update_insn_state(struct type_state *state __maybe_unused, + struct data_loc_info *dloc __maybe_unused, + struct disasm_line *dl __maybe_unused) +{ +} + #endif /* HAVE_DWARF_SUPPORT */ #endif /* _PERF_ANNOTATE_DATA_H */ diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 4ef14b3f49e4..44574056d4bd 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3844,6 +3844,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 Fri Feb 16 23:54:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13560926 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 2407F14C5B7; Fri, 16 Feb 2024 23:54: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=1708127670; cv=none; b=csPh6MuXYkq6PGoasZc3KLHM8X9onvtuyrAiHIIDh4QCfsuC0J/FWevepGjGaMidE50AwUhEXzs0155+01nE5kbarmIpnRjOW+XE/Y7YvKacu7SMYNtdN31c/oPFLhOIr9XoMiRLlFkt8ZLeqISv7V1hWXy4O5/pJ6KqewavZwI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127670; c=relaxed/simple; bh=PrQxE5dvr8+mJjo6e46jyPhkqtx2vS84G0Ikoy+xe+0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hXpXa6eqRZqu7OfMsoBywoadCQGDDsezHwBzARn2ZxGrlfHss/Guhd74gaKVWSMmCCCjYBDE5MPAqxYhFHSYiTyj1ba+C5dIoertN0o3txkVvyswx0zalOTVJ+YU6pM6Jk/xwIqSwGGWradu4QNeHQGCGx6jnVQaAcKwTBAmGyY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=hO2TBk0Q; 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="hO2TBk0Q" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7E0CBC433C7; Fri, 16 Feb 2024 23:54:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127670; bh=PrQxE5dvr8+mJjo6e46jyPhkqtx2vS84G0Ikoy+xe+0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hO2TBk0QA5Dkf4pTpyVPmUBRWot7k4ysGW1sHeSHa+2FMWZmHYcnNto2YdQ0MQZIl Z8IRUUNKeToP91HGcxZA44Y4eK3WC/uBKOy/UPfK34getv3G2TPhfsNZf1+U6VzHXY eSEx3ybnkL3aJ2fQNe0xREFItYRb2Fp7kNmuxcNlDfLtMoyGZWY7MWkBm6URRHec7r SbSraPy+w0kCV2SC5WBKyI6Z3hjp0/NHE8qWoV+7CeE7ZqPSzhxB//dg4yvDGIeE2R ZwfDwqjQgZ7pSCBne63+D9DbSg06iQmpU3vXJLHgmRBghHkrnS0CBaolauHX5zBR8X fffLsvMvMqUNQ== 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/14] perf annotate-data: Handle global variable access Date: Fri, 16 Feb 2024 15:54:17 -0800 Message-ID: <20240216235423.2343167-9-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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 | 45 ++++++++++++++++++++++++++++++--- tools/perf/util/annotate-data.h | 10 ++++++-- tools/perf/util/annotate.c | 45 ++++++++++++++++++++------------- tools/perf/util/annotate.h | 5 ++++ 4 files changed, 83 insertions(+), 22 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index b1e921663452..e46e162c783f 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -396,6 +396,7 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, * 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 @@ -407,7 +408,7 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, * are true. */ void update_insn_state(struct type_state *state, struct data_loc_info *dloc, - struct disasm_line *dl) + void *cu_die, struct disasm_line *dl) { struct annotated_insn_loc loc; struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE]; @@ -449,8 +450,46 @@ void update_insn_state(struct type_state *state, struct data_loc_info *dloc, return; retry: - /* Check stack variables with offset */ - if (sreg == fbreg) { + /* Check if it's a global variable */ + if (sreg == DWARF_REG_PC) { + Dwarf_Die var_die; + struct map_symbol *ms = dloc->ms; + int offset = src->offset; + u64 ip = ms->sym->start + dl->al.offset; + u64 pc, addr; + const char *var_name = NULL; + + addr = annotate_calc_pcrel(ms, ip, offset, dl); + pc = map__rip_2objdump(ms->map, ip); + + if (die_find_variable_by_addr(cu_die, pc, addr, + &var_die, &offset) && + check_variable(&var_die, &type_die, offset, + /*is_pointer=*/false) == 0 && + die_get_member_type(&type_die, offset, &type_die)) { + state->regs[dst->reg1].type = type_die; + state->regs[dst->reg1].ok = true; + return; + } + + /* Try to get the name of global variable */ + offset = src->offset; + get_global_var_info(dloc->thread, ms, ip, dl, + dloc->cpumode, &addr, + &var_name, &offset); + + if (var_name && die_find_variable_at(cu_die, var_name, + pc, &var_die) && + check_variable(&var_die, &type_die, offset, + /*is_pointer=*/false) == 0 && + die_get_member_type(&type_die, offset, &type_die)) { + state->regs[dst->reg1].type = type_die; + state->regs[dst->reg1].ok = true; + } else + state->regs[dst->reg1].ok = false; + } + /* And check stack variables with offset */ + else if (sreg == fbreg) { struct type_state_stack *stack; int offset = src->offset - fboff; diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index ff9acf6ea808..0bfef29fa52c 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -14,6 +14,7 @@ struct die_var_type; struct disasm_line; struct evsel; struct map_symbol; +struct thread; struct type_state; /** @@ -79,11 +80,13 @@ extern struct annotated_data_type stackop_type; /** * struct data_loc_info - Data location information - * @arch: architecture info + * @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 @@ -94,8 +97,10 @@ struct data_loc_info { /* These are input field, should be filled by caller */ struct arch *arch; struct map_symbol *ms; + struct thread *thread; u64 ip; u64 var_addr; + u8 cpumode; const char *var_name; struct annotated_op_loc *op; @@ -164,7 +169,7 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, /* Update type state table for an instruction */ void update_insn_state(struct type_state *state, struct data_loc_info *dloc, - struct disasm_line *dl); + void *cu_die, struct disasm_line *dl); #else /* HAVE_DWARF_SUPPORT */ @@ -206,6 +211,7 @@ static inline void update_var_state(struct type_state *state __maybe_unused, static inline void update_insn_state(struct type_state *state __maybe_unused, struct data_loc_info *dloc __maybe_unused, + void *cu_die __maybe_unused, struct disasm_line *dl __maybe_unused) { } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 44574056d4bd..89a8d57b1bf7 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3771,6 +3771,28 @@ u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset, return map__rip_2objdump(ms->map, addr); } +void get_global_var_info(struct thread *thread, struct map_symbol *ms, u64 ip, + struct disasm_line *dl, u8 cpumode, u64 *var_addr, + const char **var_name, int *poffset) +{ + struct addr_location al; + struct symbol *var; + u64 map_addr; + + *var_addr = annotate_calc_pcrel(ms, ip, *poffset, dl); + /* Kernel symbols might be relocated */ + map_addr = *var_addr + map__reloc(ms->map); + + addr_location__init(&al); + var = thread__find_symbol_fb(thread, cpumode, map_addr, &al); + if (var) { + *var_name = var->name; + /* Calculate type offset from the start of variable */ + *poffset = map_addr - map__unmap_ip(al.map, var->start); + } + addr_location__exit(&al); +} + /** * hist_entry__get_data_type - find data type for given hist entry * @he: hist entry @@ -3845,6 +3867,8 @@ 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, + .cpumode = he->cpumode, .ms = ms, /* Recalculate IP for LOCK prefix or insn fusion */ .ip = ms->sym->start + dl->al.offset, @@ -3859,23 +3883,10 @@ 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.type_offset = op_loc->offset; + get_global_var_info(he->thread, ms, ip, dl, he->cpumode, + &dloc.var_addr, &dloc.var_name, + &dloc.type_offset); } mem_type = find_data_type(&dloc); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 83afbe294ab7..b460785111a1 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -23,6 +23,7 @@ struct option; struct perf_sample; struct evsel; struct symbol; +struct thread; struct annotated_data_type; struct ins { @@ -495,6 +496,10 @@ extern struct list_head ann_insn_stat; u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset, struct disasm_line *dl); +void get_global_var_info(struct thread *thread, struct map_symbol *ms, u64 ip, + struct disasm_line *dl, u8 cpumode, u64 *var_addr, + const char **var_name, int *poffset); + /** * struct annotated_basic_block - Basic block of instructions * @list: List node From patchwork Fri Feb 16 23:54:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13560928 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 902ED14E2C4; Fri, 16 Feb 2024 23:54: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=1708127671; cv=none; b=SwvFCNsX1TjIIR/gAJYIhd50mvtT+YbPwSIk9dKWMYtdPfSXq+9TaxZauzV6tPbKXvEGZcYWgkTOY5GZgZddZfw+P1WwhG/FyhUquBRF7emJyrGnEiUURRd7Fg9jmeLZBU6u1+cZCgxTO1Mxs3aLfixUz3gDayhtZ7xYZegKdPE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127671; c=relaxed/simple; bh=zZHOIpCOQRvZUMTIDQX7NJi7rHNLMrUEbf5ATQRYfWI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JAxZDGh9xLbIVk7RbY55S+6brTpgQtaPFD7RwaKF6KXj3mbqYVdWEI2Eej2xU+zNc/nVihQrlyVLDhccdLkstwI4aYAGSqXlQOw+LNhAYJPWgUM1dVz18wRdn1Zh+21RkZeJlmO7vknLzwRhvVr1aaUhu20O3mQ4a4y5NjN6cEg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=tZVxGjD9; 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="tZVxGjD9" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 215B6C433B1; Fri, 16 Feb 2024 23:54:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127670; bh=zZHOIpCOQRvZUMTIDQX7NJi7rHNLMrUEbf5ATQRYfWI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tZVxGjD9fx55g/829dqU23cR9Np786MufZf4Yc5V7mqADC3/a+IuTCz2gRxEWzfhO M9QSXZnPQKiyslE/mGzNLg/0UoyBZsox0KCkEQnV54tIKBjukFdb29EnXfXahcqaSN kCzb5KBTY+SuyYADZPxf2V2oOiCtEEVithd3oP25ZfewJYx6UdtdpRrLiEr2kqayIa WqGWQ3+gca7KSH9b2bspj15L9eSz0/0sb686xOPqciCrlTbYUGEh3B7EW8MpFPMsDw An6T8jbnrK+LWBfKAwN32K6wccKsYCsA1WKgPPlxZCqmNXhin/HShdaG2Eyy+ZItYE mz7FSZcKt6MsA== 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/14] perf annotate-data: Handle call instructions Date: Fri, 16 Feb 2024 15:54:18 -0800 Message-ID: <20240216235423.2343167-10-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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 | 45 +++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index e46e162c783f..e8e363fed8c2 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -23,10 +23,14 @@ #include "symbol.h" #include "symbol_conf.h" -/* 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 */ @@ -50,6 +54,7 @@ struct type_state_stack { struct type_state { struct type_state_reg regs[TYPE_STATE_MAX_REGS]; struct list_head stack_vars; + int ret_reg; }; static bool has_reg_type(struct type_state *state, int reg) @@ -57,10 +62,23 @@ static bool has_reg_type(struct type_state *state, int reg) return (unsigned)reg < ARRAY_SIZE(state->regs); } -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) @@ -417,6 +435,29 @@ void update_insn_state(struct type_state *state, struct data_loc_info *dloc, int fbreg = dloc->fbreg; int fboff = 0; + if (ins__is_call(&dl->ins)) { + Dwarf_Die func_die; + + /* __fentry__ will preserve all registers */ + if (dl->ops.target.sym && + !strcmp(dl->ops.target.sym->name, "__fentry__")) + return; + + /* 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_realfunc(cu_die, dl->ops.target.addr, &func_die) && + die_get_real_type(&func_die, &type_die)) { + state->regs[state->ret_reg].type = type_die; + state->regs[state->ret_reg].ok = true; + } + return; + } + /* FIXME: remove x86 specific code and handle more instructions like LEA */ if (!strstr(dl->ins.name, "mov")) return; From patchwork Fri Feb 16 23:54:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13560927 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 8D04E14E2C3; Fri, 16 Feb 2024 23:54: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=1708127671; cv=none; b=lidHjEeH7QUvUrHailowGQFobxkcIkFphuo6qUiDkmcfhL3XORiinKiS2w9+zNC77FrQSqzkLzIFZ3M3HZcoUz0EOPclteNUwIGoSDiMQ4NyFmnr4JeFfsbnD9giGo21323ZIq7m2GKCd+9eAtOlXGmzL2mVP0eMYn9wwVWHJUw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127671; c=relaxed/simple; bh=mxQgos6l91axIiDZvKbOHQz0qaSv4aKPPA72xFNlJzY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mZrEVG+BNVBEFqLDrQ0Sa3xaBDn85jQxzA471EYalHZf4HzaZRfNH+ZBs225qgDW2XwVIOjqLSwN5GwWvyxx4vJQJqyDb2e2Fki8wgbLTMQ6u4ae8mfBXLduM8fCVn2V9TrVGqWCW+Pfs69jRo9HuqW9jZYa6epHq0XE1jhQ9+I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=svlHEZrA; 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="svlHEZrA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DAE6CC43390; Fri, 16 Feb 2024 23:54:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127671; bh=mxQgos6l91axIiDZvKbOHQz0qaSv4aKPPA72xFNlJzY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=svlHEZrAjad61GT4SGkJYPeohlJ4BH2qhvWmrxvxGrgSPgmm9VdPFU5c/003bc+Lj eMhbhdKn4D4Y26VTgamKR4HW3SC3Rc8rd0Wf4dDb8dJYMYwcDvctHtzVcbufYGNYrF Tomua08pSdvQxPRrm11AIxUZX4m8iB+8Ul9X+YZm1UAcLFT5Vk7LM/0iJeQSyeZ4Ej lVp9DhbMqZRnAoKF74yn7afwi9C6F2lJ4pVmg2g/XBZAmTJBLeGggBEEWEFDhphXkL ctbiVIxgfqYXE6XLZFE55rvrg+5O3QmHvhM/ey9+ZreCk8HVXH2L8eExGBss0utcrD QRMfg3imvQrXg== 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/14] perf annotate-data: Implement instruction tracking Date: Fri, 16 Feb 2024 15:54:19 -0800 Message-ID: <20240216235423.2343167-11-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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. With this change, the stat now looks like below: Annotate data type stats: total 294, ok 185 (62.9%), bad 109 (37.1%) ----------------------------------------------------------- 30 : no_sym 32 : no_mem_ops 27 : no_var 13 : no_typeinfo 7 : bad_offset Signed-off-by: Namhyung Kim --- tools/perf/util/annotate-data.c | 232 ++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index e8e363fed8c2..9dab5cc5c842 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -597,6 +597,231 @@ void update_insn_state(struct type_state *state, struct data_loc_info *dloc, /* Case 4. memory to memory transfers (not handled for now) */ } +/* Prepend this_list to full_list, 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; + + if (last_bb->end != first_bb->begin) { + pr_debug("prepend basic blocks: mismatched disasm line %lx -> %lx\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; + } + + 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, + struct data_loc_info *dloc, int reg, + Dwarf_Die *type_die) +{ + Dwarf_Word size; + + if (state->regs[reg].ok) { + int tag = dwarf_tag(&state->regs[reg].type); + + /* + * 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; + + 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; + + 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; + + 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; + } + + 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; + + 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, 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; + int ret = -1; + + 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; + + src_ip = map__objdump_2rip(dloc->ms->map, start); + + /* Get basic blocks for this scope */ + if (annotate_get_basic_blocks(dloc->ms->sym, src_ip, dst_ip, + &this_blocks) < 0) + 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 */ + 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) { @@ -697,6 +922,13 @@ 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) + goto out; + } + if (loc->multi_regs && reg == loc->reg1 && loc->reg1 != loc->reg2) { reg = loc->reg2; goto retry; From patchwork Fri Feb 16 23:54:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13560929 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 3A7B714E2FA; Fri, 16 Feb 2024 23:54:32 +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=1708127672; cv=none; b=lBehcsa7lNPc885g44idCkkUDCyT/CMToNMKqEQNhGXKNIzF1Ndi06xc9U7Ht3KW94nBxC3stP/0fF5j5ZZL+vXiOqgwhynT62QMtF8XGx5UYdgmg4fjnP6VN/tcac+c9fSOFB44A72S2hJ02t45BLYwYavAffiJg34zAJT2L/s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127672; c=relaxed/simple; bh=hE1QOsjMoRBTV7VH3Rsm9gTxYJbWkglfagXVRxF52QA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=P6zUSR5G6xwuizTs36WrsJtSez6anWSpxk+VxpTQ1wAsvAVTLftOIomYW7H4rLBLUsqa5rUuqyca61DyI1FUvpILIt+9rXqsSU5HXuKChurSgWmViy8VjE/jnl34+YfHWfnBDj2EmPabapEx1Xi9UOnG4piP8j/tL6Nfo1nFKow= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=sFFfU0DK; 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="sFFfU0DK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8E1C5C43601; Fri, 16 Feb 2024 23:54:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127672; bh=hE1QOsjMoRBTV7VH3Rsm9gTxYJbWkglfagXVRxF52QA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sFFfU0DKnsw016crE+V8gx1s8ss9Ik6x5huShitQFcFQ1lI1h/HQMAZ49c7zUA88d o5swo8klCxEgrQOJoTjsuATrV2FYcdHcXjvphKvGdCV0RHPLe8Xo2zngwVDGie5xdv Ek40jcGK4OZYgWZSrmHqCxotFM5i6caEFgQNxOAJwWTo6qkLpoAMrh40DOCBwywMaB UupHxBD3hSChVlL29j7XXDJmJMMd0o4lj7U1RKpIkmXoMzjdBzUNIJgRqVQasAH56h Vgas1hK5ue+aiInad8iHXyvS+Y/O8PncOsf9MyHT4nquTNrP9AkA+h1j09y9DK/L/c q75LuSv/HRdnA== 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/14] perf annotate: Parse x86 segment register location Date: Fri, 16 Feb 2024 15:54:20 -0800 Message-ID: <20240216235423.2343167-12-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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 | 21 +++++++++++++++++++-- tools/perf/util/annotate.h | 13 +++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 89a8d57b1bf7..86ac44c476bf 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3557,6 +3557,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++; @@ -3653,8 +3659,19 @@ 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; + + 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, + NULL, 0); + continue; + } + } + s = strdup(insn_str); if (s) { op_loc->reg1 = get_dwarf_regnum(s, 0); free(s); @@ -3875,7 +3892,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 b460785111a1..2bd654620de3 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -446,6 +446,7 @@ 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 */ @@ -453,6 +454,7 @@ struct annotated_op_loc { int reg1; int reg2; int offset; + u8 segment; bool mem_ref; bool multi_regs; }; @@ -464,6 +466,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 Fri Feb 16 23:54:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13560930 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 25CB614F9EF; Fri, 16 Feb 2024 23:54:32 +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=1708127673; cv=none; b=kCcGgs1eJK1z6au9yGHgAAqzSHUfgNbEQRK1dyFaxUh8mJhOdzdTjsbcasPoTChQjQffc9g9TeVaCPzbmqd1BdmJ01Zv5jNhuM1L5g2CjEaZiPfYeeuG0QIGupj/W0J6Li1vWCnTcQ461q28+URFBBV5Z3/OZ728Swtyrhbd6p4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127673; c=relaxed/simple; bh=7H93tb4nFoxmqjMsy4F0W3n1gdRCYZwiYhvSl0/wg+o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nZDjHrPunQSeG9q/3C8CYiX/HJFLAfra1zikmkaQ+8RdTJjxgGd9KrkP9qe/mW7c+uuP1GHhLlnHLLsMm/cUYabyEnKM6kEbsKg/WaLe3ZvUfGHo+mhJqolZtiR1vkoJ/CcNtJp6ZIxFtLvXqBjge17y8k7MyDUXa6joDtV9FrM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FbGdxWtq; 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="FbGdxWtq" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 36FBDC43330; Fri, 16 Feb 2024 23:54:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127672; bh=7H93tb4nFoxmqjMsy4F0W3n1gdRCYZwiYhvSl0/wg+o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FbGdxWtqka1vUepXIIOKJpZUUEQF1Uh+iaY3+hlzETqCcmxP6BGbwHCIshcPyZFUb xzSTOuJXQrYO7/Ztk+Da3UTt6C93Fe037aE5lryspZh+R6L52VE9jFUhsY/ON83lEQ err2HfGWkSzBYH9wLfxswwyz3rnPiBCOIEhbglSUEh6attWX9Kedvxkj2NrApcUpam Xuaek3p7EIKCg274zuh2LVV26UIGvwtYJolXU1NdZmkJDK+LpSNyE6nSk/b5tFAIka vHdfZNKGzqvR0x/S219pvSC80+1GVprPlDpadUpEqGA4fqz3o22DpIMvpchONw+Yio 8qebJZoODgE4w== 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/14] perf annotate-data: Handle this-cpu variables in kernel Date: Fri, 16 Feb 2024 15:54:21 -0800 Message-ID: <20240216235423.2343167-13-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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. The new get_percpu_var_info() helper is to get information about the 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.c | 31 +++++++++++++++++++++++++++++++ tools/perf/util/annotate.h | 4 ++++ 2 files changed, 35 insertions(+) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 86ac44c476bf..5f3136f57c62 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -3810,6 +3810,27 @@ void get_global_var_info(struct thread *thread, struct map_symbol *ms, u64 ip, addr_location__exit(&al); } +void get_percpu_var_info(struct thread *thread, struct map_symbol *ms, + u8 cpumode, u64 var_addr, const char **var_name, + int *poffset) +{ + struct addr_location al; + struct symbol *var; + u64 map_addr; + + /* Kernel symbols might be relocated */ + map_addr = var_addr + map__reloc(ms->map); + + addr_location__init(&al); + var = thread__find_symbol_fb(thread, cpumode, map_addr, &al); + if (var) { + *var_name = var->name; + /* Calculate type offset from the start of variable */ + *poffset = map_addr - map__unmap_ip(al.map, var->start); + } + addr_location__exit(&al); +} + /** * hist_entry__get_data_type - find data type for given hist entry * @he: hist entry @@ -3906,6 +3927,16 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he) &dloc.type_offset); } + /* This CPU access in kernel - pretend PC-relative addressing */ + if (op_loc->reg1 < 0 && map__dso(ms->map)->kernel && + arch__is(arch, "x86") && op_loc->segment == INSN_SEG_X86_GS) { + dloc.var_addr = op_loc->offset; + get_percpu_var_info(he->thread, ms, he->cpumode, + dloc.var_addr, &dloc.var_name, + &dloc.type_offset); + op_loc->reg1 = DWARF_REG_PC; + } + mem_type = find_data_type(&dloc); if (mem_type) istat->good++; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 2bd654620de3..490134d19c9d 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -513,6 +513,10 @@ void get_global_var_info(struct thread *thread, struct map_symbol *ms, u64 ip, struct disasm_line *dl, u8 cpumode, u64 *var_addr, const char **var_name, int *poffset); +void get_percpu_var_info(struct thread *thread, struct map_symbol *ms, + u8 cpumode, u64 var_addr, const char **var_name, + int *poffset); + /** * struct annotated_basic_block - Basic block of instructions * @list: List node From patchwork Fri Feb 16 23:54:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13560931 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 C57D21509A2; Fri, 16 Feb 2024 23:54:33 +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=1708127673; cv=none; b=aj1Jcmz3MgkWr8VwGCSqsCsUG/4nv/t6q+b2qDRPjnzShnZx5EQmtGHfjferQBwT9mkIUK6atsStYhBfVL03b3btv2gXz3VJ/Ns1DP1yV/Q+cQv8AomU5pxYOkJW6ea+iplLQ+ReJB2XxVAry3NMjIVm9UjO43cWqS/bdDU/xOs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127673; c=relaxed/simple; bh=xWpjopYeC2vvlPkH8zqbdsgUF2q6BBssG2vgYw4CIrc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cnXWbBHYxqL9Mw/a4TyQxGVG9GIi2blHdw/FlJfk9PWBcDAyQ+rFkYyLKHfdRBD8n+SH25voSh5N1TFTa36EtVbZ2imsd9cbm6oj/DSTOY9/e61mU8XwZSOmyGT0Lb/ltSKVjEw+GRPWC38TEEd+XKkb0t/y1P219Juy6WV25Sw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DYxYN2nd; 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="DYxYN2nd" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CE042C433F1; Fri, 16 Feb 2024 23:54:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127673; bh=xWpjopYeC2vvlPkH8zqbdsgUF2q6BBssG2vgYw4CIrc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DYxYN2ndPd2e6Gf1f7hgGodnEOJPQFWR3RVRDfVyd8e89z5sOJEneek0lPeXTu8Yh 01K/5QxquTIrSBLjV/Mxkw7qCzkg+IN+/hFU+mL3BT1rjOo+qUvoYUPE/bbE7Z5HIy 7cEaDoPc4hIGOB2UI3lRzUYKaNrBY5SYx56eVr3Utw269fb52ezqIF0AVbV+NrfApI 0zzorB1Z5HzUmtZf6XuHJ79ciyI4N/o2Qh7i7OC/dLvH2hJBXwpkEuXnL3svlHmDDU TPZgz8OYFDH1Qp2LsnlFsTrz/YppShL1kqoPgNz3+YasKcUyg+v9lez01zNwXxjosd 0wOZwYPYZ6zeQ== 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/14] perf annotate-data: Track instructions with a this-cpu variable Date: Fri, 16 Feb 2024 15:54:22 -0800 Message-ID: <20240216235423.2343167-14-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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 | 84 +++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 9dab5cc5c842..e3af5aec937a 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -410,6 +410,37 @@ void update_var_state(struct type_state *state, struct data_loc_info *dloc, } } +static bool get_global_var_type(Dwarf_Die *cu_die, struct map_symbol *ms, u64 ip, + u64 var_addr, const char *var_name, int var_offset, + Dwarf_Die *type_die) +{ + u64 pc; + int offset = var_offset; + bool is_pointer = false; + Dwarf_Die var_die; + + pc = map__rip_2objdump(ms->map, ip); + + /* Try to get the variable by address first */ + if (die_find_variable_by_addr(cu_die, pc, var_addr, &var_die, &offset) && + check_variable(&var_die, type_die, offset, is_pointer) == 0 && + die_get_member_type(type_die, offset, type_die)) + return true; + + if (var_name == NULL) + return false; + + offset = var_offset; + + /* 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, offset, is_pointer) == 0 && + die_get_member_type(type_die, offset, type_die)) + return true; + + return false; +} + /** * update_insn_state - Update type state for an instruction * @state: type state table @@ -473,14 +504,36 @@ void update_insn_state(struct type_state *state, struct data_loc_info *dloc, 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; if (has_reg_type(state, src->reg1)) state->regs[dst->reg1] = state->regs[src->reg1]; - else + else if (map__dso(dloc->ms->map)->kernel && + src->segment == INSN_SEG_X86_GS) { + struct map_symbol *ms = dloc->ms; + int offset = src->offset; + u64 ip = ms->sym->start + dl->al.offset; + const char *var_name = NULL; + u64 var_addr; + + /* + * 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; + get_percpu_var_info(dloc->thread, ms, dloc->cpumode, + var_addr, &var_name, &offset); + + if (get_global_var_type(cu_die, ms, ip, var_addr, + var_name, offset, &type_die)) { + state->regs[dst->reg1].type = type_die; + state->regs[dst->reg1].ok = true; + } + } else state->regs[dst->reg1].ok = false; } /* Case 2. memory to register transers */ @@ -493,37 +546,20 @@ void update_insn_state(struct type_state *state, struct data_loc_info *dloc, retry: /* Check if it's a global variable */ if (sreg == DWARF_REG_PC) { - Dwarf_Die var_die; struct map_symbol *ms = dloc->ms; int offset = src->offset; u64 ip = ms->sym->start + dl->al.offset; - u64 pc, addr; const char *var_name = NULL; + u64 var_addr; - addr = annotate_calc_pcrel(ms, ip, offset, dl); - pc = map__rip_2objdump(ms->map, ip); - - if (die_find_variable_by_addr(cu_die, pc, addr, - &var_die, &offset) && - check_variable(&var_die, &type_die, offset, - /*is_pointer=*/false) == 0 && - die_get_member_type(&type_die, offset, &type_die)) { - state->regs[dst->reg1].type = type_die; - state->regs[dst->reg1].ok = true; - return; - } + var_addr = annotate_calc_pcrel(ms, ip, offset, dl); - /* Try to get the name of global variable */ - offset = src->offset; get_global_var_info(dloc->thread, ms, ip, dl, - dloc->cpumode, &addr, + dloc->cpumode, &var_addr, &var_name, &offset); - if (var_name && die_find_variable_at(cu_die, var_name, - pc, &var_die) && - check_variable(&var_die, &type_die, offset, - /*is_pointer=*/false) == 0 && - die_get_member_type(&type_die, offset, &type_die)) { + if (get_global_var_type(cu_die, ms, ip, var_addr, + var_name, offset, &type_die)) { state->regs[dst->reg1].type = type_die; state->regs[dst->reg1].ok = true; } else From patchwork Fri Feb 16 23:54:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Namhyung Kim X-Patchwork-Id: 13560932 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 728E3151CD1; Fri, 16 Feb 2024 23:54:34 +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=1708127674; cv=none; b=S6sTxaWOvAsMZpd9DPADPCt27OfcJeiC8yDMci9A90RsjUc/b9xYFrO1wLu2tAHIUtTv47kI4Zyh3s5I7gbwMx3qmRUyo/muy4VMyc+C5A7LAFiLWorCCfEvenOc7hmWPLygCOdLaCBFcKZopqaNWhMs0IT3sG7zAQseBbO44KU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708127674; c=relaxed/simple; bh=JSCVTE9XqiSDlA8ej8yd/v+YYkjMI/c+XOMMHYmpMcI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=N9xMtNa89UjGVftyZh1Pvf2NxyrpZyXmVJDNgODptdDZYiuvI+C0eAtVdHVT/q0Tv33/1zhHvVBSKUCj9UZlm0xAcx7UNKj6yBDJTD2NNOAdnVfEhVY/dHgR2lsjP2Q5x5gXcI0IeGzrQLQ7IMdPIfdfw0A8SMcP3mH6f2ZCWd4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MTAWCSTF; 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="MTAWCSTF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6FEFFC43390; Fri, 16 Feb 2024 23:54:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1708127673; bh=JSCVTE9XqiSDlA8ej8yd/v+YYkjMI/c+XOMMHYmpMcI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MTAWCSTFqFpQXQG/f3joQWMIncRQ5STu7HgSAMGWoppmG7mNaW/7UP7WCaKPO80OP PDAUkm64BEI/oIPTYpSJoVGDwyyqbp3bL/5ImyYfyvOQor5HIqw+JHIjQttryesqM7 ZCnP31OeXbmcxL+hONZqbJ3VcHpNuQM8IBo0Ye/ZqY1tmOis6sJI+sxmlejm0Vfaim RzTuboxDG4k5ez7x38ETDoi/qM4dEjEOi4qu1vcJiS9DVdJQwK45+7pI0XhLYVOpUJ bNzYMjCQCG63xb4Ys6nUYvKaFb6lEbZ2vkdUBmZvGm2xRVW1XRD8tC5Rlq/Wqc7UtW jKFVz3evaBKRA== 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/14] perf annotate-data: Add stack canary type Date: Fri, 16 Feb 2024 15:54:23 -0800 Message-ID: <20240216235423.2343167-15-namhyung@kernel.org> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog In-Reply-To: <20240216235423.2343167-1-namhyung@kernel.org> References: <20240216235423.2343167-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.h | 1 + tools/perf/util/annotate.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index 0bfef29fa52c..e293980eb11b 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -77,6 +77,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 5f3136f57c62..f2683dadf3cf 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -116,6 +116,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; @@ -3764,6 +3771,17 @@ 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->offset == 40) + return true; + } + + return false; +} + u64 annotate_calc_pcrel(struct map_symbol *ms, u64 ip, int offset, struct disasm_line *dl) { @@ -3938,6 +3956,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