From patchwork Thu Jul 19 18:52:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Buettner X-Patchwork-Id: 28489 Received: (qmail 83836 invoked by alias); 19 Jul 2018 18:52:21 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 83823 invoked by uid 89); 19 Jul 2018 18:52:20 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_STOCKGEN, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=sk:overlay, halfway, core_addr, Above X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 19 Jul 2018 18:52:18 +0000 Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8DDAE307D869 for ; Thu, 19 Jul 2018 18:52:17 +0000 (UTC) Received: from pinnacle.lan (ovpn-116-191.phx2.redhat.com [10.3.116.191]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 616DF3001A45 for ; Thu, 19 Jul 2018 18:52:17 +0000 (UTC) Date: Thu, 19 Jul 2018 11:52:16 -0700 From: Kevin Buettner To: gdb-patches@sourceware.org Subject: Re: [PATCH 3/8] Add support for non-contiguous blocks to find_pc_partial_function Message-ID: <20180719115216.6a08ad9a@pinnacle.lan> In-Reply-To: <20180625234703.08a2e8ca@pinnacle.lan> References: <20180625233239.49dc52ea@pinnacle.lan> <20180625234703.08a2e8ca@pinnacle.lan> MIME-Version: 1.0 X-IsSubscribed: yes The description and patch below are intended as a replacement for my original patch. It uses the approach outlined by Simon Marchi for checking the find_pc_partial_function cache. - - - - This change adds an optional output parameter BLOCK to find_pc_partial_function. If BLOCK is non-null, then *BLOCK will be set to the address of the block corresponding to the function symbol if such a symbol was found during lookup. Otherwise it's set to a NULL value. Callers may wish to use the block information to determine whether the block contains any non-contiguous ranges. The caller may also iterate over or examine those ranges. When I first started looking at the broken stepping behavior associated with functions w/ non-contiguous ranges, I found that I could "fix" the problem by disabling the find_pc_partial_function cache. It would sometimes happen that the PC passed in would be between the low and high cache values, but would be in some other function that happens to be placed in between the ranges for the cached function. This caused incorrect values to be returned. So dealing with this cache turns out to be very important for fixing this problem. I explored three different ways of dealing with the cache. My first approach was to clear the cache when a block was encountered with more than one range. This would cause the non-cache pathway to be executed on the next call to find_pc_partial_function. Another approach, which I suspect is slightly faster, checks to see whether the PC is within one of the ranges associated with the cached block. If so, then the cached values can be used. It falls back to the original behavior if there is no cached block. The current approach, suggested by Simon Marchi, is to restrict the low/high pc values recorded for the cache to the beginning and end of the range containing the PC value under consideration. This allows us to retain the simple (and fast) test for determining whether the memoized (cached) values apply to the PC passed to find_pc_partial_function. Another choice that had to be made was whether to have ADDRESS continue to represent the lowest address associated with the function or with the entry pc associated with the function. For the moment, I've decided to keep the current behavior of having it represent the lowest address. In cases where the entry pc is needed, this can be found by passing a non-NULL value for BLOCK which will cause the block (pointer) associated with the function to be returned. BLOCK_ENTRY_PC can then be used on that block to obtain the entry pc. gdb/ChangeLog: * symtab.h (find_pc_partial_function): Add new parameter `block'. * blockframe.c (cache_pc_function_block): New static global. (clear_pc_function_cache): Clear cache_pc_function_block. (find_pc_partial_function): Move comment to symtab.h. Add support for non-contiguous blocks. --- gdb/blockframe.c | 77 ++++++++++++++++++++++++++++++++++++++++---------------- gdb/symtab.h | 20 ++++++++++++--- 2 files changed, 72 insertions(+), 25 deletions(-) diff --git a/gdb/blockframe.c b/gdb/blockframe.c index b3c9aa3..a3b2a11 100644 --- a/gdb/blockframe.c +++ b/gdb/blockframe.c @@ -159,6 +159,7 @@ static CORE_ADDR cache_pc_function_low = 0; static CORE_ADDR cache_pc_function_high = 0; static const char *cache_pc_function_name = 0; static struct obj_section *cache_pc_function_section = NULL; +static const struct block *cache_pc_function_block = nullptr; /* Clear cache, e.g. when symbol table is discarded. */ @@ -169,24 +170,14 @@ clear_pc_function_cache (void) cache_pc_function_high = 0; cache_pc_function_name = (char *) 0; cache_pc_function_section = NULL; + cache_pc_function_block = nullptr; } -/* Finds the "function" (text symbol) that is smaller than PC but - greatest of all of the potential text symbols in SECTION. Sets - *NAME and/or *ADDRESS conditionally if that pointer is non-null. - If ENDADDR is non-null, then set *ENDADDR to be the end of the - function (exclusive), but passing ENDADDR as non-null means that - the function might cause symbols to be read. This function either - succeeds or fails (not halfway succeeds). If it succeeds, it sets - *NAME, *ADDRESS, and *ENDADDR to real information and returns 1. - If it fails, it sets *NAME, *ADDRESS and *ENDADDR to zero and - returns 0. */ - -/* Backward compatibility, no section argument. */ +/* See symtab.h. */ int find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address, - CORE_ADDR *endaddr) + CORE_ADDR *endaddr, const struct block **block) { struct obj_section *section; struct symbol *f; @@ -232,13 +223,37 @@ find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address, f = find_pc_sect_function (mapped_pc, section); if (f != NULL && (msymbol.minsym == NULL - || (BLOCK_START (SYMBOL_BLOCK_VALUE (f)) + || (BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (f)) >= BMSYMBOL_VALUE_ADDRESS (msymbol)))) { - cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f)); - cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f)); + const struct block *b = SYMBOL_BLOCK_VALUE (f); + + if (BLOCK_CONTIGUOUS_P (b)) + { + cache_pc_function_low = BLOCK_START (b); + cache_pc_function_high = BLOCK_END (b); + } + else + { + int i; + for (i = 0; i < BLOCK_NRANGES (b); i++) + { + if (BLOCK_RANGE_START (b, i) <= mapped_pc + && mapped_pc < BLOCK_RANGE_END (b, i)) + { + cache_pc_function_low = BLOCK_RANGE_START (b, i); + cache_pc_function_high = BLOCK_RANGE_END (b, i); + break; + } + } + /* Above loop should exit via the break. */ + gdb_assert (i < BLOCK_NRANGES (b)); + } + cache_pc_function_name = SYMBOL_LINKAGE_NAME (f); cache_pc_function_section = section; + cache_pc_function_block = b; + goto return_cached_value; } } @@ -268,15 +283,33 @@ find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address, cache_pc_function_name = MSYMBOL_LINKAGE_NAME (msymbol.minsym); cache_pc_function_section = section; cache_pc_function_high = minimal_symbol_upper_bound (msymbol); + cache_pc_function_block = nullptr; return_cached_value: + CORE_ADDR f_low, f_high; + + /* The low and high addresses for the cache do not necessarily + correspond to the low and high addresses for the function. + Extract the function low/high addresses from the cached block + if there is one; otherwise use the cached low & high values. */ + if (cache_pc_function_block) + { + f_low = BLOCK_START (cache_pc_function_block); + f_high = BLOCK_END (cache_pc_function_block); + } + else + { + f_low = cache_pc_function_low; + f_high = cache_pc_function_high; + } + if (address) { if (pc_in_unmapped_range (pc, section)) - *address = overlay_unmapped_address (cache_pc_function_low, section); + *address = overlay_unmapped_address (f_low, section); else - *address = cache_pc_function_low; + *address = f_low; } if (name) @@ -291,13 +324,15 @@ find_pc_partial_function (CORE_ADDR pc, const char **name, CORE_ADDR *address, the overlay), we must actually convert (high - 1) and then add one to that. */ - *endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1, - section); + *endaddr = 1 + overlay_unmapped_address (f_high - 1, section); } else - *endaddr = cache_pc_function_high; + *endaddr = f_high; } + if (block) + *block = cache_pc_function_block; + return 1; } diff --git a/gdb/symtab.h b/gdb/symtab.h index 84fc897..e4de868 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -1683,10 +1683,22 @@ extern struct symbol *find_pc_sect_function (CORE_ADDR, struct obj_section *); extern struct symbol *find_symbol_at_address (CORE_ADDR); -/* lookup function from address, return name, start addr and end addr. */ - -extern int find_pc_partial_function (CORE_ADDR, const char **, CORE_ADDR *, - CORE_ADDR *); +/* Finds the "function" (text symbol) that is smaller than PC but + greatest of all of the potential text symbols in SECTION. Sets + *NAME and/or *ADDRESS conditionally if that pointer is non-null. + If ENDADDR is non-null, then set *ENDADDR to be the end of the + function (exclusive). If the optional parameter BLOCK is non-null, + then set *BLOCK to the address of the block corresponding to the + function symbol, if such a symbol could be found during the lookup; + nullptr is used as a return value for *BLOCK if no block is found. + This function either succeeds or fails (not halfway succeeds). If + it succeeds, it sets *NAME, *ADDRESS, and *ENDADDR to real + information and returns 1. If it fails, it sets *NAME, *ADDRESS + and *ENDADDR to zero and returns 0. */ + +extern int find_pc_partial_function (CORE_ADDR pc, const char **name, + CORE_ADDR *address, CORE_ADDR *endaddr, + const struct block **block = nullptr); /* Return the type of a function with its first instruction exactly at the PC address. Return NULL otherwise. */