/* Parser for linespec for the GNU debugger, GDB.
Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1997, 1998, 1999, 2000, 2001
+ 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
Free Software Foundation, Inc.
This file is part of GDB.
#include "command.h"
#include "symfile.h"
#include "objfiles.h"
+#include "source.h"
#include "demangle.h"
#include "value.h"
#include "completer.h"
#include "cp-abi.h"
-
-/* Prototype for one function in parser-defs.h,
- instead of including that entire file. */
-
-extern char *find_template_name_end (char *);
+#include "parser-defs.h"
/* We share this one with symtab.c, but it is not exported widely. */
/* Prototypes for local functions */
-static void cplusplus_hint (char *name);
+static void initialize_defaults (struct symtab **default_symtab,
+ int *default_line);
+
+static void set_flags (char *arg, int *is_quoted, char **paren_pointer);
+
+static struct symtabs_and_lines decode_indirect (char **argptr);
+
+static char *locate_first_half (char **argptr, int *is_quote_enclosed);
+
+static struct symtabs_and_lines decode_compound (char **argptr,
+ int funfirstline,
+ char ***canonical,
+ char *saved_arg,
+ char *p);
+
+static struct symbol *lookup_prefix_sym (char **argptr, char *p);
+
+static NORETURN void cplusplus_error (const char *name,
+ const char *fmt, ...)
+ ATTR_NORETURN ATTR_FORMAT (printf, 2, 3);
static int total_number_of_methods (struct type *type);
static struct symtabs_and_lines decode_line_2 (struct symbol *[],
int, int, char ***);
+static struct symtab *symtab_from_filename (char **argptr,
+ char *p, int is_quote_enclosed);
+
+static struct
+symtabs_and_lines decode_all_digits (char **argptr,
+ struct symtab *default_symtab,
+ int default_line,
+ char ***canonical,
+ struct symtab *file_symtab,
+ char *q);
+
+static struct symtabs_and_lines decode_dollar (char *copy,
+ int funfirstline,
+ struct symtab *default_symtab,
+ char ***canonical,
+ struct symtab *file_symtab);
+
+static struct symtabs_and_lines decode_variable (char *copy,
+ int funfirstline,
+ char ***canonical,
+ struct symtab *file_symtab);
+
+static struct
+symtabs_and_lines symbol_found (int funfirstline,
+ char ***canonical,
+ char *copy,
+ struct symbol *sym,
+ struct symtab *file_symtab,
+ struct symtab *sym_symtab);
+
+static struct
+symtabs_and_lines minsym_found (int funfirstline,
+ struct minimal_symbol *msymbol);
+
/* Helper functions. */
-/* While the C++ support is still in flux, issue a possibly helpful hint on
- using the new command completion feature on single quoted demangled C++
- symbols. Remove when loose ends are cleaned up. FIXME -fnf */
+/* Issue a helpful hint on using the command completion feature on
+ single quoted demangled C++ symbols as part of the completion
+ error. */
-static void
-cplusplus_hint (char *name)
+static NORETURN void
+cplusplus_error (const char *name, const char *fmt, ...)
{
+ struct ui_file *tmp_stream;
+ tmp_stream = mem_fileopen ();
+ make_cleanup_ui_file_delete (tmp_stream);
+
+ {
+ va_list args;
+ va_start (args, fmt);
+ vfprintf_unfiltered (tmp_stream, fmt, args);
+ va_end (args);
+ }
+
while (*name == '\'')
name++;
- printf_filtered ("Hint: try '%s<TAB> or '%s<ESC-?>\n", name, name);
- printf_filtered ("(Note leading single quote.)\n");
+ fprintf_unfiltered (tmp_stream,
+ ("Hint: try '%s<TAB> or '%s<ESC-?>\n"
+ "(Note leading single quote.)"),
+ name, name);
+ error_stream (tmp_stream);
}
/* Return the number of methods described for TYPE, including the
(struct symtab **) NULL)))
{
int method_counter;
+ int name_len = strlen (name);
CHECK_TYPEDEF (t);
else
phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
- /* Destructor is handled by caller, dont add it to the list */
+ /* Destructor is handled by caller, don't add it to
+ the list. */
if (is_destructor_name (phys_name) != 0)
continue;
*/
}
}
+ else if (strncmp (class_name, name, name_len) == 0
+ && (class_name[name_len] == '\0'
+ || class_name[name_len] == '<'))
+ {
+ /* For GCC 3.x and stabs, constructors and destructors
+ have names like __base_ctor and __complete_dtor.
+ Check the physname for now if we're looking for a
+ constructor. */
+ for (field_counter
+ = TYPE_FN_FIELDLIST_LENGTH (t, method_counter) - 1;
+ field_counter >= 0;
+ --field_counter)
+ {
+ struct fn_field *f;
+ char *phys_name;
+
+ f = TYPE_FN_FIELDLIST1 (t, method_counter);
+
+ /* GCC 3.x will never produce stabs stub methods, so
+ we don't need to handle this case. */
+ if (TYPE_FN_FIELD_STUB (f, field_counter))
+ continue;
+ phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
+ if (! is_constructor_name (phys_name))
+ continue;
+
+ /* If this method is actually defined, include it in the
+ list. */
+ sym_arr[i1] = lookup_symbol (phys_name,
+ NULL, VAR_NAMESPACE,
+ (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym_arr[i1])
+ i1++;
+ }
+ }
}
}
/* Find an instance of the character C in the string S that is outside
of all parenthesis pairs, single-quoted strings, and double-quoted
- strings. */
+ strings. Also, ignore the char within a template name, like a ','
+ within foo<int, int>. */
+
static char *
find_toplevel_char (char *s, char c)
{
int quoted = 0; /* zero if we're not in quotes;
'"' if we're in a double-quoted string;
'\'' if we're in a single-quoted string. */
- int depth = 0; /* number of unclosed parens we've seen */
+ int depth = 0; /* Number of unclosed parens we've seen. */
char *scan;
for (scan = s; *scan; scan++)
return scan;
else if (*scan == '"' || *scan == '\'')
quoted = *scan;
- else if (*scan == '(')
+ else if (*scan == '(' || *scan == '<')
depth++;
- else if (*scan == ')' && depth > 0)
+ else if ((*scan == ')' || *scan == '>') && depth > 0)
depth--;
}
printf_unfiltered ("[0] cancel\n[1] all\n");
while (i < nelts)
{
- INIT_SAL (&return_values.sals[i]); /* initialize to zeroes */
- INIT_SAL (&values.sals[i]);
+ init_sal (&return_values.sals[i]); /* Initialize to zeroes. */
+ init_sal (&values.sals[i]);
if (sym_arr[i] && SYMBOL_CLASS (sym_arr[i]) == LOC_BLOCK)
{
values.sals[i] = find_function_start_sal (sym_arr[i], funfirstline);
i++;
}
- if ((prompt = getenv ("PS2")) == NULL)
+ prompt = getenv ("PS2");
+ if (prompt == NULL)
{
prompt = "> ";
}
decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
int default_line, char ***canonical)
{
- struct symtabs_and_lines values;
- struct symtab_and_line val;
- register char *p, *p1;
- char *q, *pp, *ii, *p2;
-#if 0
- char *q1;
-#endif
- register struct symtab *s;
-
- register struct symbol *sym;
- /* The symtab that SYM was found in. */
- struct symtab *sym_symtab;
+ char *p;
+ char *q;
+ /* If a file name is specified, this is its symtab. */
+ struct symtab *file_symtab = NULL;
- register CORE_ADDR pc;
- register struct minimal_symbol *msymbol;
char *copy;
- struct symbol *sym_class;
- int i1;
+ /* This is NULL if there are no parens in *ARGPTR, or a pointer to
+ the closing parenthesis if there are parens. */
+ char *paren_pointer;
+ /* This says whether or not something in *ARGPTR is quoted with
+ completer_quotes (i.e. with single quotes). */
int is_quoted;
+ /* Is part of *ARGPTR is enclosed in double quotes? */
int is_quote_enclosed;
- int has_parens;
- int has_if = 0;
- int has_comma = 0;
- struct symbol **sym_arr;
- struct type *t;
char *saved_arg = *argptr;
- extern char *gdb_completer_quote_characters;
-
- INIT_SAL (&val); /* initialize to zeroes */
/* Defaults have defaults. */
- if (default_symtab == 0)
+ initialize_defaults (&default_symtab, &default_line);
+
+ /* See if arg is *PC. */
+
+ if (**argptr == '*')
+ return decode_indirect (argptr);
+
+ /* Set various flags. 'paren_pointer' is important for overload
+ checking, where we allow things like:
+ (gdb) break c::f(int)
+ */
+
+ set_flags (*argptr, &is_quoted, &paren_pointer);
+
+ /* Check to see if it's a multipart linespec (with colons or
+ periods). */
+
+ /* Locate the end of the first half of the linespec. */
+
+ p = locate_first_half (argptr, &is_quote_enclosed);
+
+ /* Does it look like there actually were two parts? */
+
+ if ((p[0] == ':' || p[0] == '.') && paren_pointer == NULL)
+ {
+ if (is_quoted)
+ *argptr = *argptr + 1;
+
+ /* Is it a C++ or Java compound data structure? */
+
+ if (p[0] == '.' || p[1] == ':')
+ return decode_compound (argptr, funfirstline, canonical,
+ saved_arg, p);
+
+ /* No, the first part is a filename; set s to be that file's
+ symtab. Also, move argptr past the filename. */
+
+ file_symtab = symtab_from_filename (argptr, p, is_quote_enclosed);
+ }
+#if 0
+ /* No one really seems to know why this was added. It certainly
+ breaks the command line, though, whenever the passed
+ name is of the form ClassName::Method. This bit of code
+ singles out the class name, and if funfirstline is set (for
+ example, you are setting a breakpoint at this function),
+ you get an error. This did not occur with earlier
+ verions, so I am ifdef'ing this out. 3/29/99 */
+ else
{
- default_symtab = current_source_symtab;
- default_line = current_source_line;
+ /* Check if what we have till now is a symbol name */
+
+ /* We may be looking at a template instantiation such
+ as "foo<int>". Check here whether we know about it,
+ instead of falling through to the code below which
+ handles ordinary function names, because that code
+ doesn't like seeing '<' and '>' in a name -- the
+ skip_quoted call doesn't go past them. So see if we
+ can figure it out right now. */
+
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\000';
+ sym = lookup_symbol (copy, 0, VAR_NAMESPACE, 0, &sym_symtab);
+ if (sym)
+ {
+ *argptr = (*p == '\'') ? p + 1 : p;
+ return symbol_found (funfirstline, canonical, copy, sym,
+ NULL, sym_symtab);
+ }
+ /* Otherwise fall out from here and go to file/line spec
+ processing, etc. */
}
+#endif
- /* See if arg is *PC */
+ /* S is specified file's symtab, or 0 if no file specified.
+ arg no longer contains the file name. */
- if (**argptr == '*')
+ /* Check whether arg is all digits (and sign). */
+
+ q = *argptr;
+ if (*q == '-' || *q == '+')
+ q++;
+ while (*q >= '0' && *q <= '9')
+ q++;
+
+ if (q != *argptr && (*q == 0 || *q == ' ' || *q == '\t' || *q == ','))
+ /* We found a token consisting of all digits -- at least one digit. */
+ return decode_all_digits (argptr, default_symtab, default_line,
+ canonical, file_symtab, q);
+
+ /* Arg token is not digits => try it as a variable name
+ Find the next token (everything up to end or next whitespace). */
+
+ if (**argptr == '$') /* May be a convenience variable. */
+ /* One or two $ chars possible. */
+ p = skip_quoted (*argptr + (((*argptr)[1] == '$') ? 2 : 1));
+ else if (is_quoted)
{
- (*argptr)++;
- pc = parse_and_eval_address_1 (argptr);
+ p = skip_quoted (*argptr);
+ if (p[-1] != '\'')
+ error ("Unmatched single quote.");
+ }
+ else if (paren_pointer != NULL)
+ {
+ p = paren_pointer + 1;
+ }
+ else
+ {
+ p = skip_quoted (*argptr);
+ }
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\0';
+ if (p != *argptr
+ && copy[0]
+ && copy[0] == copy[p - *argptr - 1]
+ && strchr (get_gdb_completer_quote_characters (), copy[0]) != NULL)
+ {
+ copy[p - *argptr - 1] = '\0';
+ copy++;
+ }
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
- values.nelts = 1;
- values.sals[0] = find_pc_line (pc, 0);
- values.sals[0].pc = pc;
- values.sals[0].section = find_pc_overlay (pc);
+ /* If it starts with $: may be a legitimate variable or routine name
+ (e.g. HP-UX millicode routines such as $$dyncall), or it may
+ be history value, or it may be a convenience variable. */
- return values;
+ if (*copy == '$')
+ return decode_dollar (copy, funfirstline, default_symtab,
+ canonical, file_symtab);
+
+ /* Look up that token as a variable.
+ If file specified, use that file's per-file block to start with. */
+
+ return decode_variable (copy, funfirstline, canonical, file_symtab);
+}
+
+\f
+
+/* Now, more helper functions for decode_line_1. Some conventions
+ that these functions follow:
+
+ Decode_line_1 typically passes along some of its arguments or local
+ variables to the subfunctions. It passes the variables by
+ reference if they are modified by the subfunction, and by value
+ otherwise.
+
+ Some of the functions have side effects that don't arise from
+ variables that are passed by reference. In particular, if a
+ function is passed ARGPTR as an argument, it modifies what ARGPTR
+ points to; typically, it advances *ARGPTR past whatever substring
+ it has just looked at. (If it doesn't modify *ARGPTR, then the
+ function gets passed *ARGPTR instead, which is then called ARG: see
+ set_flags, for example.) Also, functions that return a struct
+ symtabs_and_lines may modify CANONICAL, as in the description of
+ decode_line_1.
+
+ If a function returns a struct symtabs_and_lines, then that struct
+ will immediately make its way up the call chain to be returned by
+ decode_line_1. In particular, all of the functions decode_XXX
+ calculate the appropriate struct symtabs_and_lines, under the
+ assumption that their argument is of the form XXX. */
+
+/* First, some functions to initialize stuff at the beggining of the
+ function. */
+
+static void
+initialize_defaults (struct symtab **default_symtab, int *default_line)
+{
+ if (*default_symtab == 0)
+ {
+ /* Use whatever we have for the default source line. We don't use
+ get_current_or_default_symtab_and_line as it can recurse and call
+ us back! */
+ struct symtab_and_line cursal =
+ get_current_source_symtab_and_line ();
+
+ *default_symtab = cursal.symtab;
+ *default_line = cursal.line;
}
+}
+
+static void
+set_flags (char *arg, int *is_quoted, char **paren_pointer)
+{
+ char *ii;
+ int has_if = 0;
/* 'has_if' is for the syntax:
- * (gdb) break foo if (a==b)
- */
- if ((ii = strstr (*argptr, " if ")) != NULL ||
- (ii = strstr (*argptr, "\tif ")) != NULL ||
- (ii = strstr (*argptr, " if\t")) != NULL ||
- (ii = strstr (*argptr, "\tif\t")) != NULL ||
- (ii = strstr (*argptr, " if(")) != NULL ||
- (ii = strstr (*argptr, "\tif( ")) != NULL)
+ (gdb) break foo if (a==b)
+ */
+ if ((ii = strstr (arg, " if ")) != NULL ||
+ (ii = strstr (arg, "\tif ")) != NULL ||
+ (ii = strstr (arg, " if\t")) != NULL ||
+ (ii = strstr (arg, "\tif\t")) != NULL ||
+ (ii = strstr (arg, " if(")) != NULL ||
+ (ii = strstr (arg, "\tif( ")) != NULL)
has_if = 1;
- /* Temporarily zap out "if (condition)" to not
- * confuse the parenthesis-checking code below.
- * This is undone below. Do not change ii!!
- */
+ /* Temporarily zap out "if (condition)" to not confuse the
+ parenthesis-checking code below. This is undone below. Do not
+ change ii!! */
if (has_if)
{
*ii = '\0';
}
- /* Set various flags.
- * 'has_parens' is important for overload checking, where
- * we allow things like:
- * (gdb) break c::f(int)
- */
-
- /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */
+ *is_quoted = (*arg
+ && strchr (get_gdb_completer_quote_characters (),
+ *arg) != NULL);
- is_quoted = (**argptr
- && strchr (get_gdb_completer_quote_characters (),
- **argptr) != NULL);
+ *paren_pointer = strchr (arg, '(');
+ if (*paren_pointer != NULL)
+ *paren_pointer = strrchr (*paren_pointer, ')');
- has_parens = ((pp = strchr (*argptr, '(')) != NULL
- && (pp = strrchr (pp, ')')) != NULL);
-
- /* Now that we're safely past the has_parens check,
- * put back " if (condition)" so outer layers can see it
- */
+ /* Now that we're safely past the paren_pointer check, put back " if
+ (condition)" so outer layers can see it. */
if (has_if)
*ii = ' ';
+}
+
+\f
+
+/* Decode arg of the form *PC. */
+
+static struct symtabs_and_lines
+decode_indirect (char **argptr)
+{
+ struct symtabs_and_lines values;
+ CORE_ADDR pc;
+
+ (*argptr)++;
+ pc = parse_and_eval_address_1 (argptr);
+
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+
+ values.nelts = 1;
+ values.sals[0] = find_pc_line (pc, 0);
+ values.sals[0].pc = pc;
+ values.sals[0].section = find_pc_overlay (pc);
+
+ return values;
+}
+
+\f
+
+/* Locate the first half of the linespec, ending in a colon, period,
+ or whitespace. (More or less.) Also, check to see if *ARGPTR is
+ enclosed in double quotes; if so, set is_quote_enclosed, advance
+ ARGPTR past that and zero out the trailing double quote. */
+
+static char *
+locate_first_half (char **argptr, int *is_quote_enclosed)
+{
+ char *ii;
+ char *p, *p1;
+ int has_comma;
/* Maybe we were called with a line range FILENAME:LINENUM,FILENAME:LINENUM
and we must isolate the first half. Outer layers will call again later
ii = find_toplevel_char (*argptr, ',');
has_comma = (ii != 0);
- /* Temporarily zap out second half to not
- * confuse the code below.
- * This is undone below. Do not change ii!!
- */
+ /* Temporarily zap out second half to not confuse the code below.
+ This is undone below. Do not change ii!! */
if (has_comma)
{
*ii = '\0';
}
- /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */
- /* May also be CLASS::MEMBER, or NAMESPACE::NAME */
- /* Look for ':', but ignore inside of <> */
+ /* Maybe arg is FILE : LINENUM or FILE : FUNCTION. May also be
+ CLASS::MEMBER, or NAMESPACE::NAME. Look for ':', but ignore
+ inside of <>. */
- s = NULL;
p = *argptr;
if (p[0] == '"')
{
- is_quote_enclosed = 1;
+ *is_quote_enclosed = 1;
(*argptr)++;
p++;
}
else
- is_quote_enclosed = 0;
+ *is_quote_enclosed = 0;
for (; *p; p++)
{
if (p[0] == '<')
error ("malformed template specification in command");
p = temp_end;
}
- /* Check for the end of the first half of the linespec. End of line,
- a tab, a double colon or the last single colon, or a space. But
- if enclosed in double quotes we do not break on enclosed spaces */
+ /* Check for the end of the first half of the linespec. End of
+ line, a tab, a double colon or the last single colon, or a
+ space. But if enclosed in double quotes we do not break on
+ enclosed spaces. */
if (!*p
|| p[0] == '\t'
|| ((p[0] == ':')
&& ((p[1] == ':') || (strchr (p + 1, ':') == NULL)))
- || ((p[0] == ' ') && !is_quote_enclosed))
+ || ((p[0] == ' ') && !*is_quote_enclosed))
break;
- if (p[0] == '.' && strchr (p, ':') == NULL) /* Java qualified method. */
+ if (p[0] == '.' && strchr (p, ':') == NULL)
{
- /* Find the *last* '.', since the others are package qualifiers. */
+ /* Java qualified method. Find the *last* '.', since the
+ others are package qualifiers. */
for (p1 = p; *p1; p1++)
{
if (*p1 == '.')
while (p[0] == ' ' || p[0] == '\t')
p++;
- /* if the closing double quote was left at the end, remove it */
- if (is_quote_enclosed)
+ /* If the closing double quote was left at the end, remove it. */
+ if (*is_quote_enclosed)
{
char *closing_quote = strchr (p - 1, '"');
if (closing_quote && closing_quote[1] == '\0')
*closing_quote = '\0';
}
- /* Now that we've safely parsed the first half,
- * put back ',' so outer layers can see it
- */
+ /* Now that we've safely parsed the first half, put back ',' so
+ outer layers can see it. */
if (has_comma)
*ii = ',';
- if ((p[0] == ':' || p[0] == '.') && !has_parens)
+ return p;
+}
+
+\f
+
+/* This handles C++ and Java compound data structures. P should point
+ at the first component separator, i.e. double-colon or period. */
+
+static struct symtabs_and_lines
+decode_compound (char **argptr, int funfirstline, char ***canonical,
+ char *saved_arg, char *p)
+{
+ struct symtabs_and_lines values;
+ char *p2;
+#if 0
+ char *q, *q1;
+#endif
+ char *saved_arg2 = *argptr;
+ char *temp_end;
+ struct symbol *sym;
+ /* The symtab that SYM was found in. */
+ struct symtab *sym_symtab;
+ char *copy;
+ struct symbol *sym_class;
+ int i1;
+ struct symbol **sym_arr;
+ struct type *t;
+
+ /* First check for "global" namespace specification,
+ of the form "::foo". If found, skip over the colons
+ and jump to normal symbol processing. */
+ if (p[0] == ':'
+ && ((*argptr == p) || (p[-1] == ' ') || (p[-1] == '\t')))
+ saved_arg2 += 2;
+
+ /* We have what looks like a class or namespace
+ scope specification (A::B), possibly with many
+ levels of namespaces or classes (A::B::C::D).
+
+ Some versions of the HP ANSI C++ compiler (as also possibly
+ other compilers) generate class/function/member names with
+ embedded double-colons if they are inside namespaces. To
+ handle this, we loop a few times, considering larger and
+ larger prefixes of the string as though they were single
+ symbols. So, if the initially supplied string is
+ A::B::C::D::foo, we have to look up "A", then "A::B",
+ then "A::B::C", then "A::B::C::D", and finally
+ "A::B::C::D::foo" as single, monolithic symbols, because
+ A, B, C or D may be namespaces.
+
+ Note that namespaces can nest only inside other
+ namespaces, and not inside classes. So we need only
+ consider *prefixes* of the string; there is no need to look up
+ "B::C" separately as a symbol in the previous example. */
+
+ p2 = p; /* Save for restart. */
+ while (1)
{
- /* C++ */
- /* ... or Java */
- if (is_quoted)
- *argptr = *argptr + 1;
- if (p[0] == '.' || p[1] == ':')
+ sym_class = lookup_prefix_sym (argptr, p);
+
+ if (sym_class &&
+ (t = check_typedef (SYMBOL_TYPE (sym_class)),
+ (TYPE_CODE (t) == TYPE_CODE_STRUCT
+ || TYPE_CODE (t) == TYPE_CODE_UNION)))
{
- char *saved_arg2 = *argptr;
- char *temp_end;
- /* First check for "global" namespace specification,
- of the form "::foo". If found, skip over the colons
- and jump to normal symbol processing */
- if (p[0] == ':'
- && ((*argptr == p) || (p[-1] == ' ') || (p[-1] == '\t')))
- saved_arg2 += 2;
-
- /* We have what looks like a class or namespace
- scope specification (A::B), possibly with many
- levels of namespaces or classes (A::B::C::D).
-
- Some versions of the HP ANSI C++ compiler (as also possibly
- other compilers) generate class/function/member names with
- embedded double-colons if they are inside namespaces. To
- handle this, we loop a few times, considering larger and
- larger prefixes of the string as though they were single
- symbols. So, if the initially supplied string is
- A::B::C::D::foo, we have to look up "A", then "A::B",
- then "A::B::C", then "A::B::C::D", and finally
- "A::B::C::D::foo" as single, monolithic symbols, because
- A, B, C or D may be namespaces.
-
- Note that namespaces can nest only inside other
- namespaces, and not inside classes. So we need only
- consider *prefixes* of the string; there is no need to look up
- "B::C" separately as a symbol in the previous example. */
-
- p2 = p; /* save for restart */
- while (1)
+ /* Arg token is not digits => try it as a function name.
+ Find the next token (everything up to end or next
+ blank). */
+ if (**argptr
+ && strchr (get_gdb_completer_quote_characters (),
+ **argptr) != NULL)
+ {
+ p = skip_quoted (*argptr);
+ *argptr = *argptr + 1;
+ }
+ else
{
- /* Extract the class name. */
- p1 = p;
- while (p != *argptr && p[-1] == ' ')
- --p;
- copy = (char *) alloca (p - *argptr + 1);
- memcpy (copy, *argptr, p - *argptr);
- copy[p - *argptr] = 0;
-
- /* Discard the class name from the arg. */
- p = p1 + (p1[0] == ':' ? 2 : 1);
- while (*p == ' ' || *p == '\t')
+ p = *argptr;
+ while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p != ':')
p++;
- *argptr = p;
-
- sym_class = lookup_symbol (copy, 0, STRUCT_NAMESPACE, 0,
- (struct symtab **) NULL);
-
- if (sym_class &&
- (t = check_typedef (SYMBOL_TYPE (sym_class)),
- (TYPE_CODE (t) == TYPE_CODE_STRUCT
- || TYPE_CODE (t) == TYPE_CODE_UNION)))
- {
- /* Arg token is not digits => try it as a function name
- Find the next token(everything up to end or next blank). */
- if (**argptr
- && strchr (get_gdb_completer_quote_characters (),
- **argptr) != NULL)
- {
- p = skip_quoted (*argptr);
- *argptr = *argptr + 1;
- }
- else
- {
- p = *argptr;
- while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p != ':')
- p++;
- }
+ }
/*
q = operator_chars (*argptr, &q1);
if (q1 - q)
opname = cplus_mangle_opname (tmp, DMGL_ANSI);
if (opname == NULL)
{
- error_begin ();
- printf_filtered ("no mangling for \"%s\"\n", tmp);
- cplusplus_hint (saved_arg);
- return_to_top_level (RETURN_ERROR);
+ cplusplus_error (saved_arg, "no mangling for \"%s\"\n", tmp);
}
copy = (char*) alloca (3 + strlen(opname));
sprintf (copy, "__%s", opname);
}
else
*/
- {
- copy = (char *) alloca (p - *argptr + 1);
- memcpy (copy, *argptr, p - *argptr);
- copy[p - *argptr] = '\0';
- if (p != *argptr
- && copy[p - *argptr - 1]
- && strchr (get_gdb_completer_quote_characters (),
- copy[p - *argptr - 1]) != NULL)
- copy[p - *argptr - 1] = '\0';
- }
-
- /* no line number may be specified */
- while (*p == ' ' || *p == '\t')
- p++;
- *argptr = p;
-
- sym = 0;
- i1 = 0; /* counter for the symbol array */
- sym_arr = (struct symbol **) alloca (total_number_of_methods (t)
- * sizeof (struct symbol *));
+ {
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = '\0';
+ if (p != *argptr
+ && copy[p - *argptr - 1]
+ && strchr (get_gdb_completer_quote_characters (),
+ copy[p - *argptr - 1]) != NULL)
+ copy[p - *argptr - 1] = '\0';
+ }
+
+ /* No line number may be specified. */
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
+
+ sym = 0;
+ i1 = 0; /* Counter for the symbol array. */
+ sym_arr = (struct symbol **) alloca (total_number_of_methods (t)
+ * sizeof (struct symbol *));
+
+ if (destructor_name_p (copy, t))
+ {
+ /* Destructors are a special case. */
+ int m_index, f_index;
- if (destructor_name_p (copy, t))
- {
- /* Destructors are a special case. */
- int m_index, f_index;
-
- if (get_destructor_fn_field (t, &m_index, &f_index))
- {
- struct fn_field *f = TYPE_FN_FIELDLIST1 (t, m_index);
-
- sym_arr[i1] =
- lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, f_index),
- NULL, VAR_NAMESPACE, (int *) NULL,
- (struct symtab **) NULL);
- if (sym_arr[i1])
- i1++;
- }
- }
- else
- i1 = find_methods (t, copy, sym_arr);
- if (i1 == 1)
- {
- /* There is exactly one field with that name. */
- sym = sym_arr[0];
-
- if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
- {
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.nelts = 1;
- values.sals[0] = find_function_start_sal (sym,
- funfirstline);
- }
- else
- {
- values.nelts = 0;
- }
- return values;
- }
- if (i1 > 0)
- {
- /* There is more than one field with that name
- (overloaded). Ask the user which one to use. */
- return decode_line_2 (sym_arr, i1, funfirstline, canonical);
- }
- else
- {
- char *tmp;
-
- if (is_operator_name (copy))
- {
- tmp = (char *) alloca (strlen (copy + 3) + 9);
- strcpy (tmp, "operator ");
- strcat (tmp, copy + 3);
- }
- else
- tmp = copy;
- error_begin ();
- if (tmp[0] == '~')
- printf_filtered
- ("the class `%s' does not have destructor defined\n",
- SYMBOL_SOURCE_NAME (sym_class));
- else
- printf_filtered
- ("the class %s does not have any method named %s\n",
- SYMBOL_SOURCE_NAME (sym_class), tmp);
- cplusplus_hint (saved_arg);
- return_to_top_level (RETURN_ERROR);
- }
+ if (get_destructor_fn_field (t, &m_index, &f_index))
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, m_index);
+
+ sym_arr[i1] =
+ lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, f_index),
+ NULL, VAR_NAMESPACE, (int *) NULL,
+ (struct symtab **) NULL);
+ if (sym_arr[i1])
+ i1++;
}
+ }
+ else
+ i1 = find_methods (t, copy, sym_arr);
+ if (i1 == 1)
+ {
+ /* There is exactly one field with that name. */
+ sym = sym_arr[0];
- /* Move pointer up to next possible class/namespace token */
- p = p2 + 1; /* restart with old value +1 */
- /* Move pointer ahead to next double-colon */
- while (*p && (p[0] != ' ') && (p[0] != '\t') && (p[0] != '\''))
+ if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
{
- if (p[0] == '<')
- {
- temp_end = find_template_name_end (p);
- if (!temp_end)
- error ("malformed template specification in command");
- p = temp_end;
- }
- else if ((p[0] == ':') && (p[1] == ':'))
- break; /* found double-colon */
- else
- p++;
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ values.sals[0] = find_function_start_sal (sym,
+ funfirstline);
+ }
+ else
+ {
+ values.nelts = 0;
}
+ return values;
+ }
+ if (i1 > 0)
+ {
+ /* There is more than one field with that name
+ (overloaded). Ask the user which one to use. */
+ return decode_line_2 (sym_arr, i1, funfirstline, canonical);
+ }
+ else
+ {
+ char *tmp;
- if (*p != ':')
- break; /* out of the while (1) */
-
- p2 = p; /* save restart for next time around */
- *argptr = saved_arg2; /* restore argptr */
- } /* while (1) */
-
- /* Last chance attempt -- check entire name as a symbol */
- /* Use "copy" in preparation for jumping out of this block,
- to be consistent with usage following the jump target */
- copy = (char *) alloca (p - saved_arg2 + 1);
- memcpy (copy, saved_arg2, p - saved_arg2);
- /* Note: if is_quoted should be true, we snuff out quote here anyway */
- copy[p - saved_arg2] = '\000';
- /* Set argptr to skip over the name */
- *argptr = (*p == '\'') ? p + 1 : p;
- /* Look up entire name */
- sym = lookup_symbol (copy, 0, VAR_NAMESPACE, 0, &sym_symtab);
- s = (struct symtab *) 0;
- /* Prepare to jump: restore the " if (condition)" so outer layers see it */
- /* Symbol was found --> jump to normal symbol processing.
- Code following "symbol_found" expects "copy" to have the
- symbol name, "sym" to have the symbol pointer, "s" to be
- a specified file's symtab, and sym_symtab to be the symbol's
- symtab. */
- /* By jumping there we avoid falling through the FILE:LINE and
- FILE:FUNC processing stuff below */
- if (sym)
- goto symbol_found;
-
- /* Couldn't find any interpretation as classes/namespaces, so give up */
- error_begin ();
- /* The quotes are important if copy is empty. */
- printf_filtered
- ("Can't find member of namespace, class, struct, or union named \"%s\"\n", copy);
- cplusplus_hint (saved_arg);
- return_to_top_level (RETURN_ERROR);
+ if (is_operator_name (copy))
+ {
+ tmp = (char *) alloca (strlen (copy + 3) + 9);
+ strcpy (tmp, "operator ");
+ strcat (tmp, copy + 3);
+ }
+ else
+ tmp = copy;
+ if (tmp[0] == '~')
+ cplusplus_error (saved_arg,
+ "the class `%s' does not have destructor defined\n",
+ SYMBOL_SOURCE_NAME (sym_class));
+ else
+ cplusplus_error (saved_arg,
+ "the class %s does not have any method named %s\n",
+ SYMBOL_SOURCE_NAME (sym_class), tmp);
+ }
}
- /* end of C++ */
-
- /* Extract the file name. */
- p1 = p;
- while (p != *argptr && p[-1] == ' ')
- --p;
- if ((*p == '"') && is_quote_enclosed)
- --p;
- copy = (char *) alloca (p - *argptr + 1);
- if ((**argptr == '"') && is_quote_enclosed)
+ /* Move pointer up to next possible class/namespace token. */
+ p = p2 + 1; /* Restart with old value +1. */
+ /* Move pointer ahead to next double-colon. */
+ while (*p && (p[0] != ' ') && (p[0] != '\t') && (p[0] != '\''))
{
- memcpy (copy, *argptr + 1, p - *argptr - 1);
- /* It may have the ending quote right after the file name */
- if (copy[p - *argptr - 2] == '"')
- copy[p - *argptr - 2] = 0;
+ if (p[0] == '<')
+ {
+ temp_end = find_template_name_end (p);
+ if (!temp_end)
+ error ("malformed template specification in command");
+ p = temp_end;
+ }
+ else if ((p[0] == ':') && (p[1] == ':'))
+ break; /* Found double-colon. */
else
- copy[p - *argptr - 1] = 0;
- }
- else
- {
- memcpy (copy, *argptr, p - *argptr);
- copy[p - *argptr] = 0;
+ p++;
}
- /* Find that file's data. */
- s = lookup_symtab (copy);
- if (s == 0)
- {
- if (!have_full_symbols () && !have_partial_symbols ())
- error ("No symbol table is loaded. Use the \"file\" command.");
- error ("No source file named %s.", copy);
- }
+ if (*p != ':')
+ break; /* Out of the while (1). */
+
+ p2 = p; /* Save restart for next time around. */
+ *argptr = saved_arg2; /* Restore argptr. */
+ } /* while (1) */
+
+ /* Last chance attempt -- check entire name as a symbol. Use "copy"
+ in preparation for jumping out of this block, to be consistent
+ with usage following the jump target. */
+ copy = (char *) alloca (p - saved_arg2 + 1);
+ memcpy (copy, saved_arg2, p - saved_arg2);
+ /* Note: if is_quoted should be true, we snuff out quote here
+ anyway. */
+ copy[p - saved_arg2] = '\000';
+ /* Set argptr to skip over the name. */
+ *argptr = (*p == '\'') ? p + 1 : p;
+ /* Look up entire name */
+ sym = lookup_symbol (copy, 0, VAR_NAMESPACE, 0, &sym_symtab);
+ if (sym)
+ return symbol_found (funfirstline, canonical, copy, sym,
+ NULL, sym_symtab);
+
+ /* Couldn't find any interpretation as classes/namespaces, so give
+ up. The quotes are important if copy is empty. */
+ cplusplus_error (saved_arg,
+ "Can't find member of namespace, class, struct, or union named \"%s\"\n",
+ copy);
+}
- /* Discard the file name from the arg. */
- p = p1 + 1;
- while (*p == ' ' || *p == '\t')
- p++;
- *argptr = p;
- }
-#if 0
- /* No one really seems to know why this was added. It certainly
- breaks the command line, though, whenever the passed
- name is of the form ClassName::Method. This bit of code
- singles out the class name, and if funfirstline is set (for
- example, you are setting a breakpoint at this function),
- you get an error. This did not occur with earlier
- verions, so I am ifdef'ing this out. 3/29/99 */
- else
- {
- /* Check if what we have till now is a symbol name */
+/* Next come some helper functions for decode_compound. */
- /* We may be looking at a template instantiation such
- as "foo<int>". Check here whether we know about it,
- instead of falling through to the code below which
- handles ordinary function names, because that code
- doesn't like seeing '<' and '>' in a name -- the
- skip_quoted call doesn't go past them. So see if we
- can figure it out right now. */
+/* Return the symbol corresponding to the substring of *ARGPTR ending
+ at P, allowing whitespace. Also, advance *ARGPTR past the symbol
+ name in question, the compound object separator ("::" or "."), and
+ whitespace. */
- copy = (char *) alloca (p - *argptr + 1);
- memcpy (copy, *argptr, p - *argptr);
- copy[p - *argptr] = '\000';
- sym = lookup_symbol (copy, 0, VAR_NAMESPACE, 0, &sym_symtab);
- if (sym)
- {
- /* Yes, we have a symbol; jump to symbol processing */
- /* Code after symbol_found expects S, SYM_SYMTAB, SYM,
- and COPY to be set correctly */
- *argptr = (*p == '\'') ? p + 1 : p;
- s = (struct symtab *) 0;
- goto symbol_found;
- }
- /* Otherwise fall out from here and go to file/line spec
- processing, etc. */
- }
-#endif
+static struct symbol *
+lookup_prefix_sym (char **argptr, char *p)
+{
+ char *p1;
+ char *copy;
- /* S is specified file's symtab, or 0 if no file specified.
- arg no longer contains the file name. */
+ /* Extract the class name. */
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ')
+ --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ copy[p - *argptr] = 0;
- /* Check whether arg is all digits (and sign) */
+ /* Discard the class name from the arg. */
+ p = p1 + (p1[0] == ':' ? 2 : 1);
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
- q = *argptr;
- if (*q == '-' || *q == '+')
- q++;
- while (*q >= '0' && *q <= '9')
- q++;
+ return lookup_symbol (copy, 0, STRUCT_NAMESPACE, 0,
+ (struct symtab **) NULL);
+}
- if (q != *argptr && (*q == 0 || *q == ' ' || *q == '\t' || *q == ','))
+\f
+
+/* Return the symtab associated to the filename given by the substring
+ of *ARGPTR ending at P, and advance ARGPTR past that filename. */
+
+static struct symtab *
+symtab_from_filename (char **argptr, char *p, int is_quote_enclosed)
+{
+ char *p1;
+ char *copy;
+ struct symtab *file_symtab;
+
+ p1 = p;
+ while (p != *argptr && p[-1] == ' ')
+ --p;
+ if ((*p == '"') && is_quote_enclosed)
+ --p;
+ copy = (char *) alloca (p - *argptr + 1);
+ memcpy (copy, *argptr, p - *argptr);
+ /* It may have the ending quote right after the file name. */
+ if (is_quote_enclosed && copy[p - *argptr - 1] == '"')
+ copy[p - *argptr - 1] = 0;
+ else
+ copy[p - *argptr] = 0;
+
+ /* Find that file's data. */
+ file_symtab = lookup_symtab (copy);
+ if (file_symtab == 0)
{
- /* We found a token consisting of all digits -- at least one digit. */
- enum sign
- {
- none, plus, minus
- }
- sign = none;
+ if (!have_full_symbols () && !have_partial_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
+ error ("No source file named %s.", copy);
+ }
- /* We might need a canonical line spec if no file was specified. */
- int need_canonical = (s == 0) ? 1 : 0;
+ /* Discard the file name from the arg. */
+ p = p1 + 1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ *argptr = p;
- /* This is where we need to make sure that we have good defaults.
- We must guarantee that this section of code is never executed
- when we are called with just a function name, since
- select_source_symtab calls us with such an argument */
+ return file_symtab;
+}
- if (s == 0 && default_symtab == 0)
- {
- select_source_symtab (0);
- default_symtab = current_source_symtab;
- default_line = current_source_line;
- }
+\f
- if (**argptr == '+')
- sign = plus, (*argptr)++;
- else if (**argptr == '-')
- sign = minus, (*argptr)++;
- val.line = atoi (*argptr);
- switch (sign)
- {
- case plus:
- if (q == *argptr)
- val.line = 5;
- if (s == 0)
- val.line = default_line + val.line;
- break;
- case minus:
- if (q == *argptr)
- val.line = 15;
- if (s == 0)
- val.line = default_line - val.line;
- else
- val.line = 1;
- break;
- case none:
- break; /* No need to adjust val.line. */
- }
+/* This decodes a line where the argument is all digits (possibly
+ preceded by a sign). Q should point to the end of those digits;
+ the other arguments are as usual. */
- while (*q == ' ' || *q == '\t')
- q++;
- *argptr = q;
- if (s == 0)
- s = default_symtab;
+static struct symtabs_and_lines
+decode_all_digits (char **argptr, struct symtab *default_symtab,
+ int default_line, char ***canonical,
+ struct symtab *file_symtab, char *q)
- /* It is possible that this source file has more than one symtab,
- and that the new line number specification has moved us from the
- default (in s) to a new one. */
- val.symtab = find_line_symtab (s, val.line, NULL, NULL);
- if (val.symtab == 0)
- val.symtab = s;
+{
+ struct symtabs_and_lines values;
+ struct symtab_and_line val;
- val.pc = 0;
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.sals[0] = val;
- values.nelts = 1;
- if (need_canonical)
- build_canonical_line_spec (values.sals, NULL, canonical);
- return values;
+ enum sign
+ {
+ none, plus, minus
}
+ sign = none;
- /* Arg token is not digits => try it as a variable name
- Find the next token (everything up to end or next whitespace). */
+ /* We might need a canonical line spec if no file was specified. */
+ int need_canonical = (file_symtab == 0) ? 1 : 0;
- if (**argptr == '$') /* May be a convenience variable */
- p = skip_quoted (*argptr + (((*argptr)[1] == '$') ? 2 : 1)); /* One or two $ chars possible */
- else if (is_quoted)
+ init_sal (&val);
+
+ /* This is where we need to make sure that we have good defaults.
+ We must guarantee that this section of code is never executed
+ when we are called with just a function name, since
+ set_default_source_symtab_and_line uses
+ select_source_symtab that calls us with such an argument. */
+
+ if (file_symtab == 0 && default_symtab == 0)
{
- p = skip_quoted (*argptr);
- if (p[-1] != '\'')
- error ("Unmatched single quote.");
+ /* Make sure we have at least a default source file. */
+ set_default_source_symtab_and_line ();
+ initialize_defaults (&default_symtab, &default_line);
}
- else if (has_parens)
+
+ if (**argptr == '+')
+ sign = plus, (*argptr)++;
+ else if (**argptr == '-')
+ sign = minus, (*argptr)++;
+ val.line = atoi (*argptr);
+ switch (sign)
{
- p = pp + 1;
+ case plus:
+ if (q == *argptr)
+ val.line = 5;
+ if (file_symtab == 0)
+ val.line = default_line + val.line;
+ break;
+ case minus:
+ if (q == *argptr)
+ val.line = 15;
+ if (file_symtab == 0)
+ val.line = default_line - val.line;
+ else
+ val.line = 1;
+ break;
+ case none:
+ break; /* No need to adjust val.line. */
}
- else
+
+ while (*q == ' ' || *q == '\t')
+ q++;
+ *argptr = q;
+ if (file_symtab == 0)
+ file_symtab = default_symtab;
+
+ /* It is possible that this source file has more than one symtab,
+ and that the new line number specification has moved us from the
+ default (in file_symtab) to a new one. */
+ val.symtab = find_line_symtab (file_symtab, val.line, NULL, NULL);
+ if (val.symtab == 0)
+ val.symtab = file_symtab;
+
+ val.pc = 0;
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.sals[0] = val;
+ values.nelts = 1;
+ if (need_canonical)
+ build_canonical_line_spec (values.sals, NULL, canonical);
+ return values;
+}
+
+\f
+
+/* Decode a linespec starting with a dollar sign. */
+
+static struct symtabs_and_lines
+decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
+ char ***canonical, struct symtab *file_symtab)
+{
+ struct value *valx;
+ int index = 0;
+ int need_canonical = 0;
+ struct symtabs_and_lines values;
+ struct symtab_and_line val;
+ char *p;
+ struct symbol *sym;
+ /* The symtab that SYM was found in. */
+ struct symtab *sym_symtab;
+ struct minimal_symbol *msymbol;
+
+ p = (copy[1] == '$') ? copy + 2 : copy + 1;
+ while (*p >= '0' && *p <= '9')
+ p++;
+ if (!*p) /* Reached end of token without hitting non-digit. */
{
- p = skip_quoted (*argptr);
+ /* We have a value history reference. */
+ sscanf ((copy[1] == '$') ? copy + 2 : copy + 1, "%d", &index);
+ valx = access_value_history ((copy[1] == '$') ? -index : index);
+ if (TYPE_CODE (VALUE_TYPE (valx)) != TYPE_CODE_INT)
+ error ("History values used in line specs must have integer values.");
}
-
- copy = (char *) alloca (p - *argptr + 1);
- memcpy (copy, *argptr, p - *argptr);
- copy[p - *argptr] = '\0';
- if (p != *argptr
- && copy[0]
- && copy[0] == copy[p - *argptr - 1]
- && strchr (get_gdb_completer_quote_characters (), copy[0]) != NULL)
+ else
{
- copy[p - *argptr - 1] = '\0';
- copy++;
+ /* Not all digits -- may be user variable/function or a
+ convenience variable. */
+
+ /* Look up entire name as a symbol first. */
+ sym = lookup_symbol (copy, 0, VAR_NAMESPACE, 0, &sym_symtab);
+ file_symtab = (struct symtab *) 0;
+ need_canonical = 1;
+ /* Symbol was found --> jump to normal symbol processing. */
+ if (sym)
+ return symbol_found (funfirstline, canonical, copy, sym,
+ NULL, sym_symtab);
+
+ /* If symbol was not found, look in minimal symbol tables. */
+ msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+ /* Min symbol was found --> jump to minsym processing. */
+ if (msymbol)
+ return minsym_found (funfirstline, msymbol);
+
+ /* Not a user variable or function -- must be convenience variable. */
+ need_canonical = (file_symtab == 0) ? 1 : 0;
+ valx = value_of_internalvar (lookup_internalvar (copy + 1));
+ if (TYPE_CODE (VALUE_TYPE (valx)) != TYPE_CODE_INT)
+ error ("Convenience variables used in line specs must have integer values.");
}
- while (*p == ' ' || *p == '\t')
- p++;
- *argptr = p;
- /* If it starts with $: may be a legitimate variable or routine name
- (e.g. HP-UX millicode routines such as $$dyncall), or it may
- be history value, or it may be a convenience variable */
+ init_sal (&val);
- if (*copy == '$')
- {
- struct value *valx;
- int index = 0;
- int need_canonical = 0;
-
- p = (copy[1] == '$') ? copy + 2 : copy + 1;
- while (*p >= '0' && *p <= '9')
- p++;
- if (!*p) /* reached end of token without hitting non-digit */
- {
- /* We have a value history reference */
- sscanf ((copy[1] == '$') ? copy + 2 : copy + 1, "%d", &index);
- valx = access_value_history ((copy[1] == '$') ? -index : index);
- if (TYPE_CODE (VALUE_TYPE (valx)) != TYPE_CODE_INT)
- error ("History values used in line specs must have integer values.");
- }
- else
- {
- /* Not all digits -- may be user variable/function or a
- convenience variable */
-
- /* Look up entire name as a symbol first */
- sym = lookup_symbol (copy, 0, VAR_NAMESPACE, 0, &sym_symtab);
- s = (struct symtab *) 0;
- need_canonical = 1;
- /* Symbol was found --> jump to normal symbol processing.
- Code following "symbol_found" expects "copy" to have the
- symbol name, "sym" to have the symbol pointer, "s" to be
- a specified file's symtab, and sym_symtab to be the symbol's
- symtab. */
- if (sym)
- goto symbol_found;
-
- /* If symbol was not found, look in minimal symbol tables */
- msymbol = lookup_minimal_symbol (copy, NULL, NULL);
- /* Min symbol was found --> jump to minsym processing. */
- if (msymbol)
- goto minimal_symbol_found;
-
- /* Not a user variable or function -- must be convenience variable */
- need_canonical = (s == 0) ? 1 : 0;
- valx = value_of_internalvar (lookup_internalvar (copy + 1));
- if (TYPE_CODE (VALUE_TYPE (valx)) != TYPE_CODE_INT)
- error ("Convenience variables used in line specs must have integer values.");
- }
+ /* Either history value or convenience value from above, in valx. */
+ val.symtab = file_symtab ? file_symtab : default_symtab;
+ val.line = value_as_long (valx);
+ val.pc = 0;
- /* Either history value or convenience value from above, in valx */
- val.symtab = s ? s : default_symtab;
- val.line = value_as_long (valx);
- val.pc = 0;
+ values.sals = (struct symtab_and_line *) xmalloc (sizeof val);
+ values.sals[0] = val;
+ values.nelts = 1;
- values.sals = (struct symtab_and_line *) xmalloc (sizeof val);
- values.sals[0] = val;
- values.nelts = 1;
+ if (need_canonical)
+ build_canonical_line_spec (values.sals, NULL, canonical);
- if (need_canonical)
- build_canonical_line_spec (values.sals, NULL, canonical);
+ return values;
+}
- return values;
- }
+\f
+/* Decode a linespec that's a variable. If FILE_SYMTAB is non-NULL,
+ look in that symtab's static variables first. */
- /* Look up that token as a variable.
- If file specified, use that file's per-file block to start with. */
+static struct symtabs_and_lines
+decode_variable (char *copy, int funfirstline, char ***canonical,
+ struct symtab *file_symtab)
+{
+ struct symbol *sym;
+ /* The symtab that SYM was found in. */
+ struct symtab *sym_symtab;
+
+ struct minimal_symbol *msymbol;
sym = lookup_symbol (copy,
- (s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK)
- : get_selected_block ()),
+ (file_symtab
+ ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab),
+ STATIC_BLOCK)
+ : get_selected_block (0)),
VAR_NAMESPACE, 0, &sym_symtab);
-symbol_found: /* We also jump here from inside the C++ class/namespace
- code on finding a symbol of the form "A::B::C" */
-
if (sym != NULL)
- {
- if (SYMBOL_CLASS (sym) == LOC_BLOCK)
- {
- /* Arg is the name of a function */
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.sals[0] = find_function_start_sal (sym, funfirstline);
- values.nelts = 1;
+ return symbol_found (funfirstline, canonical, copy, sym,
+ file_symtab, sym_symtab);
- /* Don't use the SYMBOL_LINE; if used at all it points to
- the line containing the parameters or thereabouts, not
- the first line of code. */
+ msymbol = lookup_minimal_symbol (copy, NULL, NULL);
- /* We might need a canonical line spec if it is a static
- function. */
- if (s == 0)
- {
- struct blockvector *bv = BLOCKVECTOR (sym_symtab);
- struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
- if (lookup_block_symbol (b, copy, VAR_NAMESPACE) != NULL)
- build_canonical_line_spec (values.sals, copy, canonical);
- }
- return values;
- }
- else
- {
- if (funfirstline)
- error ("\"%s\" is not a function", copy);
- else if (SYMBOL_LINE (sym) != 0)
- {
- /* We know its line number. */
- values.sals = (struct symtab_and_line *)
- xmalloc (sizeof (struct symtab_and_line));
- values.nelts = 1;
- memset (&values.sals[0], 0, sizeof (values.sals[0]));
- values.sals[0].symtab = sym_symtab;
- values.sals[0].line = SYMBOL_LINE (sym);
- return values;
- }
- else
- /* This can happen if it is compiled with a compiler which doesn't
- put out line numbers for variables. */
- /* FIXME: Shouldn't we just set .line and .symtab to zero
- and return? For example, "info line foo" could print
- the address. */
- error ("Line number not known for symbol \"%s\"", copy);
- }
- }
+ if (msymbol != NULL)
+ return minsym_found (funfirstline, msymbol);
- msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+ if (!have_full_symbols () &&
+ !have_partial_symbols () && !have_minimal_symbols ())
+ error ("No symbol table is loaded. Use the \"file\" command.");
-minimal_symbol_found: /* We also jump here from the case for variables
- that begin with '$' */
+ error ("Function \"%s\" not defined.", copy);
+}
- if (msymbol != NULL)
+
+\f
+
+/* Now come some functions that are called from multiple places within
+ decode_line_1. */
+
+/* We've found a symbol SYM to associate with our linespec; build a
+ corresponding struct symtabs_and_lines. */
+
+static struct symtabs_and_lines
+symbol_found (int funfirstline, char ***canonical, char *copy,
+ struct symbol *sym, struct symtab *file_symtab,
+ struct symtab *sym_symtab)
+{
+ struct symtabs_and_lines values;
+
+ if (SYMBOL_CLASS (sym) == LOC_BLOCK)
{
+ /* Arg is the name of a function */
values.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
- values.sals[0] = find_pc_sect_line (SYMBOL_VALUE_ADDRESS (msymbol),
- (struct sec *) 0, 0);
- values.sals[0].section = SYMBOL_BFD_SECTION (msymbol);
- if (funfirstline)
+ values.sals[0] = find_function_start_sal (sym, funfirstline);
+ values.nelts = 1;
+
+ /* Don't use the SYMBOL_LINE; if used at all it points to
+ the line containing the parameters or thereabouts, not
+ the first line of code. */
+
+ /* We might need a canonical line spec if it is a static
+ function. */
+ if (file_symtab == 0)
{
- values.sals[0].pc += FUNCTION_START_OFFSET;
- values.sals[0].pc = SKIP_PROLOGUE (values.sals[0].pc);
+ struct blockvector *bv = BLOCKVECTOR (sym_symtab);
+ struct block *b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+ if (lookup_block_symbol (b, copy, NULL, VAR_NAMESPACE) != NULL)
+ build_canonical_line_spec (values.sals, copy, canonical);
}
- values.nelts = 1;
return values;
}
+ else
+ {
+ if (funfirstline)
+ error ("\"%s\" is not a function", copy);
+ else if (SYMBOL_LINE (sym) != 0)
+ {
+ /* We know its line number. */
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.nelts = 1;
+ memset (&values.sals[0], 0, sizeof (values.sals[0]));
+ values.sals[0].symtab = sym_symtab;
+ values.sals[0].line = SYMBOL_LINE (sym);
+ return values;
+ }
+ else
+ /* This can happen if it is compiled with a compiler which doesn't
+ put out line numbers for variables. */
+ /* FIXME: Shouldn't we just set .line and .symtab to zero
+ and return? For example, "info line foo" could print
+ the address. */
+ error ("Line number not known for symbol \"%s\"", copy);
+ }
+}
- if (!have_full_symbols () &&
- !have_partial_symbols () && !have_minimal_symbols ())
- error ("No symbol table is loaded. Use the \"file\" command.");
+/* We've found a minimal symbol MSYMBOL to associate with our
+ linespec; build a corresponding struct symtabs_and_lines. */
- error ("Function \"%s\" not defined.", copy);
- return values; /* for lint */
+static struct symtabs_and_lines
+minsym_found (int funfirstline, struct minimal_symbol *msymbol)
+{
+ struct symtabs_and_lines values;
+
+ values.sals = (struct symtab_and_line *)
+ xmalloc (sizeof (struct symtab_and_line));
+ values.sals[0] = find_pc_sect_line (SYMBOL_VALUE_ADDRESS (msymbol),
+ (struct sec *) 0, 0);
+ values.sals[0].section = SYMBOL_BFD_SECTION (msymbol);
+ if (funfirstline)
+ {
+ values.sals[0].pc += FUNCTION_START_OFFSET;
+ values.sals[0].pc = SKIP_PROLOGUE (values.sals[0].pc);
+ }
+ values.nelts = 1;
+ return values;
}