From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4234 invoked by alias); 8 Oct 2013 11:17:30 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 4218 invoked by uid 89); 8 Oct 2013 11:17:29 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-2.1 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD,SPF_PASS autolearn=ham version=3.3.2 X-HELO: rock.gnat.com Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Tue, 08 Oct 2013 11:17:29 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id A56831166BE for ; Tue, 8 Oct 2013 07:17:47 -0400 (EDT) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id CQqUtDyF8x3p for ; Tue, 8 Oct 2013 07:17:47 -0400 (EDT) Received: from joel.gnat.com (localhost.localdomain [127.0.0.1]) by rock.gnat.com (Postfix) with ESMTP id 33F611166B9 for ; Tue, 8 Oct 2013 07:17:47 -0400 (EDT) Received: by joel.gnat.com (Postfix, from userid 1000) id 7A811E0D55; Tue, 8 Oct 2013 15:17:23 +0400 (RET) From: Joel Brobecker To: gdb-patches@sourceware.org Subject: [commit/Ada] psymbol search failure due to comparison function discrepancy Date: Tue, 08 Oct 2013 11:17:00 -0000 Message-Id: <1381231039-4090-1-git-send-email-brobecker@adacore.com> X-SW-Source: 2013-10/txt/msg00209.txt.bz2 Hello, Upon trying to print the value of a variant record, a user noticed the following problem: (gdb) print rt warning: Unknown upper bound, using 1. warning: Unknown upper bound, using 1. $1 = (a => ((a1 => (4), a2 => (4)), (a1 => (8), a2 => (8)))) The expected output is: (gdb) print rt $1 = (a => ((a1 => (4, 4), a2 => (8, 8)), (a1 => (4, 4), a2 => (8, 8)))) (the number of elements in the "a1", "a2" arrays should be 2, not 1) The problems comes from the fact that components "a1" and "a2" are defined as arrays whose upper bound is dynamic. To determine the value of that upper bound, GDB relies on the GNAT encoding and searches for the parallel ___U variable. Unfortunately, the search fails while doing a binary search inside the partial symtab of the unit where the array and its bound (and therefore the parallel ___U variable) are defined. It fails because partial symbols are sorted using strcmp_iw_ordered, while Ada symbol lookups are performed using a different comparison function (ada-lang.c:compare_names). The two functions are supposed to be compatible, but a change performed in April 2011 modified strcmp_iw_ordered, introducing case-sensitivity issues. As a result, the two functions would now disagree when passed the following two arguments: string1="common__inner_arr___SIZE_A_UNIT" string2="common__inner_arr__T4s___U" The difference starts at "_SIZE_A_UNIT" vs "T4s___U". So, it's mostly a matter of comparing '_' with 'T'. On the one hand, strcmp_iw_ordered would return -1, while compare_names returned 11. The change that made all the difference is that strcmp_iw_ordered now performs a case-insensitive comparison, and only resorts to case-sentitive comparison if the first comparison finds an equality. This changes everything, because while 'T' (84) and 't' (116) are on opposite sides of '_' (95). This patch aims at restoring the compatibility between the two functions, by adding case-sensitivity handling in the Ada comparison function. gdb/ChangeLog: * ada-lang.c (compare_names_with_case): Renamed from compare_names, adding a new parameter "casing" and its handling. New function documentation. (compare_names): New function, implemented using compare_names_with_case. Tested on x86_64-linux. No testcase unfortunately, as the problem is sensitive to symbol names and ordering, and the only reproducer we have has non-contributable code in it. I will commit momentarily. Cheeers, -- Joel --- gdb/ada-lang.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index 1e18129..9ff3ab9 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -4982,23 +4982,37 @@ aux_add_nonlocal_symbols (struct block *block, struct symbol *sym, void *data0) return 0; } -/* Compare STRING1 to STRING2, with results as for strcmp. - Compatible with strcmp_iw in that strcmp_iw (STRING1, STRING2) <= 0 - implies compare_names (STRING1, STRING2) (they may differ as to - what symbols compare equal). */ +/* Implements compare_names, but only applying the comparision using + the given CASING. */ static int -compare_names (const char *string1, const char *string2) +compare_names_with_case (const char *string1, const char *string2, + enum case_sensitivity casing) { while (*string1 != '\0' && *string2 != '\0') { + char c1, c2; + if (isspace (*string1) || isspace (*string2)) return strcmp_iw_ordered (string1, string2); - if (*string1 != *string2) + + if (casing == case_sensitive_off) + { + c1 = tolower (*string1); + c2 = tolower (*string2); + } + else + { + c1 = *string1; + c2 = *string2; + } + if (c1 != c2) break; + string1 += 1; string2 += 1; } + switch (*string1) { case '(': @@ -5016,10 +5030,43 @@ compare_names (const char *string1, const char *string2) if (*string2 == '(') return strcmp_iw_ordered (string1, string2); else - return *string1 - *string2; + { + if (casing == case_sensitive_off) + return tolower (*string1) - tolower (*string2); + else + return *string1 - *string2; + } } } +/* Compare STRING1 to STRING2, with results as for strcmp. + Compatible with strcmp_iw_ordered in that... + + strcmp_iw_ordered (STRING1, STRING2) <= 0 + + ... implies... + + compare_names (STRING1, STRING2) <= 0 + + (they may differ as to what symbols compare equal). */ + +static int +compare_names (const char *string1, const char *string2) +{ + int result; + + /* Similar to what strcmp_iw_ordered does, we need to perform + a case-insensitive comparison first, and only resort to + a second, case-sensitive, comparison if the first one was + not sufficient to differentiate the two strings. */ + + result = compare_names_with_case (string1, string2, case_sensitive_off); + if (result == 0) + result = compare_names_with_case (string1, string2, case_sensitive_on); + + return result; +} + /* Add to OBSTACKP all non-local symbols whose name and domain match NAME and DOMAIN respectively. The search is performed on GLOBAL_BLOCK symbols if GLOBAL is non-zero, or on STATIC_BLOCK symbols otherwise. */ -- 1.8.1.2