* gdb.texinfo (Index Section Format): Change the version to 5.
Describe the different formula.
gdb/
Case insensitive lookups implementation.
* dwarf2read.c: Include ctype.h.
(struct mapped_index): New field version.
(mapped_index_string_hash): New parameter index_version. New comment
for it. Call tolower appropriately.
(find_slot_in_mapped_hash): New variable cmp, initialize it, use it.
Choose the right index version for mapped_index_string_hash.
(dwarf2_read_index): Support also the index version 5. Initialize the
new struct mapped_index field version.
(hash_strtab_entry): Pass INT_MAX for the new parameter, explain why.
(find_slot): Explain the version needs. Pass INT_MAX for the new
parameter.
(write_psymtabs_to_index): Produce version 5.
* minsyms.c (lookup_minimal_symbol): New variable cmp, initialize it,
use it. New comment for SYMBOL_MATCHES_SEARCH_NAME.
* psymtab.c (lookup_partial_symbol): Find the
SYMBOL_MATCHES_SEARCH_NAME start of the found block of matching
entries.
* symtab.c (lookup_symbol_in_language): Remove the case_sensitive_off
NAME lowercasing.
(search_symbols): Pass REG_ICASE to regcomp for case_sensitive_off.
(completion_list_add_name): New variable ncmp, initialize it, use it.
* symtab.h (SYMBOL_HASH_NEXT): Always call tolower.
* utils.c (strcmp_iw): Support case_sensitive_off.
(strcmp_iw_ordered): Sort in a way compatible with case_sensitive_off.
New function comment part. New variables saved_string1,
saved_string2 and case_pass. Add a proper second pass.
gdb/testsuite/
* gdb.base/fortran-sym-case.c: New file.
* gdb.base/fortran-sym-case.exp: New file.
* gdb.dwarf2/dw2-case-insensitive-debug.S: New file.
* gdb.dwarf2/dw2-case-insensitive.c: New file.
* gdb.dwarf2/dw2-case-insensitive.exp: New file.
+2011-04-27 Jan Kratochvil <jan.kratochvil@redhat.com>
+
+ Case insensitive lookups implementation.
+ * dwarf2read.c: Include ctype.h.
+ (struct mapped_index): New field version.
+ (mapped_index_string_hash): New parameter index_version. New comment
+ for it. Call tolower appropriately.
+ (find_slot_in_mapped_hash): New variable cmp, initialize it, use it.
+ Choose the right index version for mapped_index_string_hash.
+ (dwarf2_read_index): Support also the index version 5. Initialize the
+ new struct mapped_index field version.
+ (hash_strtab_entry): Pass INT_MAX for the new parameter, explain why.
+ (find_slot): Explain the version needs. Pass INT_MAX for the new
+ parameter.
+ (write_psymtabs_to_index): Produce version 5.
+ * minsyms.c (lookup_minimal_symbol): New variable cmp, initialize it,
+ use it. New comment for SYMBOL_MATCHES_SEARCH_NAME.
+ * psymtab.c (lookup_partial_symbol): Find the
+ SYMBOL_MATCHES_SEARCH_NAME start of the found block of matching
+ entries.
+ * symtab.c (lookup_symbol_in_language): Remove the case_sensitive_off
+ NAME lowercasing.
+ (search_symbols): Pass REG_ICASE to regcomp for case_sensitive_off.
+ (completion_list_add_name): New variable ncmp, initialize it, use it.
+ * symtab.h (SYMBOL_HASH_NEXT): Always call tolower.
+ * utils.c (strcmp_iw): Support case_sensitive_off.
+ (strcmp_iw_ordered): Sort in a way compatible with case_sensitive_off.
+ New function comment part. New variables saved_string1,
+ saved_string2 and case_pass. Add a proper second pass.
+
2011-04-27 Jan Kratochvil <jan.kratochvil@redhat.com>
Replace re_comp/re_exec by regcomp/regexec.
+2011-04-27 Jan Kratochvil <jan.kratochvil@redhat.com>
+ Eli Zaretskii <eliz@gnu.org>
+
+ * gdb.texinfo (Index Section Format): Change the version to 5.
+ Describe the different formula.
+
2011-04-24 Jan Kratochvil <jan.kratochvil@redhat.com>
Eli Zaretskii <eliz@gnu.org>
@enumerate
@item
-The version number, currently 4. Versions 1, 2 and 3 are obsolete.
+The version number, currently 5. Versions 1, 2 and 3 are obsolete.
+Version 4 differs by its hashing function.
@item
The offset, from the start of the file, of the CU list.
The hash value for a table entry is computed by applying an
iterative hash function to the symbol's name. Starting with an
initial value of @code{r = 0}, each (unsigned) character @samp{c} in
-the string is incorporated into the hash using the formula
-@code{r = r * 67 + c - 113}. The terminating @samp{\0} is not
-incorporated into the hash.
+the string is incorporated into the hash using the formula depending on the
+index version:
+
+@table @asis
+@item Version 4
+The formula is @code{r = r * 67 + c - 113}.
+
+@item Version 5
+The formula is @code{r = r * 67 + tolower (c) - 113}.
+@end table
+
+The terminating @samp{\0} is not incorporated into the hash.
The step size used in the hash table is computed via
@code{((hash * 17) & (size - 1)) | 1}, where @samp{hash} is the hash
a comment by the code that writes the index. */
struct mapped_index
{
+ /* Index data format version. */
+ int version;
+
/* The total length of the buffer. */
off_t total_size;
SYMBOL_HASH_NEXT, but we keep a separate copy to maintain control over the
implementation. This is necessary because the hash function is tied to the
format of the mapped index file. The hash values do not have to match with
- SYMBOL_HASH_NEXT. */
+ SYMBOL_HASH_NEXT.
+
+ Use INT_MAX for INDEX_VERSION if you generate the current index format. */
static hashval_t
-mapped_index_string_hash (const void *p)
+mapped_index_string_hash (int index_version, const void *p)
{
const unsigned char *str = (const unsigned char *) p;
hashval_t r = 0;
unsigned char c;
while ((c = *str++) != 0)
- r = r * 67 + c - 113;
+ {
+ if (index_version >= 5)
+ c = tolower (c);
+ r = r * 67 + c - 113;
+ }
return r;
}
struct cleanup *back_to = make_cleanup (null_cleanup, 0);
offset_type hash;
offset_type slot, step;
+ int (*cmp) (const char *, const char *);
if (current_language->la_language == language_cplus
|| current_language->la_language == language_java
}
}
- hash = mapped_index_string_hash (name);
+ /* Index version 4 did not support case insensitive searches. But the
+ indexes for case insensitive languages are built in lowercase, therefore
+ simulate our NAME being searched is also lowercased. */
+ hash = mapped_index_string_hash ((index->version == 4
+ && case_sensitivity == case_sensitive_off
+ ? 5 : index->version),
+ name);
+
slot = hash & (index->symbol_table_slots - 1);
step = ((hash * 17) & (index->symbol_table_slots - 1)) | 1;
+ cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
for (;;)
{
}
str = index->constant_pool + MAYBE_SWAP (index->symbol_table[i]);
- if (!strcmp (name, str))
+ if (!cmp (name, str))
{
*vec_out = (offset_type *) (index->constant_pool
+ MAYBE_SWAP (index->symbol_table[i + 1]));
/* Versions earlier than 3 emitted every copy of a psymbol. This
causes the index to behave very poorly for certain requests. Version 3
contained incomplete addrmap. So, it seems better to just ignore such
- indices. */
+ indices. Index version 4 uses a different hash function than index
+ version 5 and later. */
if (version < 4)
return 0;
/* Indexes with higher version than the one supported by GDB may be no
longer backward compatible. */
- if (version > 4)
+ if (version > 5)
return 0;
map = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct mapped_index);
+ map->version = version;
map->total_size = dwarf2_per_objfile->gdb_index.size;
metadata = (offset_type *) (addr + sizeof (offset_type));
const char *str;
};
-/* Hash function for a strtab_entry. */
+/* Hash function for a strtab_entry.
+
+ Function is used only during write_hash_table so no index format backward
+ compatibility is needed. */
static hashval_t
hash_strtab_entry (const void *e)
{
const struct strtab_entry *entry = e;
- return mapped_index_string_hash (entry->str);
+ return mapped_index_string_hash (INT_MAX, entry->str);
}
/* Equality function for a strtab_entry. */
}
/* Find a slot in SYMTAB for the symbol NAME. Returns a pointer to
- the slot. */
+ the slot.
+
+ Function is used only during write_hash_table so no index format backward
+ compatibility is needed. */
static struct symtab_index_entry **
find_slot (struct mapped_symtab *symtab, const char *name)
{
- offset_type index, step, hash = mapped_index_string_hash (name);
+ offset_type index, step, hash = mapped_index_string_hash (INT_MAX, name);
index = hash & (symtab->size - 1);
step = ((hash * 17) & (symtab->size - 1)) | 1;
total_len = size_of_contents;
/* The version number. */
- val = MAYBE_SWAP (4);
+ val = MAYBE_SWAP (5);
obstack_grow (&contents, &val, sizeof (val));
/* The offset of the CU list from the start of the file. */
if (pass == 1)
{
- match = strcmp (SYMBOL_LINKAGE_NAME (msymbol),
- modified_name) == 0;
+ int (*cmp) (const char *, const char *);
+
+ cmp = (case_sensitivity == case_sensitive_on
+ ? strcmp : strcasecmp);
+ match = cmp (SYMBOL_LINKAGE_NAME (msymbol),
+ modified_name) == 0;
}
else
{
+ /* The function respects CASE_SENSITIVITY. */
match = SYMBOL_MATCHES_SEARCH_NAME (msymbol,
modified_name);
}
internal_error (__FILE__, __LINE__,
_("failed internal consistency check"));
- while (top <= real_top
- && SYMBOL_MATCHES_SEARCH_NAME (*top, search_name))
+ /* For `case_sensitivity == case_sensitive_off' strcmp_iw_ordered will
+ search more exactly than what matches SYMBOL_MATCHES_SEARCH_NAME. */
+ while (top >= start && SYMBOL_MATCHES_SEARCH_NAME (*top, search_name))
+ top--;
+
+ /* Fixup to have a symbol which matches SYMBOL_MATCHES_SEARCH_NAME. */
+ top++;
+
+ while (top <= real_top && SYMBOL_MATCHES_SEARCH_NAME (*top, search_name))
{
if (symbol_matches_domain (SYMBOL_LANGUAGE (*top),
SYMBOL_DOMAIN (*top), domain))
}
}
- if (case_sensitivity == case_sensitive_off)
- {
- char *copy;
- int len, i;
-
- len = strlen (name);
- copy = (char *) alloca (len + 1);
- for (i= 0; i < len; i++)
- copy[i] = tolower (name[i]);
- copy[len] = 0;
- modified_name = copy;
- }
-
returnval = lookup_symbol_aux (modified_name, block, domain, lang,
is_a_field_of_this);
do_cleanups (cleanup);
}
}
- errcode = regcomp (&datum.preg, regexp, REG_NOSUB);
+ errcode = regcomp (&datum.preg, regexp,
+ REG_NOSUB | (case_sensitivity == case_sensitive_off
+ ? REG_ICASE : 0));
if (errcode != 0)
{
char *err = get_regcomp_error (errcode, &datum.preg);
char *text, char *word)
{
int newsize;
+ int (*ncmp) (const char *, const char *, size_t);
+
+ ncmp = (case_sensitivity == case_sensitive_on ? strncmp : strncasecmp);
/* Clip symbols that cannot match. */
- if (strncmp (symname, sym_text, sym_text_len) != 0)
+ if (ncmp (symname, sym_text, sym_text_len) != 0)
{
return;
}
is only a GDB in-memory computed value with no external files compatibility
requirements. */
-#define SYMBOL_HASH_NEXT(hash, c) ((hash) * 67 + (c) - 113)
+#define SYMBOL_HASH_NEXT(hash, c) \
+ ((hash) * 67 + tolower ((unsigned char) (c)) - 113)
extern struct objfile * msymbol_objfile (struct minimal_symbol *sym);
+2011-04-27 Jan Kratochvil <jan.kratochvil@redhat.com>
+
+ * gdb.base/fortran-sym-case.c: New file.
+ * gdb.base/fortran-sym-case.exp: New file.
+ * gdb.dwarf2/dw2-case-insensitive-debug.S: New file.
+ * gdb.dwarf2/dw2-case-insensitive.c: New file.
+ * gdb.dwarf2/dw2-case-insensitive.exp: New file.
+
2011-04-27 Jan Kratochvil <jan.kratochvil@redhat.com>
* lib/gdb.exp (gdb_test_multiple): Eror on newline in $message.
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 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 <http://www.gnu.org/licenses/>. */
+
+int
+main (int argc, char **aRGv)
+{
+ return 0;
+}
--- /dev/null
+# Copyright (C) 2011 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 <http://www.gnu.org/licenses/>.
+
+set testfile fortran-sym-case
+if { [prepare_for_testing ${testfile}.exp ${testfile}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+gdb_test "set language fortran" {Warning: the current language does not match this frame\.}
+
+gdb_test "frame" ", aRGv=.*"
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 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 <http://www.gnu.org/licenses/>. */
+
+ .section .debug_info
+.Lcu1_begin:
+ /* CU header */
+ .4byte .Lcu1_end - .Lcu1_start /* Length of Compilation Unit */
+.Lcu1_start:
+ .2byte 2 /* DWARF Version */
+ .4byte .Labbrev1_begin /* Offset into abbrev section */
+ .byte 4 /* Pointer size */
+
+ /* CU die */
+ .uleb128 1 /* Abbrev: DW_TAG_compile_unit */
+ .ascii "file1.txt\0" /* DW_AT_name */
+ .ascii "GNU C 3.3.3\0" /* DW_AT_producer */
+ .byte 8 /* DW_AT_language (DW_LANG_Fortran90) */
+ .4byte FUNC_lang /* DW_AT_low_pc */
+ .4byte main /* DW_AT_high_pc */
+
+ .uleb128 3 /* Abbrev: DW_TAG_subprogram */
+ .byte 1 /* DW_AT_external */
+ .ascii "FUNC_lang\0" /* DW_AT_name */
+ .4byte FUNC_lang /* DW_AT_low_pc */
+ .4byte main /* DW_AT_high_pc */
+ .byte 1 /* DW_AT_prototyped */
+ .4byte .Ltype - .Lcu1_begin /* DW_AT_type */
+
+.Ltype:
+ .uleb128 0x5 /* Abbrev: DW_TAG_base_type */
+ .byte 0x4 /* DW_AT_byte_size */
+ .byte 0x5 /* DW_AT_encoding */
+ .ascii "foo\0" /* DW_AT_name */
+
+ .byte 0 /* End of children of CU */
+.Lcu1_end:
+
+/* Abbrev table */
+ .section .debug_abbrev
+.Labbrev1_begin:
+ .uleb128 1 /* Abbrev code */
+ .uleb128 0x11 /* DW_TAG_compile_unit */
+ .byte 1 /* has_children */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x25 /* DW_AT_producer */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x13 /* DW_AT_language */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 3 /* Abbrev code */
+ .uleb128 0x2e /* DW_TAG_subprogram */
+ .byte 0 /* has_children */
+ .uleb128 0x3f /* DW_AT_external */
+ .uleb128 0xc /* DW_FORM_flag */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .uleb128 0x11 /* DW_AT_low_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x12 /* DW_AT_high_pc */
+ .uleb128 0x1 /* DW_FORM_addr */
+ .uleb128 0x27 /* DW_AT_prototyped */
+ .uleb128 0xc /* DW_FORM_flag */
+ .uleb128 0x49 /* DW_AT_type */
+ .uleb128 0x13 /* DW_FORM_ref4 */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .uleb128 0x5 /* Abbrev code */
+ .uleb128 0x24 /* DW_TAG_base_type */
+ .byte 0x0 /* DW_children_no */
+ .uleb128 0xb /* DW_AT_byte_size */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3e /* DW_AT_encoding */
+ .uleb128 0xb /* DW_FORM_data1 */
+ .uleb128 0x3 /* DW_AT_name */
+ .uleb128 0x8 /* DW_FORM_string */
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
+
+ .byte 0x0 /* Terminator */
+ .byte 0x0 /* Terminator */
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 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 <http://www.gnu.org/licenses/>. */
+
+/* Use DW_LANG_Fortran90 for case insensitive DWARF. */
+
+void
+FUNC_lang (void)
+{
+}
+
+/* Symbol is present only in ELF .symtab. */
+
+void
+FUNC_symtab (void)
+{
+}
+
+int
+main (void)
+{
+ FUNC_lang ();
+ FUNC_symtab ();
+ return 0;
+}
--- /dev/null
+# Copyright 2011 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 <http://www.gnu.org/licenses/>.
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+ return 0
+}
+
+set testfile "dw2-case-insensitive"
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} [list ${testfile}.c ${testfile}-debug.S] {nodebug}] } {
+ return -1
+}
+
+gdb_test "show case-sensitive" {Case sensitivity in name search is "auto; currently on"\.}
+
+gdb_test "info functions fUnC_lang" \
+ "All functions matching regular expression \"fUnC_lang\":" \
+ "regexp case-sensitive on"
+
+gdb_test "set case-sensitive off" {warning: the current case sensitivity setting does not match the language\.}
+
+gdb_test "info functions fUnC_lang" \
+ "All functions matching regular expression \"fUnC_lang\":\[\r\n\]+File file1.txt:\r\nfoo FUNC_lang\\(void\\);" \
+ "regexp case-sensitive off"
+
+gdb_test "p fuNC_lang" { = {foo \(void\)} 0x[0-9a-f]+ <FUNC_lang>}
+gdb_test "p fuNC_symtab" { = {<text variable, no debug info>} 0x[0-9a-f]+ <FUNC_symtab>}
+
+if {[gdb_breakpoint "fuNC_lang"] == 1} {
+ pass "setting breakpoint at fuNC_lang"
+}
+
+if {[gdb_breakpoint "fuNC_symtab"] == 1} {
+ pass "setting breakpoint at fuNC_symtab"
+}
{
string2++;
}
- if (*string1 != *string2)
- {
- break;
- }
+ if (case_sensitivity == case_sensitive_on && *string1 != *string2)
+ break;
+ if (case_sensitivity == case_sensitive_off
+ && (tolower ((unsigned char) *string1)
+ != tolower ((unsigned char) *string2)))
+ break;
if (*string1 != '\0')
{
string1++;
strcmp_iw(LIST_ELT, NAME), then the place to start looking is right
where this function would put NAME.
+ This function must be neutral to the CASE_SENSITIVITY setting as the user
+ may choose it during later lookup. Therefore this function always sorts
+ primarily case-insensitively and secondarily case-sensitively.
+
Here are some examples of why using strcmp to sort is a bad idea:
Whitespace example:
int
strcmp_iw_ordered (const char *string1, const char *string2)
{
- /* Formatting stub. */
- if (1)
+ const char *saved_string1 = string1, *saved_string2 = string2;
+ enum case_sensitivity case_pass = case_sensitive_off;
+
+ for (;;)
{
/* C1 and C2 are valid only if *string1 != '\0' && *string2 != '\0'.
Provide stub characters if we are already at the end of one of the
while (isspace (*string2))
string2++;
+ switch (case_pass)
+ {
+ case case_sensitive_off:
+ c1 = tolower ((unsigned char) *string1);
+ c2 = tolower ((unsigned char) *string2);
+ break;
+ case case_sensitive_on:
c1 = *string1;
c2 = *string2;
+ break;
+ }
if (c1 != c2)
break;
comparison in the cases where one of them is '\0' or '('. */
case '\0':
if (*string2 == '\0')
- return 0;
+ break;
else
return -1;
case '(':
default:
if (*string2 == '\0' || *string2 == '(')
return 1;
- else
- return c1 - c2;
+ else if (c1 > c2)
+ return 1;
+ else if (c1 < c2)
+ return -1;
+ /* PASSTHRU */
}
+
+ if (case_pass == case_sensitive_on)
+ return 0;
+
+ /* Otherwise the strings were equal in case insensitive way, make
+ a more fine grained comparison in a case sensitive way. */
+
+ case_pass = case_sensitive_on;
+ string1 = saved_string1;
+ string2 = saved_string2;
}
}