+/* 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.
+ If ARGPTR is just a simple name like "main", p will point to ""
+ at the end. */
+
+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
+ for the second half.
+
+ Don't count commas that appear in argument lists of overloaded
+ functions, or in quoted strings. It's stupid to go to this much
+ trouble when the rest of the function is such an obvious roach hotel. */
+ 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!! */
+ 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 <>. */
+
+ 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;
+ }
+ /* Check for a colon and a plus or minus and a [ (which
+ indicates an Objective-C method) */
+ if (is_objc_method_format (p))
+ {
+ break;
+ }
+ /* 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))
+ break;
+ if (p[0] == '.' && strchr (p, ':') == NULL)
+ {
+ /* Java qualified method. Find the *last* '.', since the
+ others are package qualifiers. */
+ for (p1 = p; *p1; p1++)
+ {
+ if (*p1 == '.')
+ p = p1;
+ }
+ break;
+ }
+ }
+ while (p[0] == ' ' || p[0] == '\t')
+ p++;
+
+ /* 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. */
+ if (has_comma)
+ *ii = ',';
+
+ return p;
+}
+
+\f
+
+/* Here's where we recognise an Objective-C Selector. An Objective C
+ selector may be implemented by more than one class, therefore it
+ may represent more than one method/function. This gives us a
+ situation somewhat analogous to C++ overloading. If there's more
+ than one method that could represent the selector, then use some of
+ the existing C++ code to let the user choose one. */
+
+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;
+ unsigned i1 = 0;
+ unsigned i2 = 0;
+
+ values.sals = NULL;
+ values.nelts = 0;
+
+ 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;
+ }
+
+ /* i1 now represents the TOTAL number of matches found.
+ i2 represents how many HIGH-LEVEL (struct symbol) matches,
+ which will come first in the sym_arr array. Any low-level
+ (minimal_symbol) matches will follow those. */
+
+ if (i1 == 1)
+ {
+ if (i2 > 0)
+ {
+ /* Already a struct symbol. */
+ sym = sym_arr[0];
+ }
+ else
+ {
+ sym = find_pc_function (SYMBOL_VALUE_ADDRESS (sym_arr[0]));
+ if ((sym != NULL) && strcmp (SYMBOL_LINKAGE_NAME (sym_arr[0]), SYMBOL_LINKAGE_NAME (sym)) != 0)
+ {
+ warning (_("debugging symbol \"%s\" does not match selector; ignoring"), SYMBOL_LINKAGE_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)
+ {
+ /* Canonicalize this, so it remains resolved for dylib loads. */
+ values.sals[0] = find_function_start_sal (sym, funfirstline);
+ build_canonical_line_spec (values.sals, SYMBOL_NATURAL_NAME (sym), canonical);
+ }
+ else
+ {
+ /* The only match was a non-debuggable symbol. */
+ 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)
+ {
+ /* More than one match. The user must choose one or more. */
+ return decode_line_2 (sym_arr, i2, funfirstline, canonical);
+ }
+
+ return values;
+}
+
+/* This handles C++ and Java compound data structures. P should point
+ at the first component separator, i.e. double-colon or period. As
+ an example, on entrance to this function we could have ARGPTR
+ pointing to "AAA::inA::fun" and P pointing to "::inA::fun". */
+
+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;
+ 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;
+ 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. I.e. the whole line specification starts with
+ "::" (note the condition that *argptr == p). */
+ if (p[0] == ':'
+ && ((*argptr == p) || (p[-1] == ' ') || (p[-1] == '\t')))
+ saved_arg2 += 2;
+
+ /* Given our example "AAA::inA::fun", we have two cases to consider:
+
+ 1) AAA::inA is the name of a class. In that case, presumably it
+ has a method called "fun"; we then look up that method using
+ find_method.
+
+ 2) AAA::inA isn't the name of a class. In that case, either the
+ user made a typo or AAA::inA is the name of a namespace.
+ Either way, we just look up AAA::inA::fun with lookup_symbol.
+
+ Thus, our first task is to find everything before the last set of
+ double-colons and figure out if it's the name of a class. So we
+ first loop through all of the double-colons. */
+
+ p2 = p; /* Save for restart. */
+
+ /* This is very messy. Following the example above we have now the
+ following pointers:
+ p -> "::inA::fun"
+ argptr -> "AAA::inA::fun
+ saved_arg -> "AAA::inA::fun
+ saved_arg2 -> "AAA::inA::fun
+ p2 -> "::inA::fun". */
+
+ /* In the loop below, with these strings, we'll make 2 passes, each
+ is marked in comments.*/
+
+ while (1)
+ {
+ /* Move pointer up to next possible class/namespace token. */
+
+ p = p2 + 1; /* Restart with old value +1. */
+
+ /* PASS1: at this point p2->"::inA::fun", so p->":inA::fun",
+ i.e. if there is a double-colon, p will now point to the
+ second colon. */
+ /* PASS2: p2->"::fun", p->":fun" */
+
+ /* Move pointer ahead to next double-colon. */
+ while (*p && (p[0] != ' ') && (p[0] != '\t') && (p[0] != '\''))
+ {
+ if (p[0] == '<')
+ {
+ temp_end = find_template_name_end (p);
+ if (!temp_end)
+ error (_("malformed template specification in command"));
+ p = temp_end;
+ }
+ /* Note that, since, at the start of this loop, p would be
+ pointing to the second colon in a double-colon, we only
+ satisfy the condition below if there is another
+ double-colon to the right (after). I.e. there is another
+ component that can be a class or a namespace. I.e, if at
+ the beginning of this loop (PASS1), we had
+ p->":inA::fun", we'll trigger this when p has been
+ advanced to point to "::fun". */
+ /* PASS2: we will not trigger this. */
+ else if ((p[0] == ':') && (p[1] == ':'))
+ break; /* Found double-colon. */