#include "defs.h"
#include "symtab.h"
#include "frame.h"
#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"
#include "parser-defs.h"
extern int metrowerks_ignore_breakpoint_errors_flag;
int allow_objc_selectors_flag = 1;
static void initialize_defaults (struct symtab **default_symtab,
int *default_line);
static void set_flags (char *arg, int *is_quoted, char **paren_pointer,
char **if_pointer);
static struct symtabs_and_lines decode_indirect (char **argptr);
static char *locate_first_half (char **argptr, int *is_quote_enclosed);
static char *find_toplevel_char (char *s, char c);
static struct symtabs_and_lines decode_compound (char **argptr,
int funfirstline,
char ***canonical,
char *saved_arg,
char *next_component);
static struct symtabs_and_lines decode_objc (char **argptr,
int funfirstline,
struct symtab *file_symtab,
char ***canonical,
char *saved_arg);
static int examine_compound_token (char **argptr,
int funfirstline,
char ***canonical,
char *saved_arg,
char *p,
struct symtabs_and_lines *values);
static struct symbol *locate_class_sym (char **argptr, char *p);
static char *find_next_token (char **argptr);
static int total_number_of_methods (struct type *type);
static struct symtabs_and_lines find_method (int funfirstline,
char ***canonical,
char *saved_arg,
char *method,
struct type *class_type,
struct symbol *class_sym);
static int count_methods (struct type *class_type, char *method,
struct symbol **sym_arr);
static int find_methods (struct type *class_type, char *method,
struct symbol **sym_arr);
static const char *find_method_name (struct type *class_type,
int method_counter,
char *dem_opname);
static int add_matching_methods (int method_counter, struct type *class_type,
struct symbol **sym_arr);
static int add_constructors (int method_counter, struct type *class_type,
struct symbol **sym_arr);
static struct symtabs_and_lines select_symbols (struct symbol **sym_arr,
int nelts,
int nsyms,
int funfirstline,
char ***canonical);
static struct
symtabs_and_lines select_symbols_args (struct symbol **sym_arr,
int nelts,
int nsyms,
char *args,
char **canonical_arr,
struct symtabs_and_lines values,
struct cleanup *old_chain);
static NORETURN void cplusplus_error (const char *name,
const char *fmt, ...)
ATTR_NORETURN ATTR_FORMAT (printf, 2, 3);
static struct symtab *handle_filename (char **argptr, char *filename_end,
int is_quote_enclosed);
static int is_all_digits (char *arg);
static struct
symtabs_and_lines decode_all_digits (char **argptr,
int funfirstline,
struct symtab *default_symtab,
int default_line,
char ***canonical,
struct symtab *file_symtab);
static char *skip_digits (char *arg);
static struct symtabs_and_lines decode_dollar (char **argptr,
int funfirstline,
struct symtab *default_symtab,
char ***canonical,
struct symtab *file_symtab);
static struct symtabs_and_lines decode_variable (char **argptr,
int funfirstline,
char ***canonical,
int is_quoted,
char *paren_pointer,
struct symtab *file_symtab);
static void build_canonical_line_spec (struct symtab_and_line *sal,
char *symname,
char ***canonical);
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);
struct symtabs_and_lines
decode_line_2 (char **argptr, int funfirstline, struct symtab *default_symtab,
int default_line, char ***canonical,
int is_quoted, char *paren_pointer)
{
struct symtab *file_symtab = NULL;
char *saved_arg = *argptr;
if (**argptr == '*')
return decode_indirect (argptr);
{
struct symtabs_and_lines values;
values = decode_objc (argptr, funfirstline, file_symtab,
canonical, saved_arg);
if (values.sals != NULL)
return values;
}
{
char *p;
int is_quote_enclosed;
p = locate_first_half (argptr, &is_quote_enclosed);
if ((p[0] == ':' || p[0] == '.') && paren_pointer == NULL)
{
if (is_quoted)
*argptr = *argptr + 1;
if (p[0] == '.' || p[1] == ':')
return decode_compound (argptr, funfirstline, canonical,
saved_arg, p);
file_symtab = handle_filename (argptr, p, is_quote_enclosed);
}
}
if (is_all_digits (*argptr))
return decode_all_digits (argptr, funfirstline, default_symtab,
default_line, canonical, file_symtab);
if (**argptr == '$')
return decode_dollar (argptr, funfirstline, default_symtab, canonical,
file_symtab);
return decode_variable (argptr, funfirstline, canonical, is_quoted,
paren_pointer, file_symtab);
}
struct symtabs_and_lines
decode_line_1 (char **argptr, int funfirstline, struct symtab *default_symtab,
int default_line, char ***canonical)
{
int is_quoted;
char *paren_pointer;
char *if_pointer;
struct symtabs_and_lines values;
initialize_defaults (&default_symtab, &default_line);
set_flags (*argptr, &is_quoted, &paren_pointer, &if_pointer);
if (if_pointer != NULL)
*if_pointer = '\0';
values = decode_line_2 (argptr, funfirstline, default_symtab, default_line,
canonical, is_quoted, paren_pointer);
if (if_pointer != NULL)
*if_pointer = ' ';
return values;
}
static void
initialize_defaults (struct symtab **default_symtab, int *default_line)
{
if (*default_symtab == NULL)
{
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 **if_pointer)
{
char *if_index;
char *paren_start;
int has_if = 0;
if ((if_index = strstr (arg, " if ")) != NULL ||
(if_index = strstr (arg, "\tif ")) != NULL ||
(if_index = strstr (arg, " if\t")) != NULL ||
(if_index = strstr (arg, "\tif\t")) != NULL ||
(if_index = strstr (arg, " if(")) != NULL ||
(if_index = strstr (arg, "\tif( ")) != NULL)
has_if = 1;
if (has_if)
{
*if_index = '\0';
}
*is_quoted = (*arg && (strchr (get_gdb_completer_quote_characters (),
*arg)
!= NULL));
paren_start = strchr (arg, '(');
if (paren_start != NULL)
*paren_pointer = strrchr (paren_start, ')');
else
*paren_pointer = NULL;
if (has_if)
{
*if_pointer = if_index;
*if_index = ' ';
}
else
*if_pointer = NULL;
}
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 = 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;
}
static char *
locate_first_half (char **argptr, int *is_quote_enclosed)
{
char *comma_index;
char *p, *p1;
int has_comma;
comma_index = find_toplevel_char (*argptr, ',');
has_comma = (comma_index != NULL);
if (has_comma)
{
*comma_index = '\0';
}
p = *argptr;
if (p[0] == '"')
{
*is_quote_enclosed = 1;
(*argptr)++;
p++;
}
else
*is_quote_enclosed = 0;
for (; *p; p++)
{
if (p[0] == '<')
{
char *temp_end = find_template_name_end (p);
if (!temp_end)
error ("malformed template specification in command");
p = temp_end;
}
if (!*p
|| p[0] == '\t'
|| ((p[0] == ':')
&& ((p[1] == ':') || (strchr (p + 1, ':') == NULL)))
|| ((p[0] == ' ') && !*is_quote_enclosed))
break;
if (p[0] == '.' && strchr (p, ':') == NULL)
{
for (p1 = p; *p1; p1++)
{
if (*p1 == '.')
p = p1;
}
break;
}
}
while (p[0] == ' ' || p[0] == '\t')
p++;
if (*is_quote_enclosed)
{
char *closing_quote = strchr (p - 1, '"');
if (closing_quote != NULL && closing_quote[1] == '\0')
*closing_quote = '\0';
}
if (has_comma)
*comma_index = ',';
return p;
}
static char *
find_toplevel_char (char *s, char c)
{
char quoted = 0;
int depth = 0;
char *scan;
for (scan = s; *scan; scan++)
{
if (quoted)
{
if (*scan == quoted)
quoted = 0;
else if (*scan == '\\' && *(scan + 1))
scan++;
}
else if (*scan == c && !quoted && depth == 0)
return scan;
else if (*scan == '"' || *scan == '\'')
quoted = *scan;
else if (*scan == '(' || *scan == '<')
depth++;
else if ((*scan == ')' || *scan == '>') && depth > 0)
depth--;
}
return NULL;
}
static struct symtabs_and_lines
decode_compound (char **argptr, int funfirstline, char ***canonical,
char *saved_arg, char *next_component)
{
char *saved_arg2 = *argptr;
char *temp_end;
char *copy;
struct symtab *sym_symtab;
struct symbol *sym;
if (next_component[0] == ':'
&& ((*argptr == next_component)
|| (next_component[-1] == ' ')
|| (next_component[-1] == '\t')))
saved_arg2 += 2;
while (1)
{
struct symtabs_and_lines values;
char *current_component = next_component;
if (examine_compound_token (argptr, funfirstline, canonical,
saved_arg, next_component, &values))
return values;
next_component = current_component + 1;
while (*next_component
&& (next_component[0] != ' ')
&& (next_component[0] != '\t')
&& (next_component[0] != '\''))
{
if (next_component[0] == '<')
{
temp_end = find_template_name_end (next_component);
if (!temp_end)
error ("malformed template specification in command");
next_component = temp_end;
}
else if ((next_component[0] == ':')
&& (next_component[1] == ':'))
break;
else
next_component++;
}
if (*next_component != ':')
break;
*argptr = saved_arg2;
}
copy = alloca (next_component - saved_arg2 + 1);
memcpy (copy, saved_arg2, next_component - saved_arg2);
copy[next_component - saved_arg2] = '\0';
*argptr = (*next_component == '\'') ? next_component + 1 : next_component;
sym = lookup_symbol (copy, 0, VAR_NAMESPACE, 0, &sym_symtab);
if (sym != NULL)
return symbol_found (funfirstline, canonical, copy,
sym, NULL, sym_symtab);
cplusplus_error (saved_arg,
"Can't find member of namespace, class, struct, or union named \"%s\"\n",
copy);
}
struct symtabs_and_lines
decode_objc (char **argptr, int funfirstline, struct symtab *file_symtab,
char ***canonical, char *saved_arg)
{
struct symtabs_and_lines values;
struct symbol **sym_arr = NULL;
struct symbol *sym = NULL;
char *copy = NULL;
struct block *block = NULL;
int i1 = 0;
int i2 = 0;
values.sals = NULL;
values.nelts = 0;
if (! allow_objc_selectors_flag)
return values;
if (file_symtab != NULL)
block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab), STATIC_BLOCK);
else
block = get_selected_block (0);
copy = find_imps (file_symtab, block, *argptr, NULL, &i1, &i2);
if (i1 > 0)
{
sym_arr = (struct symbol **) alloca ((i1 + 1) * sizeof (struct symbol *));
sym_arr[i1] = 0;
copy = find_imps (file_symtab, block, *argptr, sym_arr, &i1, &i2);
*argptr = copy;
}
if (i1 == 1)
{
if (i2 > 0)
{
sym = sym_arr[0];
}
else
{
sym = find_pc_function (SYMBOL_VALUE_ADDRESS (sym_arr[0]));
if ((sym != NULL) && strcmp (SYMBOL_NAME (sym_arr[0]), SYMBOL_NAME (sym)) != 0)
{
warning ("debugging symbol \"%s\" does not match selector; ignoring", SYMBOL_NAME (sym));
sym = NULL;
}
}
values.sals = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line));
values.nelts = 1;
if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK)
{
values.sals[0] = find_function_start_sal (sym, funfirstline);
build_canonical_line_spec (values.sals, SYMBOL_SOURCE_NAME (sym), canonical);
}
else
{
values.sals[0].symtab = 0;
values.sals[0].line = 0;
values.sals[0].end = 0;
values.sals[0].pc = SYMBOL_VALUE_ADDRESS (sym_arr[0]);
}
return values;
}
if (i1 > 1)
{
return select_symbols (sym_arr, i1, i2, funfirstline, canonical);
}
return values;
}
static int
examine_compound_token (char **argptr, int funfirstline,
char ***canonical,
char *saved_arg, char *current_component,
struct symtabs_and_lines *values)
{
char *copy;
struct symbol *class_sym;
struct type *t;
class_sym = locate_class_sym (argptr, current_component);
if (class_sym == NULL)
return 0;
t = check_typedef (SYMBOL_TYPE (class_sym));
switch (TYPE_CODE (t))
{
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
current_component = find_next_token (argptr);
copy = alloca (current_component - *argptr + 1);
memcpy (copy, *argptr, current_component - *argptr);
copy[current_component - *argptr] = '\0';
if (current_component != *argptr
&& copy[current_component - *argptr - 1]
&& (strchr (get_gdb_completer_quote_characters (),
copy[current_component - *argptr - 1])
!= NULL))
copy[current_component - *argptr - 1] = '\0';
while (*current_component == ' ' || *current_component == '\t')
current_component++;
*argptr = current_component;
*values = find_method (funfirstline, canonical, saved_arg, copy,
t, class_sym);
return 1;
#if 0
case TYPE_CODE_NAMESPACE:
return 0;
#endif
default:
return 0;
}
}
static struct symbol *
locate_class_sym (char **argptr, char *p)
{
char *p1;
char *copy;
p1 = p;
while (p != *argptr && p[-1] == ' ')
--p;
copy = alloca (p - *argptr + 1);
memcpy (copy, *argptr, p - *argptr);
copy[p - *argptr] = 0;
p = p1 + (p1[0] == ':' ? 2 : 1);
while (*p == ' ' || *p == '\t')
p++;
*argptr = p;
return lookup_symbol (copy, NULL, STRUCT_NAMESPACE, NULL, NULL);
}
static char *
find_next_token (char **argptr)
{
char *p;
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++;
}
return p;
}
static int
total_number_of_methods (struct type *type)
{
int n;
int count;
CHECK_TYPEDEF (type);
if (TYPE_CPLUS_SPECIFIC (type) == NULL)
return 0;
count = TYPE_NFN_FIELDS_TOTAL (type);
for (n = 0; n < TYPE_N_BASECLASSES (type); n++)
count += total_number_of_methods (TYPE_BASECLASS (type, n));
return count;
}
static struct symtabs_and_lines
find_method (int funfirstline, char ***canonical, char *saved_arg,
char *method, struct type *class_type,
struct symbol *class_sym)
{
struct symtabs_and_lines values;
struct symbol **sym_arr;
int method_count;
sym_arr = alloca (total_number_of_methods (class_type)
* sizeof (struct symbol *));
method_count = count_methods (class_type, method, sym_arr);
if (method_count == 1)
{
struct symbol *sym = sym_arr[0];
if (sym != NULL && SYMBOL_CLASS (sym) == LOC_BLOCK)
{
values.sals = xmalloc (sizeof (struct symtab_and_line));
values.nelts = 1;
values.sals[0] = find_function_start_sal (sym, funfirstline);
}
else
{
values.nelts = 0;
}
}
else if (method_count > 0)
{
values = select_symbols (sym_arr, method_count, method_count, funfirstline, canonical);
}
else
{
char *tmp;
if (is_operator_name (method))
{
tmp = alloca (strlen (method + 3) + 9);
strcpy (tmp, "operator ");
strcat (tmp, method + 3);
}
else
tmp = method;
if (tmp[0] == '~')
cplusplus_error (saved_arg,
"the class `%s' does not have destructor defined\n",
SYMBOL_SOURCE_NAME (class_sym));
else
cplusplus_error (saved_arg,
"the class %s does not have any method named %s\n",
SYMBOL_SOURCE_NAME (class_sym), tmp);
}
return values;
}
static int
count_methods (struct type *class_type, char *method,
struct symbol **sym_arr)
{
int count = 0;
if (destructor_name_p (method, class_type))
{
int m_index, f_index;
if (get_destructor_fn_field (class_type, &m_index, &f_index))
{
struct fn_field *f = TYPE_FN_FIELDLIST1 (class_type, m_index);
sym_arr[count] =
lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, f_index),
NULL, VAR_NAMESPACE, NULL, NULL);
if (sym_arr[count])
count++;
}
}
else
count = find_methods (class_type, method, sym_arr);
return count;
}
static int
find_methods (struct type *class_type, char *method,
struct symbol **sym_arr)
{
int count = 0;
int ibase;
const char *class_name = type_name_no_tag (class_type);
if (class_name != NULL
&& (lookup_symbol (class_name, NULL, STRUCT_NAMESPACE, NULL,
NULL) != NULL))
{
int method_counter;
int name_len = strlen (method);
check_typedef (class_type);
for (method_counter = TYPE_NFN_FIELDS (class_type) - 1;
method_counter >= 0;
--method_counter)
{
int field_counter;
char dem_opname[64];
const char *current_method_name
= find_method_name (class_type, method_counter, dem_opname);
if (strcmp_iw (method, current_method_name) == 0)
count += add_matching_methods (method_counter, class_type,
sym_arr + count);
else if (strncmp (class_name, method, name_len) == 0
&& (class_name[name_len] == '\0'
|| class_name[name_len] == '<'))
count += add_constructors (method_counter, class_type,
sym_arr + count);
}
}
if (count == 0)
for (ibase = 0; ibase < TYPE_N_BASECLASSES (class_type); ibase++)
count += find_methods (TYPE_BASECLASS (class_type, ibase), method,
sym_arr + count);
return count;
}
static const char *
find_method_name (struct type *class_type, int method_counter,
char *dem_opname)
{
const char *name = TYPE_FN_FIELDLIST_NAME (class_type, method_counter);
if (strncmp (name, "__", 2) == 0
|| strncmp (name, "op", 2) == 0
|| strncmp (name, "type", 4) == 0)
{
if (cplus_demangle_opname (name, dem_opname, DMGL_ANSI))
name = dem_opname;
else if (cplus_demangle_opname (name, dem_opname, 0))
name = dem_opname;
}
return name;
}
static int
add_matching_methods (int method_counter, struct type *class_type,
struct symbol **sym_arr)
{
int field_counter;
int count = 0;
for (field_counter
= TYPE_FN_FIELDLIST_LENGTH (class_type, method_counter) - 1;
field_counter >= 0;
--field_counter)
{
struct fn_field *f;
char *phys_name;
f = TYPE_FN_FIELDLIST1 (class_type, method_counter);
if (TYPE_FN_FIELD_STUB (f, field_counter))
{
char *tmp_name;
tmp_name = gdb_mangle_name (class_type, method_counter,
field_counter);
phys_name = alloca (strlen (tmp_name) + 1);
strcpy (phys_name, tmp_name);
xfree (tmp_name);
}
else
phys_name = TYPE_FN_FIELD_PHYSNAME (f, field_counter);
if (is_destructor_name (phys_name) != 0)
continue;
sym_arr[count] = lookup_symbol (phys_name, NULL, VAR_NAMESPACE,
NULL, NULL);
if (sym_arr[count])
count++;
else
{
}
}
return count;
}
static int
add_constructors (int method_counter, struct type *class_type,
struct symbol **sym_arr)
{
int field_counter;
int count = 0;
for (field_counter
= TYPE_FN_FIELDLIST_LENGTH (class_type, method_counter) - 1;
field_counter >= 0;
--field_counter)
{
struct fn_field *f;
char *phys_name;
f = TYPE_FN_FIELDLIST1 (class_type, method_counter);
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;
sym_arr[count] = lookup_symbol (phys_name, NULL, VAR_NAMESPACE,
NULL, NULL);
if (sym_arr[count])
count++;
}
return count;
}
static struct symtabs_and_lines
select_symbols (struct symbol **sym_arr, int nelts, int nsyms, int funfirstline,
char ***canonical)
{
struct symtabs_and_lines values, return_values;
char *args, *arg1;
int i;
char *prompt;
char *symname;
struct cleanup *old_chain = NULL;
char **canonical_arr = NULL;
values.sals = alloca (nelts * sizeof (struct symtab_and_line));
if (canonical)
{
canonical_arr = xmalloc (nelts * sizeof (char *));
old_chain = make_cleanup (xfree, canonical_arr);
memset (canonical_arr, 0, nelts * sizeof (char *));
*canonical = canonical_arr;
}
printf_unfiltered ("[0] cancel\n[1] all\n");
for (i = 0; i < nsyms; i++)
{
QUIT;
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);
printf_unfiltered ("[%d] %s at %s:%d\n",
(i + 2),
SYMBOL_SOURCE_NAME (sym_arr[i]),
values.sals[i].symtab->filename,
values.sals[i].line);
}
else
printf_filtered ("[%d] %s\n",
(i + 2),
SYMBOL_SOURCE_NAME (sym_arr[i]) ?
SYMBOL_SOURCE_NAME (sym_arr[i]) : "?HERE?");
}
if (nelts != nsyms)
printf_filtered ("\nNon-debugging symbols:\n");
for (i = nsyms; i < nelts; i++)
{
QUIT;
values.sals[i].symtab = 0;
values.sals[i].line = 0;
values.sals[i].end = 0;
values.sals[i].pc = SYMBOL_VALUE_ADDRESS (sym_arr[i]);
printf_filtered ("[%d] %s\n",
(i + 2),
SYMBOL_SOURCE_NAME (sym_arr[i]));
}
if ((prompt = getenv ("PS2")) == NULL)
{
prompt = "> ";
}
args = command_line_input (prompt, 0, "overload-choice");
if (args == 0 || *args == 0)
error_no_arg ("one or more choice numbers");
return select_symbols_args (sym_arr, nelts, nsyms, args, canonical_arr,
values, old_chain);
}
static struct symtabs_and_lines
select_symbols_args (struct symbol **sym_arr, int nelts, int nsyms,
char *args, char **canonical_arr,
struct symtabs_and_lines values,
struct cleanup *old_chain)
{
struct symtabs_and_lines return_values;
struct cleanup *new_chain;
int i;
return_values.sals = xmalloc (nelts * sizeof (struct symtab_and_line));
new_chain = make_cleanup (xfree, return_values.sals);
if (old_chain == NULL)
old_chain = new_chain;
for (i = 0; i < nelts; ++i)
init_sal (&return_values.sals[i]);
i = 0;
while (*args)
{
int num;
char *arg1;
arg1 = args;
while (*arg1 >= '0' && *arg1 <= '9')
arg1++;
if (*arg1 && *arg1 != ' ' && *arg1 != '\t')
error ("Arguments must be choice numbers.");
num = atoi (args);
if (num == 0)
error ("cancelled");
else if (num == 1)
{
if (canonical_arr != NULL)
{
int j;
for (j = 0; j < nelts; j++)
{
if (canonical_arr[j] == NULL)
{
char *symname = NULL;
if (values.sals[j].symtab)
{
symname = xmalloc
(strlen (values.sals[j].symtab->filename) + 30);
sprintf (symname, "%s:%d",
values.sals[j].symtab->filename,
values.sals[j].line);
}
else
{
symname = SYMBOL_NAME (sym_arr[j]);
}
canonical_arr[j]
= savestring (symname, strlen (symname));
}
}
}
memcpy (return_values.sals, values.sals,
(nelts * sizeof (struct symtab_and_line)));
return_values.nelts = nelts;
discard_cleanups (old_chain);
return return_values;
}
if (num >= nelts + 2)
{
printf_unfiltered ("No choice number %d.\n", num);
}
else
{
num -= 2;
if (values.sals[num].pc)
{
if (canonical_arr != NULL)
{
char *symname = NULL;
if (values.sals[num].symtab)
{
symname = xmalloc
(strlen (values.sals[num].symtab->filename) + 30);
sprintf (symname, "%s:%d",
values.sals[num].symtab->filename,
values.sals[num].line);
}
else
{
symname = SYMBOL_NAME (sym_arr[num]);
}
canonical_arr[i] = savestring (symname, strlen (symname));
}
return_values.sals[i++] = values.sals[num];
values.sals[num].pc = 0;
}
else
{
printf_filtered ("duplicate request for %d ignored.\n", num);
}
}
args = arg1;
while (*args == ' ' || *args == '\t')
args++;
}
return_values.nelts = i;
discard_cleanups (old_chain);
return return_values;
}
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++;
fprintf_unfiltered (tmp_stream,
("Hint: try '%s<TAB> or '%s<ESC-?>\n"
"(Note leading single quote.)"),
name, name);
error_stream (tmp_stream);
}
static struct symtab *
handle_filename (char **argptr, char *filename_end, int is_quote_enclosed)
{
char *saved_filename_end;
char *copy;
struct symtab *file_symtab;
saved_filename_end = filename_end;
while (filename_end != *argptr && filename_end[-1] == ' ')
--filename_end;
if ((*filename_end == '"') && is_quote_enclosed)
--filename_end;
copy = alloca (filename_end - *argptr + 1);
memcpy (copy, *argptr, filename_end - *argptr);
if (is_quote_enclosed && copy[filename_end - *argptr - 1] == '"')
copy[filename_end - *argptr - 1] = 0;
else
copy[filename_end - *argptr] = 0;
file_symtab = lookup_symtab (copy);
if (file_symtab == NULL)
{
if (!have_full_symbols () && !have_partial_symbols ())
error ("No symbol table is loaded. Use the \"file\" command.");
error ("No source file named %s.", copy);
}
filename_end = saved_filename_end + 1;
while (*filename_end == ' ' || *filename_end == '\t')
filename_end++;
*argptr = filename_end;
return file_symtab;
}
void
reset_allow_objc_selectors_flag (PTR dummy)
{
allow_objc_selectors_flag = 1;
}
static int
is_all_digits (char *arg)
{
char *q = skip_digits (arg);
return q != arg && (*q == 0 || *q == ' ' || *q == '\t' || *q == ',');
}
static struct symtabs_and_lines
decode_all_digits (char **argptr, int funfirstline,
struct symtab *default_symtab,
int default_line, char ***canonical,
struct symtab *file_symtab)
{
struct symtabs_and_lines values;
struct symtab_and_line val;
char *end_of_digits = skip_digits (*argptr);
int need_canonical;
enum sign
{
none, plus, minus
}
sign = none;
need_canonical = (file_symtab == NULL) ? 1 : 0;
init_sal (&val);
if (file_symtab == NULL && default_symtab == NULL)
{
set_default_source_symtab_and_line ();
initialize_defaults (&default_symtab, &default_line);
}
if (**argptr == '+')
sign = plus, (*argptr)++;
else if (**argptr == '-')
sign = minus, (*argptr)++;
val.line = atoi (*argptr);
switch (sign)
{
case plus:
if (end_of_digits == *argptr)
val.line = 5;
if (file_symtab == NULL)
val.line = default_line + val.line;
break;
case minus:
if (end_of_digits == *argptr)
val.line = 15;
if (file_symtab == NULL)
val.line = default_line - val.line;
else
val.line = 1;
break;
case none:
break;
}
while (*end_of_digits == ' ' || *end_of_digits == '\t')
end_of_digits++;
*argptr = end_of_digits;
if (file_symtab == NULL)
file_symtab = default_symtab;
val.symtab = find_line_symtab (file_symtab, val.line, NULL, NULL);
if (val.symtab == NULL)
val.symtab = file_symtab;
val.pc = 0;
if (funfirstline)
{
CORE_ADDR pc = 0;
if (find_line_pc (val.symtab, val.line, &pc))
{
struct symbol *func_sym;
struct symtab_and_line sal;
func_sym = find_pc_function (pc);
if (func_sym)
{
sal = find_function_start_sal (func_sym, 1);
if (val.line <= sal.line)
val.pc = sal.pc;
}
}
}
values.sals = 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;
}
static char *
skip_digits (char *arg)
{
if (*arg == '-' || *arg == '+')
arg++;
while (*arg >= '0' && *arg <= '9')
arg++;
return arg;
}
static struct symtabs_and_lines
decode_dollar (char **argptr, int funfirstline, struct symtab *default_symtab,
char ***canonical, struct symtab *file_symtab)
{
struct value *valx;
int index = 0;
int need_canonical = 0;
char *p;
struct symtabs_and_lines values;
char *copy;
p = skip_quoted (*argptr + (((*argptr)[1] == '$') ? 2 : 1));
copy = alloca (p - *argptr + 1);
memcpy (copy, *argptr, p - *argptr);
copy[p - *argptr] = '\0';
while (*p == ' ' || *p == '\t')
p++;
*argptr = p;
p = (copy[1] == '$') ? copy + 2 : copy + 1;
while (*p >= '0' && *p <= '9')
p++;
if (!*p)
{
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
{
struct symbol *sym;
struct symtab *sym_symtab;
struct minimal_symbol *msymbol;
sym = lookup_symbol (copy, 0, VAR_NAMESPACE, 0, &sym_symtab);
if (sym != NULL)
return symbol_found (funfirstline, canonical, copy,
sym, NULL, sym_symtab);
msymbol = lookup_minimal_symbol (copy, NULL, NULL);
if (msymbol != NULL)
return minsym_found (funfirstline, msymbol);
file_symtab = NULL;
need_canonical = 1;
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.");
}
values.sals = xmalloc (sizeof (struct symtab_and_line));
init_sal (values.sals);
values.sals[0].symtab = file_symtab != NULL ? file_symtab : default_symtab;
values.sals[0].line = value_as_long (valx);
values.sals[0].pc = 0;
values.nelts = 1;
if (need_canonical)
build_canonical_line_spec (values.sals, NULL, canonical);
return values;
}
static struct symtabs_and_lines
decode_variable (char **argptr, int funfirstline, char ***canonical,
int is_quoted, char *paren_pointer,
struct symtab *file_symtab)
{
char *p;
char *copy;
struct symbol *sym;
struct symtab *sym_symtab;
struct minimal_symbol *msymbol;
if (is_quoted)
{
p = skip_quoted (*argptr);
if (p[-1] != '\'')
error ("Unmatched single quote.");
}
#if 0
else if (paren_pointer != NULL)
{
p = paren_pointer + 1;
}
#endif
else
{
p = skip_quoted_chars (*argptr, NULL, "");
}
copy = 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;
sym = lookup_symbol (copy,
(file_symtab != NULL
? BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab),
STATIC_BLOCK)
: get_selected_block (0)),
VAR_NAMESPACE, NULL, &sym_symtab);
if (sym != NULL)
{
return symbol_found (funfirstline, canonical, copy,
sym, file_symtab, sym_symtab);
}
msymbol = lookup_minimal_symbol (copy, NULL, NULL);
if (msymbol != NULL)
return minsym_found (funfirstline, msymbol);
if (!have_full_symbols () &&
!have_partial_symbols () && !have_minimal_symbols ())
error ("No symbol table is loaded. Use the \"file\" command.");
if (metrowerks_ignore_breakpoint_errors_flag)
{
struct symtabs_and_lines values;
values.sals = NULL;
return values;
}
if (file_symtab == NULL)
error ("Function \"%s\" not defined.", copy);
else
error ("Function \"%s\" not defined in file %s.",
copy, file_symtab->filename);
}
static void
build_canonical_line_spec (struct symtab_and_line *sal, char *symname,
char ***canonical)
{
char **canonical_arr;
char *canonical_name;
char *filename;
struct symtab *sal_symtab = sal->symtab;
if (sal_symtab == NULL
|| sal_symtab->filename == NULL
|| canonical == NULL)
return;
canonical_arr = xmalloc (sizeof (char *));
*canonical = canonical_arr;
filename = sal_symtab->filename;
if (symname != NULL)
{
if ((strstr (symname, "::") != NULL)
|| (((symname[0] == '-') || (symname[0] == '+')) && (symname[1] == '[')))
{
canonical_name = xmalloc (strlen (symname) + 1);
sprintf (canonical_name, "%s", symname);
}
else
{
canonical_name = xmalloc (strlen (filename) + strlen (symname) + 2);
sprintf (canonical_name, "%s:%s", filename, symname);
}
}
else
{
canonical_name = xmalloc (strlen (filename) + 30);
sprintf (canonical_name, "%s:%d", filename, sal->line);
}
canonical_arr[0] = canonical_name;
}
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)
{
values.sals = xmalloc (sizeof (struct symtab_and_line));
values.sals[0] = find_function_start_sal (sym, funfirstline);
values.nelts = 1;
if (file_symtab == NULL)
{
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);
}
return values;
}
else
{
if (funfirstline)
error ("\"%s\" is not a function", copy);
else if (SYMBOL_LINE (sym) != 0)
{
values.sals = 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
error ("Line number not known for symbol \"%s\"", copy);
}
}
static struct symtabs_and_lines
minsym_found (int funfirstline, struct minimal_symbol *msymbol)
{
struct symtabs_and_lines values;
values.sals = xmalloc (sizeof (struct symtab_and_line));
values.sals[0] = find_pc_sect_line (SYMBOL_VALUE_ADDRESS (msymbol),
NULL, 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;
}