From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id qykeFnrvtGCBOgAAWB0awg (envelope-from ) for ; Mon, 31 May 2021 10:15:22 -0400 Received: by simark.ca (Postfix, from userid 112) id 521B01F163; Mon, 31 May 2021 10:15:22 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-0.7 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,RDNS_DYNAMIC,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id F19DB1E940 for ; Mon, 31 May 2021 10:15:20 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 933043898532; Mon, 31 May 2021 14:15:20 +0000 (GMT) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by sourceware.org (Postfix) with ESMTPS id 4B07F3848018 for ; Mon, 31 May 2021 14:15:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 4B07F3848018 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tdevries@suse.de Received: from imap.suse.de (imap-alt.suse-dmz.suse.de [192.168.254.47]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 3752C21914 for ; Mon, 31 May 2021 14:15:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1622470516; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version:content-type:content-type; bh=rhBp1yODfSVJnSaybt+EOlgqRCH/OwqdHqVafPr+Xmc=; b=Rhu3J4SInfL2p3+j2oMwNW+msHSmsV4X/qe5Hx2GMZYqUP0Whgk6aSbPIXXFvDXCGrNEiS csrO7NHb/VoWk8n9hj5iUzj8YcFrBrGIpVXsbiDzwU0jBoPhtprF3UI5pFBwKU4ou7JToz wlaXwxpM3ey5sMzRO/dlfG2lelIolQQ= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1622470516; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version:content-type:content-type; bh=rhBp1yODfSVJnSaybt+EOlgqRCH/OwqdHqVafPr+Xmc=; b=w4yj3PG5/Ul5/7tGnMxwBLhXBnL+qrnUeV6FRsuiSvvvWQ5SAV4BvStsmcB/fQppzSLRVB /qVfDilz6ED1dmDQ== Received: from imap3-int (imap-alt.suse-dmz.suse.de [192.168.254.47]) by imap.suse.de (Postfix) with ESMTP id A2552118DD for ; Mon, 31 May 2021 14:15:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1622470515; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version:content-type:content-type; bh=rhBp1yODfSVJnSaybt+EOlgqRCH/OwqdHqVafPr+Xmc=; b=eUOAuOazsDrLxmLifJiqv2FXAshaqeAX0+fz02NJLnUsdwsr1P82RrKcD0bn1nCbsxXeo1 GJiB5vESHWp3uXH6+4SJ6ndiKf6DG8ReQxP1/89E8bt6d/iRbY8N3Oiunwmy7OLje8VVdA r8h3kaCgf4cvW3tkJA8F5FD3cqftW9E= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1622470515; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version:content-type:content-type; bh=rhBp1yODfSVJnSaybt+EOlgqRCH/OwqdHqVafPr+Xmc=; b=nvYCjFfkUZvGisWk5/rLJoJtXE//NCwQcarXVf18PfPjkNuoMsZvwkO1b8X6G6lsZ9DzXI A1zE12PJMohBEZBA== Received: from director2.suse.de ([192.168.254.72]) by imap3-int with ESMTPSA id zcPsJXPvtGDxdQAALh3uQQ (envelope-from ) for ; Mon, 31 May 2021 14:15:15 +0000 Date: Mon, 31 May 2021 16:15:14 +0200 From: Tom de Vries To: gdb-patches@sourceware.org Subject: [PATCH][gdb/symtab] Ignore cold clones Message-ID: <20210531141512.GA3181@delia> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) Authentication-Results: imap.suse.de; none X-Spamd-Result: default: False [-0.50 / 100.00]; ARC_NA(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; FROM_HAS_DN(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; MIME_GOOD(-0.10)[text/plain]; TO_DN_NONE(0.00)[]; PREVIOUSLY_DELIVERED(0.00)[gdb-patches@sourceware.org]; RCPT_COUNT_ONE(0.00)[1]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; NEURAL_HAM_SHORT(-1.00)[-1.000]; RCVD_NO_TLS_LAST(0.10)[]; FROM_EQ_ENVFROM(0.00)[]; MIME_TRACE(0.00)[0:+]; MID_RHS_NOT_FQDN(0.50)[]; RCVD_COUNT_TWO(0.00)[2] X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" Hi, Consider the test-case contained in this patch, compiled for c using gcc-10: ... $ gcc-10 -x c src/gdb/testsuite/gdb.cp/cold-clone.cc -O2 -g -Wall -Wextra ... When setting a breakpoint on foo, we get one breakpoint location: ... $ gdb -q -batch a.out -ex "b foo" Breakpoint 1 at 0x400560: file cold-clone.cc, line 28. ... However, when we compile for c++ instead, we get two breakpoint locations: ... $ gdb -q -batch a.out -ex "b foo" -ex "info break" Breakpoint 1 at 0x400430: foo. (2 locations) Num Type Disp Enb Address What 1 breakpoint keep y 1.1 y 0x0000000000400430 in foo() at cold-clone.cc:30 1.2 y 0x0000000000400560 in foo() at cold-clone.cc:28 ... The additional breakpoint location at 0x400430 corresponds to the cold clone: ... $ nm a.out | grep foo 0000000000400560 t _ZL3foov 0000000000400430 t _ZL3foov.cold ... which demangled looks like this: ... $ nm -C a.out | grep foo 0000000000400560 t foo() 0000000000400430 t foo() [clone .cold] ... [ Or, in the case of the cc1 mentioned in PR23710: ... $ nm cc1 | grep do_rpo_vn.*cold 000000000058659d t \ _ZL9do_rpo_vnP8functionP8edge_defP11bitmap_headbb.cold.138 $ nm -C cc1 | grep do_rpo_vn.*cold 000000000058659d t \ do_rpo_vn(function*, edge_def*, bitmap_head*, bool, bool) [clone .cold.138] ... ] The cold clone is a part of the function that is split off from the rest of the function because it's considered cold (not frequently executed). So while the symbol points to code that is part of a function, it doesn't point to a function entry, so the desirable behaviour for "break foo" is to ignore this symbol. When compiling for c, the symbol "foo.cold" is entered as minimal symbol with the search name "foo.cold", and the lookup using "foo" fails to find that symbol. But when compiling for c++, the symbol "foo.cold" is entered as minimal symbol with both the mangled and demangled name, and for the demangled name "foo() [clone .cold]" we get the search name "foo" (because cp_search_name_hash stops hashing at '('), and the lookup using "foo" succeeds. Fix this by recognizing the cold clone suffix and returning false for such a minimal symbol in msymbol_is_function. Tested on x86_64-linux. Any comments? Thanks, - Tom [gdb/symtab] Ignore cold clones gdb/ChangeLog: 2021-05-31 Tom de Vries PR symtab/26096 * minsyms.c (msymbol_is_cold_clone): New function. (msymbol_is_function): Use msymbol_is_cold_clone. gdb/testsuite/ChangeLog: 2021-05-31 Tom de Vries PR symtab/26096 * gdb.cp/cold-clone.cc: New test. * gdb.cp/cold-clone.exp: New file. --- gdb/minsyms.c | 52 +++++++++++++++++++++++++++++++++++ gdb/testsuite/gdb.cp/cold-clone.cc | 54 +++++++++++++++++++++++++++++++++++++ gdb/testsuite/gdb.cp/cold-clone.exp | 30 +++++++++++++++++++++ 3 files changed, 136 insertions(+) diff --git a/gdb/minsyms.c b/gdb/minsyms.c index 8ffd9076124..80c3d431209 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -60,6 +60,53 @@ #include #endif +/* Return true if MINSYM is a cold clone symbol. + Recognize f.i. these symbols (mangled/demangled): + - _ZL3foov.cold + foo() [clone .cold] + - _ZL9do_rpo_vnP8functionP8edge_defP11bitmap_headbb.cold.138 + do_rpo_vn(function*, edge_def*, bitmap_head*, bool, bool) \ + [clone .cold.138]. */ + +static bool +msymbol_is_cold_clone (minimal_symbol *minsym) +{ + const char *name = minsym->natural_name (); + size_t name_len = strlen (name); + if (name_len < 1) + return false; + + const char *last = &name[name_len - 1]; + if (*last != ']') + return false; + + const char *suffix = " [clone .cold"; + size_t suffix_len = strlen (suffix); + const char *found = strstr (name, suffix); + if (found == nullptr) + return false; + + const char *start = &found[suffix_len]; + if (*start == ']') + return true; + + if (*start != '.') + return false; + + const char *p; + for (p = start + 1; p <= last; ++p) + { + if (*p >= '0' && *p <= '9') + continue; + break; + } + + if (p == last) + return true; + + return false; +} + /* See minsyms.h. */ bool @@ -89,6 +136,11 @@ msymbol_is_function (struct objfile *objfile, minimal_symbol *minsym, } return false; } + case mst_file_text: + /* Ignore function symbol that is not a function entry. */ + if (msymbol_is_cold_clone (minsym)) + return false; + /* fallthru */ default: if (func_address_p != NULL) *func_address_p = msym_addr; diff --git a/gdb/testsuite/gdb.cp/cold-clone.cc b/gdb/testsuite/gdb.cp/cold-clone.cc new file mode 100644 index 00000000000..233a84a7ee7 --- /dev/null +++ b/gdb/testsuite/gdb.cp/cold-clone.cc @@ -0,0 +1,54 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include "../lib/attributes.h" + +int a; +int b; +int c; + +static int __attribute__((used, noinline)) ATTRIBUTE_NOCLONE +foo (void) +{ + a = 2; + if (b) + abort (); + + return c; +} + +static int __attribute__((used, noinline)) ATTRIBUTE_NOCLONE +bar (void) +{ + a = 1; + if (c) + abort (); + return b; +} + +int +main (int argc, char **argv __attribute__((unused))) +{ + b = argc * 2; + c = argc / 2; + + if (b + c == 5) + abort (); + + return foo () + bar (); +} diff --git a/gdb/testsuite/gdb.cp/cold-clone.exp b/gdb/testsuite/gdb.cp/cold-clone.exp new file mode 100644 index 00000000000..07b9bdc0a93 --- /dev/null +++ b/gdb/testsuite/gdb.cp/cold-clone.exp @@ -0,0 +1,30 @@ +# Copyright 2021 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +standard_testfile .cc + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile \ + {debug c++ optimize=-O2}]} { + return -1 +} + +gdb_test_multiple "break foo" "" { + -re -wrap "\\($decimal locations\\)" { + fail $gdb_test_name + } + -re -wrap "" { + pass $gdb_test_name + } +}