From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 129623 invoked by alias); 18 Jul 2015 18:32: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 129608 invoked by uid 89); 18 Jul 2015 18:32:29 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.2 required=5.0 tests=AWL,BAYES_50,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,KAM_STOCKGEN,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=no version=3.3.2 X-HELO: mail-pd0-f169.google.com Received: from mail-pd0-f169.google.com (HELO mail-pd0-f169.google.com) (209.85.192.169) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Sat, 18 Jul 2015 18:32:26 +0000 Received: by pdbbh15 with SMTP id bh15so33592801pdb.1 for ; Sat, 18 Jul 2015 11:32:24 -0700 (PDT) X-Received: by 10.66.102.103 with SMTP id fn7mr42023929pab.85.1437244344273; Sat, 18 Jul 2015 11:32:24 -0700 (PDT) Received: from seba.sebabeach.org.gmail.com (173-13-178-53-sfba.hfc.comcastbusiness.net. [173.13.178.53]) by smtp.gmail.com with ESMTPSA id xv9sm15000708pbc.2.2015.07.18.11.32.22 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 18 Jul 2015 11:32:22 -0700 (PDT) From: Doug Evans To: Iain Buclaw Cc: gdb-patches@sourceware.org Subject: Re: [PATCH] D: Support looking up symbols in the current and imported modules References: Date: Sat, 18 Jul 2015 18:32:00 -0000 In-Reply-To: (Iain Buclaw's message of "Tue, 14 Jul 2015 11:04:51 +0200") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-IsSubscribed: yes X-SW-Source: 2015-07/txt/msg00539.txt.bz2 Iain Buclaw writes: > Hi, > > D has the notion of importing modules, whether it is public, private, > or static; basic, selective, or renamed. > > This adds support for looking up symbols in both the current and > imported modules so that it is not a necessity to use the qualified > name every time. > > Example: > > module A; > > import B; // Basic import > import R = C; // Renamed import > import D : funD; // Selective import > import E : funR = funE; // Renamed selective import > > void funA() > { > // <- Breakpoint here > } > > From the given breakpoint, the following should work in: > - All symbols in module 'A' (our current module) can be looked up by name. > - All symbols in module 'B' can be looked up by name. > - All symbols in module 'C' can be looked up through it's alias R.name. > - Only 'funD' in module 'D' can be looked up by name. > - Only 'funE' in module 'E' can be looked up through it's alias 'funR'. > - All fully qualified symbol names can be looked up. > > > The implementation of this itself is mostly borrowed from > cp-namespace.c, but differs in the follow ways: > - The separator for modules is a single dot '.' > - Renamed selective imports need special handling for D. > > > This has a dependency on dwarf2read.c being able to handle language_d > when reading/parsing module/imported declaration symbols, which has > been raised as a separate patch. > > Regards > Iain > > --- > 2015-07-14 Iain Buclaw > > * Makefile.in (SFILES): Add d-namespace.c. > (COMMON_OBS): Add d-namespace.o. > * d-lang.c (d_language_defn): Use d_lookup_symbol_nonlocal as the > la_lookup_symbol_nonlocal callback function pointer. > * d-lang.h (d_lookup_symbol_nonlocal): New declaration. > (d_lookup_nested_symbol): New declaration. > * d-namespace.c: New file. Hi. I didn't study this too much for d-language correctness. [If there are issues I'm happy to let them get addressed in subsequent patches.] LGTM with the nits below fixed. > > --- a/gdb/Makefile.in > +++ b/gdb/Makefile.in > @@ -835,7 +835,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ > charset.c common/cleanups.c cli-out.c coffread.c coff-pe-read.c \ > complaints.c completer.c continuations.c corefile.c corelow.c \ > cp-abi.c cp-support.c cp-namespace.c cp-valprint.c \ > - d-exp.y d-lang.c d-valprint.c \ > + d-exp.y d-lang.c d-namespace.c d-valprint.c \ > cp-name-parser.y \ > dbxread.c demangle.c dictionary.c disasm.c doublest.c \ > dtrace-probe.c dummy-frame.c \ > @@ -1070,7 +1070,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ > frame-base.o \ > inline-frame.o \ > gnu-v2-abi.o gnu-v3-abi.o cp-abi.o cp-support.o \ > - cp-namespace.o \ > + cp-namespace.o d-namespace.o \ > reggroups.o \ > trad-frame.o \ > tramp-frame.o \ > --- a/gdb/d-lang.c > +++ b/gdb/d-lang.c > @@ -214,7 +214,7 @@ static const struct language_defn d_language_defn = > default_read_var_value, /* la_read_var_value */ > NULL, /* Language specific skip_trampoline. */ > "this", > - basic_lookup_symbol_nonlocal, > + d_lookup_symbol_nonlocal, > basic_lookup_transparent_type, > d_demangle, /* Language specific symbol demangler. */ > NULL, /* Language specific > --- a/gdb/d-lang.h > +++ b/gdb/d-lang.h > @@ -68,6 +68,16 @@ extern char *d_demangle (const char *mangled, int options); > > extern const struct builtin_d_type *builtin_d_type (struct gdbarch *); > > +/* Defined in d-namespace.c */ > + > +extern struct symbol *d_lookup_symbol_nonlocal (const struct language_defn *, > + const char *, > + const struct block *, > + const domain_enum); > + > +extern struct symbol *d_lookup_nested_symbol (struct type *, const char *, > + const struct block *); > + > /* Defined in d-valprint.c */ > > extern void d_val_print (struct type *type, const gdb_byte *valaddr, > --- /dev/null > +++ b/gdb/d-namespace.c > @@ -0,0 +1,574 @@ > +/* Helper routines for D support in GDB. > + > + Copyright (C) 2014-2015 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + 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 "defs.h" > +#include "symtab.h" > +#include "block.h" > +#include "language.h" > +#include "d-lang.h" > +#include "cp-support.h" Is including cp-support.h necessary? > +#include "gdb_obstack.h" > + > +static struct symbol *lookup_module_scope (const char *, > + const struct block *, > + const domain_enum, > + const char *, int); > + > +static struct symbol *lookup_symbol_file (const char *, > + const struct block *, > + const domain_enum, int); > + > + > +/* This returns the length of first component of NAME, which should be > + the demangled name of a D variable/function/method/etc. > + Specifically, it returns the index of the first dot forming the > + boundary of the first component: so, given 'A.foo' or 'A.B.foo' > + it returns the 1, and given 'foo', it returns 0. */ > + > +/* The character in NAME indexed by the return value is guaranteed to > + always be either '.' or '\0'. */ > + > +static unsigned int > +d_find_first_component (const char *name) > +{ > + unsigned int index = 0; > + > + for (;; ++index) > + { > + if (name[index] == '.' || name[index] == '\0') > + return index; > + } > +} > + > +/* Look up NAME in the D module MODULE. Other arguments are as in > + d_lookup_symbol_nonlocal. If SEARCH is non-zero, search through > + base classes for a matching symbol. */ > + > +static struct symbol * > +d_lookup_symbol_in_module (const char *module, const char *name, > + const struct block *block, > + const domain_enum domain, int search) > +{ > + if (module[0] == '\0') > + { > + return lookup_symbol_file (name, block, domain, search); > + } > + else > + { > + char *concatenated_name = alloca (strlen (module) > + + strlen (name) + 2); > + > + strcpy (concatenated_name, module); > + strcat (concatenated_name, "."); > + strcat (concatenated_name, name); > + return lookup_symbol_file (concatenated_name, block, > + domain, search); > + } > +} > + > +/* Lookup NAME at module scope. SCOPE is the module that the current > + function is defined within; only consider modules whose length is at > + least SCOPE_LEN. Other arguments are as in d_lookup_symbol_nonlocal. > + > + For example, if we're within a function A.B.f and looking for a > + symbol x, this will get called with NAME = "x", SCOPE = "A.B", and > + SCOPE_LEN = 0. It then calls itself with NAME and SCOPE the same, > + but with SCOPE_LEN = 1. And then it calls itself with NAME and > + SCOPE the same, but with SCOPE_LEN = 4. This third call looks for > + "A.B.x"; if it doesn't find it, then the second call looks for "A.x", > + and if that call fails, then the first call looks for "x". */ > + > +static struct symbol * > +lookup_module_scope (const char *name, const struct block *block, > + const domain_enum domain, const char *scope, > + int scope_len) > +{ > + char *module; > + > + if (scope[scope_len] != '\0') > + { > + /* Recursively search for names in child modules first. */ > + > + struct symbol *sym; > + int new_scope_len = scope_len; > + > + /* If the current scope is followed by ".", skip past that. */ > + if (new_scope_len != 0) > + { > + gdb_assert (scope[new_scope_len] == '.'); > + new_scope_len++; > + } > + new_scope_len += d_find_first_component (scope + new_scope_len); > + sym = lookup_module_scope (name, block, domain, > + scope, new_scope_len); > + if (sym != NULL) > + return sym; > + } > + > + /* Okay, we didn't find a match in our children, so look for the > + name in the current module. */ > + > + module = alloca (scope_len + 1); > + strncpy (module, scope, scope_len); > + module[scope_len] = '\0'; > + return d_lookup_symbol_in_module (module, name, > + block, domain, 1); > +} > + > +/* If NAME is the fully-qualified name of a D function/variable/method, > + this returns the length of its entire prefix: all of the modules and > + classes that make up its name. Given 'A.foo', it returns 1, given > + 'A.B.foo', it returns 4, given 'foo', it returns 0. */ > + > +static unsigned int > +d_entire_prefix_len (const char *name) > +{ > + unsigned int current_len = d_find_first_component (name); > + unsigned int previous_len = 0; > + > + while (name[current_len] != '\0') > + { > + gdb_assert (name[current_len] == '.'); > + previous_len = current_len; > + /* Skip the '.' */ > + current_len++; > + current_len += d_find_first_component (name + current_len); > + } > + > + return previous_len; > +} > + > +/* Search through the base classes of PARENT_TYPE for a symbol named > + NAME in block BLOCK. */ > + > +static struct symbol * > +find_symbol_in_baseclass (struct type *parent_type, const char *name, > + const struct block *block) > +{ > + int i; > + struct symbol *sym; > + struct cleanup *cleanup; > + char *concatenated_name; > + > + sym = NULL; > + concatenated_name = NULL; > + cleanup = make_cleanup (free_current_contents, &concatenated_name); > + for (i = 0; i < TYPE_N_BASECLASSES (parent_type); ++i) > + { > + size_t len; > + struct type *base_type = TYPE_BASECLASS (parent_type, i); > + const char *base_name = TYPE_BASECLASS_NAME (parent_type, i); > + > + if (base_name == NULL) > + continue; > + > + /* Search this particular base class. */ > + sym = d_lookup_symbol_in_module (base_name, name, block, > + VAR_DOMAIN, 0); > + if (sym != NULL) > + break; > + > + /* Now search all static file-level symbols. We have to do this for > + things like typedefs in the class. First search in this symtab, > + what we want is possibly there. */ > + len = strlen (base_name) + strlen (name) + 2; > + concatenated_name = xrealloc (concatenated_name, len); > + xsnprintf (concatenated_name, len, "%s.%s", base_name, name); > + sym = lookup_symbol_in_static_block (concatenated_name, block, > + VAR_DOMAIN); > + if (sym != NULL) > + break; > + > + /* Nope. We now have to search all static blocks in all objfiles, > + even if block != NULL, because there's no guarantees as to which > + symtab the symbol we want is in. */ > + sym = lookup_static_symbol (concatenated_name, VAR_DOMAIN); > + if (sym != NULL) > + break; > + > + /* If this class has base classes, search them next. */ > + base_type = check_typedef (base_type); > + if (TYPE_N_BASECLASSES (base_type) > 0) > + { > + sym = find_symbol_in_baseclass (base_type, name, block); > + if (sym != NULL) > + break; > + } > + } > + > + do_cleanups (cleanup); > + return sym; > +} > + > +/* Look up a symbol named NESTED_NAME that is nested inside the D > + class or module given by PARENT_TYPE, from within the context > + given by BLOCK. Return NULL if there is no such nested type. */ > + > +struct symbol * Make static. [Or is there another patch that will use this function? E.g., c-exp.y also uses cp_lookup_nested_symbol.] > +d_lookup_nested_symbol (struct type *parent_type, > + const char *nested_name, > + const struct block *block) > +{ > + /* type_name_no_tag_required provides better error reporting using the > + original type. */ > + struct type *saved_parent_type = parent_type; > + > + parent_type = check_typedef (parent_type); > + > + switch (TYPE_CODE (parent_type)) > + { > + case TYPE_CODE_STRUCT: > + case TYPE_CODE_UNION: > + case TYPE_CODE_MODULE: > + { > + int size; > + const char *parent_name = type_name_no_tag_or_error (saved_parent_type); > + struct symbol *sym > + = d_lookup_symbol_in_module (parent_name, nested_name, > + block, VAR_DOMAIN, 0); > + char *concatenated_name; > + > + if (sym != NULL) > + return sym; > + > + /* Now search all static file-level symbols. We have to do this > + for things like typedefs in the class. We do not try to > + guess any imported module as even the fully specified > + module search is already not D compliant and more assumptions > + could make it too magic. */ > + size = strlen (parent_name) + strlen (nested_name) + 2; > + concatenated_name = alloca (size); > + > + xsnprintf (concatenated_name, size, "%s.%s", > + parent_name, nested_name); > + > + sym = lookup_static_symbol (concatenated_name, VAR_DOMAIN); > + if (sym != NULL) > + return sym; > + > + /* If no matching symbols were found, try searching any > + base classes. */ > + return find_symbol_in_baseclass (parent_type, nested_name, block); > + } > + > + case TYPE_CODE_FUNC: > + case TYPE_CODE_METHOD: > + return NULL; > + > + default: > + internal_error (__FILE__, __LINE__, > + _("d_lookup_nested_symbol called " > + "on a non-aggregate type.")); gdb_assert_not_reached would be simpler. > + } > +} > + > +/* Look up NAME in BLOCK's static block and in global blocks. > + If SEARCH is non-zero, search through base classes for a matching > + symbol. Other arguments are as in d_lookup_symbol_nonlocal. */ > + > +static struct symbol * > +lookup_symbol_file (const char *name, const struct block *block, > + const domain_enum domain, int search) > +{ > + struct symbol *sym = NULL; > + > + sym = lookup_symbol_in_static_block (name, block, domain); > + if (sym != NULL) > + return sym; > + > + sym = lookup_global_symbol (name, block, domain); > + > + if (sym != NULL) > + return sym; > + > + if (search) > + { > + char *classname, *nested; > + unsigned int prefix_len; > + struct cleanup *cleanup; > + struct symbol *class_sym; > + > + /* A simple lookup failed. Check if the symbol was defined in > + a base class. */ > + > + cleanup = make_cleanup (null_cleanup, NULL); > + > + /* Find the name of the class and the name of the method, > + variable, etc. */ > + prefix_len = d_entire_prefix_len (name); > + > + /* If no prefix was found, search "this". */ > + if (prefix_len == 0) > + { > + struct type *type; > + struct symbol *this; > + > + this = lookup_language_this (language_def (language_d), block); > + if (this == NULL) > + { > + do_cleanups (cleanup); > + return NULL; > + } > + > + type = check_typedef (TYPE_TARGET_TYPE (SYMBOL_TYPE (this))); > + classname = xstrdup (TYPE_NAME (type)); > + nested = xstrdup (name); > + } > + else > + { > + /* The class name is everything up to and including PREFIX_LEN. */ > + classname = savestring (name, prefix_len); > + > + /* The rest of the name is everything else past the initial scope > + operator. */ > + nested = xstrdup (name + prefix_len + 1); > + } > + > + /* Add cleanups to free memory for these strings. */ > + make_cleanup (xfree, classname); > + make_cleanup (xfree, nested); > + > + /* Lookup a class named CLASSNAME. If none is found, there is nothing > + more that can be done. */ > + class_sym = lookup_global_symbol (classname, block, domain); > + if (class_sym == NULL) > + { > + do_cleanups (cleanup); > + return NULL; > + } > + > + /* Look for a symbol named NESTED in this class. */ > + sym = d_lookup_nested_symbol (SYMBOL_TYPE (class_sym), nested, block); > + do_cleanups (cleanup); > + } > + > + return sym; > +} > + > +/* Used for cleanups to reset the "searched" flag incase > + of an error. */ > + > +static void > +reset_directive_searched (void *data) > +{ > + struct using_direct *direct = data; > + direct->searched = 0; > +} > + > +/* Search for NAME by applying all import statements belonging to > + BLOCK which are applicable in SCOPE. > + > + If SEARCH_PARENTS the search will include imports which are > + applicable in parents of SCOPE. > + Example: > + > + module A; > + import X; > + void B() { > + import Y; > + } > + > + If SCOPE is "A.B" and SEARCH_PARENTS is true, the imports of > + modules X and Y will be considered. If SEARCH_PARENTS is false > + only the import of Y is considered. */ > + > +static struct symbol * > +d_lookup_symbol_imports (const char *scope, const char *name, > + const struct block *block, > + const domain_enum domain, > + const int search_parents) > +{ > + struct using_direct *current; > + struct symbol *sym = NULL; > + int directive_match; > + struct cleanup *searched_cleanup; > + > + /* First, try to find the symbol in the given module. */ > + sym = d_lookup_symbol_in_module (scope, name, block, domain, 1); > + > + if (sym != NULL) > + return sym; > + > + /* Go through the using directives. If any of them add new names to > + the module we're searching in, see if we can find a match by > + applying them. */ > + > + for (current = block_using (block); > + current != NULL; > + current = current->next) > + { > + const char **excludep; > + int len = strlen (current->import_dest); > + > + directive_match = (search_parents > + ? (strncmp (scope, current->import_dest, len) == 0 > + && (len == 0 > + || scope[len] == '.' > + || scope[len] == '\0')) > + : strcmp (scope, current->import_dest) == 0); > + > + /* If the import destination is the current scope or one of its > + ancestors then it is applicable. */ > + if (directive_match && !current->searched) > + { > + /* Mark this import as searched so that the recursive call > + does not search it again. */ > + current->searched = 1; > + searched_cleanup = make_cleanup (reset_directive_searched, > + current); > + > + /* If there is an import of a single declaration, compare the > + imported declaration (after optional renaming by its alias) > + with the sought out name. If there is a match pass > + current->import_src as MODULE to direct the search towards > + the imported module. */ > + if (current->declaration > + && strcmp (name, current->alias > + ? current->alias : current->declaration) == 0) > + sym = d_lookup_symbol_in_module (current->import_src, > + current->declaration, > + block, domain, 1); > + > + /* If a symbol was found or this import statement was an import > + declaration, the search of this import is complete. */ > + if (sym != NULL || current->declaration) > + { > + current->searched = 0; > + discard_cleanups (searched_cleanup); > + > + if (sym != NULL) > + return sym; > + > + continue; > + } > + > + /* Do not follow CURRENT if NAME matches its EXCLUDES. */ > + for (excludep = current->excludes; *excludep; excludep++) > + if (strcmp (name, *excludep) == 0) > + break; > + if (*excludep) > + { > + discard_cleanups (searched_cleanup); > + continue; > + } > + > + /* If the import statement is creating an alias. */ > + if (current->alias != NULL) > + { > + if (strcmp (name, current->alias) == 0) > + { > + /* If the alias matches the sought name. Pass > + current->import_src as the NAME to direct the > + search towards the aliased module. */ > + sym = lookup_module_scope (current->import_src, block, > + domain, scope, 0); > + } > + else > + { > + /* If the alias matches the first component of the > + sought name, pass current->import_src as MODULE > + to direct the search, skipping over the aliased > + component in NAME. */ > + int name_scope = d_find_first_component (name); > + > + if (name[name_scope] != '\0' > + && strncmp (name, current->alias, name_scope) == 0) > + { > + /* Skip the '.' */ > + name_scope++; > + sym = d_lookup_symbol_imports (current->import_src, > + name + name_scope, > + block, domain, 0); > + } > + } > + } > + else > + { > + /* If this import statement creates no alias, pass > + current->import_src as MODULE to direct the search > + towards the imported module. */ > + sym = d_lookup_symbol_imports (current->import_src, > + name, block, domain, 0); > + } > + current->searched = 0; > + discard_cleanups (searched_cleanup); > + > + if (sym != NULL) > + return sym; > + } > + } > + > + return NULL; > +} > + > +/* Searches for NAME in the current module, and by applying relevant > + import statements belonging to BLOCK and its parents. SCOPE is the > + module scope of the context in which the search is being evaluated. */ > + > +static struct symbol* > +d_lookup_symbol_module (const char *scope, const char *name, > + const struct block *block, > + const domain_enum domain) > +{ > + struct symbol *sym; > + > + /* First, try to find the symbol in the given module. */ > + sym = d_lookup_symbol_in_module (scope, name, > + block, domain, 1); > + if (sym != NULL) > + return sym; > + > + /* Search for name in modules imported to this and parent > + blocks. */ > + while (block != NULL) > + { > + sym = d_lookup_symbol_imports (scope, name, block, domain, 1); > + > + if (sym) > + return sym; > + > + block = BLOCK_SUPERBLOCK (block); > + } > + > + return NULL; > +} > + > +/* The D-specific version of name lookup for static and global names > + This makes sure that names get looked for in all modules that are > + in scope. NAME is the natural name of the symbol that we're looking > + looking for, BLOCK is the block that we're searching within, DOMAIN > + says what kind of symbols we're looking for, and if SYMTAB is non-NULL, > + we should store the symtab where we found the symbol in it. */ > + > +struct symbol * > +d_lookup_symbol_nonlocal (const struct language_defn *langdef, > + const char *name, > + const struct block *block, > + const domain_enum domain) > +{ > + struct symbol *sym; > + const char *scope = block_scope (block); > + > + sym = lookup_module_scope (name, block, domain, scope, 0); > + if (sym != NULL) > + return sym; > + > + return d_lookup_symbol_module (scope, name, block, domain); > +} > +