mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-06 12:09:26 +08:00
1d506c26d9
This commit is the result of the following actions: - Running gdb/copyright.py to update all of the copyright headers to include 2024, - Manually updating a few files the copyright.py script told me to update, these files had copyright headers embedded within the file, - Regenerating gdbsupport/Makefile.in to refresh it's copyright date, - Using grep to find other files that still mentioned 2023. If these files were updated last year from 2022 to 2023 then I've updated them this year to 2024. I'm sure I've probably missed some dates. Feel free to fix them up as you spot them.
849 lines
23 KiB
C
849 lines
23 KiB
C
/* Data structures and API for location specs in GDB.
|
|
Copyright (C) 2013-2024 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 <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "defs.h"
|
|
#include "gdbsupport/gdb_assert.h"
|
|
#include "gdbsupport/gdb-checked-static-cast.h"
|
|
#include "location.h"
|
|
#include "symtab.h"
|
|
#include "language.h"
|
|
#include "linespec.h"
|
|
#include "cli/cli-utils.h"
|
|
#include "probe.h"
|
|
#include "cp-support.h"
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
static std::string
|
|
explicit_to_string_internal (bool as_linespec,
|
|
const explicit_location_spec *explicit_loc);
|
|
|
|
/* Return a xstrdup of STR if not NULL, otherwise return NULL. */
|
|
|
|
static char *
|
|
maybe_xstrdup (const char *str)
|
|
{
|
|
return (str != nullptr ? xstrdup (str) : nullptr);
|
|
}
|
|
|
|
probe_location_spec::probe_location_spec (std::string &&probe)
|
|
: location_spec (PROBE_LOCATION_SPEC, std::move (probe))
|
|
{
|
|
}
|
|
|
|
location_spec_up
|
|
probe_location_spec::clone () const
|
|
{
|
|
return location_spec_up (new probe_location_spec (*this));
|
|
}
|
|
|
|
bool
|
|
probe_location_spec::empty_p () const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
std::string probe_location_spec::compute_string () const
|
|
{
|
|
return std::move (m_as_string);
|
|
}
|
|
|
|
/* A "normal" linespec. */
|
|
linespec_location_spec::linespec_location_spec
|
|
(const char **linespec, symbol_name_match_type match_type_)
|
|
: location_spec (LINESPEC_LOCATION_SPEC),
|
|
match_type (match_type_)
|
|
{
|
|
if (*linespec != NULL)
|
|
{
|
|
const char *p;
|
|
const char *orig = *linespec;
|
|
|
|
linespec_lex_to_end (linespec);
|
|
p = remove_trailing_whitespace (orig, *linespec);
|
|
|
|
/* If there is no valid linespec then this will leave the
|
|
spec_string as nullptr. This behaviour is relied on in the
|
|
breakpoint setting code, where spec_string being nullptr means
|
|
to use the default breakpoint location. */
|
|
if ((p - orig) > 0)
|
|
spec_string.reset (savestring (orig, p - orig));
|
|
}
|
|
}
|
|
|
|
location_spec_up
|
|
linespec_location_spec::clone () const
|
|
{
|
|
return location_spec_up (new linespec_location_spec (*this));
|
|
}
|
|
|
|
bool
|
|
linespec_location_spec::empty_p () const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
linespec_location_spec::linespec_location_spec
|
|
(const linespec_location_spec &other)
|
|
: location_spec (other),
|
|
match_type (other.match_type),
|
|
spec_string (maybe_xstrdup (other.spec_string.get ()))
|
|
{
|
|
}
|
|
|
|
std::string
|
|
linespec_location_spec::compute_string () const
|
|
{
|
|
if (spec_string != nullptr)
|
|
{
|
|
if (match_type == symbol_name_match_type::FULL)
|
|
return std::string ("-qualified ") + spec_string.get ();
|
|
else
|
|
return spec_string.get ();
|
|
}
|
|
return {};
|
|
}
|
|
|
|
address_location_spec::address_location_spec (CORE_ADDR addr,
|
|
const char *addr_string,
|
|
int addr_string_len)
|
|
: location_spec (ADDRESS_LOCATION_SPEC),
|
|
address (addr)
|
|
{
|
|
if (addr_string != nullptr)
|
|
m_as_string = std::string (addr_string, addr_string_len);
|
|
}
|
|
|
|
location_spec_up
|
|
address_location_spec::clone () const
|
|
{
|
|
return location_spec_up (new address_location_spec (*this));
|
|
}
|
|
|
|
bool
|
|
address_location_spec::empty_p () const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
address_location_spec::address_location_spec
|
|
(const address_location_spec &other)
|
|
: location_spec (other),
|
|
address (other.address)
|
|
{
|
|
}
|
|
|
|
std::string
|
|
address_location_spec::compute_string () const
|
|
{
|
|
const char *addr_string = core_addr_to_string (address);
|
|
return std::string ("*") + addr_string;
|
|
}
|
|
|
|
explicit_location_spec::explicit_location_spec (const char *function_name)
|
|
: location_spec (EXPLICIT_LOCATION_SPEC),
|
|
function_name (maybe_xstrdup (function_name))
|
|
{
|
|
}
|
|
|
|
explicit_location_spec::explicit_location_spec
|
|
(const explicit_location_spec &other)
|
|
: location_spec (other),
|
|
source_filename (maybe_xstrdup (other.source_filename.get ())),
|
|
function_name (maybe_xstrdup (other.function_name.get ())),
|
|
func_name_match_type (other.func_name_match_type),
|
|
label_name (maybe_xstrdup (other.label_name.get ())),
|
|
line_offset (other.line_offset)
|
|
{
|
|
}
|
|
|
|
location_spec_up
|
|
explicit_location_spec::clone () const
|
|
{
|
|
return location_spec_up (new explicit_location_spec (*this));
|
|
}
|
|
|
|
bool
|
|
explicit_location_spec::empty_p () const
|
|
{
|
|
return (source_filename == nullptr
|
|
&& function_name == nullptr
|
|
&& label_name == nullptr
|
|
&& line_offset.sign == LINE_OFFSET_UNKNOWN);
|
|
}
|
|
|
|
std::string
|
|
explicit_location_spec::compute_string () const
|
|
{
|
|
return explicit_to_string_internal (false, this);
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
location_spec_up
|
|
new_linespec_location_spec (const char **linespec,
|
|
symbol_name_match_type match_type)
|
|
{
|
|
return location_spec_up (new linespec_location_spec (linespec,
|
|
match_type));
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
const linespec_location_spec *
|
|
as_linespec_location_spec (const location_spec *locspec)
|
|
{
|
|
gdb_assert (locspec->type () == LINESPEC_LOCATION_SPEC);
|
|
return gdb::checked_static_cast<const linespec_location_spec *> (locspec);
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
location_spec_up
|
|
new_address_location_spec (CORE_ADDR addr, const char *addr_string,
|
|
int addr_string_len)
|
|
{
|
|
return location_spec_up (new address_location_spec (addr, addr_string,
|
|
addr_string_len));
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
const address_location_spec *
|
|
as_address_location_spec (const location_spec *locspec)
|
|
{
|
|
gdb_assert (locspec->type () == ADDRESS_LOCATION_SPEC);
|
|
return gdb::checked_static_cast<const address_location_spec *> (locspec);
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
location_spec_up
|
|
new_probe_location_spec (std::string &&probe)
|
|
{
|
|
return location_spec_up (new probe_location_spec (std::move (probe)));
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
const probe_location_spec *
|
|
as_probe_location_spec (const location_spec *locspec)
|
|
{
|
|
gdb_assert (locspec->type () == PROBE_LOCATION_SPEC);
|
|
return gdb::checked_static_cast<const probe_location_spec *> (locspec);
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
const explicit_location_spec *
|
|
as_explicit_location_spec (const location_spec *locspec)
|
|
{
|
|
gdb_assert (locspec->type () == EXPLICIT_LOCATION_SPEC);
|
|
return gdb::checked_static_cast<const explicit_location_spec *> (locspec);
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
explicit_location_spec *
|
|
as_explicit_location_spec (location_spec *locspec)
|
|
{
|
|
gdb_assert (locspec->type () == EXPLICIT_LOCATION_SPEC);
|
|
return gdb::checked_static_cast<explicit_location_spec *> (locspec);
|
|
}
|
|
|
|
/* Return a string representation of the explicit location spec in
|
|
EXPLICIT_LOCSPEC.
|
|
|
|
AS_LINESPEC is true if this string should be a linespec. Otherwise
|
|
it will be output in explicit form. */
|
|
|
|
static std::string
|
|
explicit_to_string_internal (bool as_linespec,
|
|
const explicit_location_spec *explicit_loc)
|
|
{
|
|
bool need_space = false;
|
|
char space = as_linespec ? ':' : ' ';
|
|
string_file buf;
|
|
|
|
if (explicit_loc->source_filename != NULL)
|
|
{
|
|
if (!as_linespec)
|
|
buf.puts ("-source ");
|
|
buf.puts (explicit_loc->source_filename.get ());
|
|
need_space = true;
|
|
}
|
|
|
|
if (explicit_loc->function_name != NULL)
|
|
{
|
|
if (need_space)
|
|
buf.putc (space);
|
|
if (explicit_loc->func_name_match_type == symbol_name_match_type::FULL)
|
|
buf.puts ("-qualified ");
|
|
if (!as_linespec)
|
|
buf.puts ("-function ");
|
|
buf.puts (explicit_loc->function_name.get ());
|
|
need_space = true;
|
|
}
|
|
|
|
if (explicit_loc->label_name != NULL)
|
|
{
|
|
if (need_space)
|
|
buf.putc (space);
|
|
if (!as_linespec)
|
|
buf.puts ("-label ");
|
|
buf.puts (explicit_loc->label_name.get ());
|
|
need_space = true;
|
|
}
|
|
|
|
if (explicit_loc->line_offset.sign != LINE_OFFSET_UNKNOWN)
|
|
{
|
|
if (need_space)
|
|
buf.putc (space);
|
|
if (!as_linespec)
|
|
buf.puts ("-line ");
|
|
buf.printf ("%s%d",
|
|
(explicit_loc->line_offset.sign == LINE_OFFSET_NONE ? ""
|
|
: (explicit_loc->line_offset.sign
|
|
== LINE_OFFSET_PLUS ? "+" : "-")),
|
|
explicit_loc->line_offset.offset);
|
|
}
|
|
|
|
return buf.release ();
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
std::string
|
|
explicit_location_spec::to_linespec () const
|
|
{
|
|
return explicit_to_string_internal (true, this);
|
|
}
|
|
|
|
/* Find an instance of the quote character C in the string S that is
|
|
outside of all single- and double-quoted strings (i.e., any quoting
|
|
other than C). */
|
|
|
|
static const char *
|
|
find_end_quote (const char *s, char end_quote_char)
|
|
{
|
|
/* zero if we're not in quotes;
|
|
'"' if we're in a double-quoted string;
|
|
'\'' if we're in a single-quoted string. */
|
|
char nested_quote_char = '\0';
|
|
|
|
for (const char *scan = s; *scan != '\0'; scan++)
|
|
{
|
|
if (nested_quote_char != '\0')
|
|
{
|
|
if (*scan == nested_quote_char)
|
|
nested_quote_char = '\0';
|
|
else if (scan[0] == '\\' && *(scan + 1) != '\0')
|
|
scan++;
|
|
}
|
|
else if (*scan == end_quote_char && nested_quote_char == '\0')
|
|
return scan;
|
|
else if (*scan == '"' || *scan == '\'')
|
|
nested_quote_char = *scan;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* A lexer for explicit location specs. This function will advance
|
|
INP past any strings that it lexes. Returns a malloc'd copy of the
|
|
lexed string or NULL if no lexing was done. */
|
|
|
|
static gdb::unique_xmalloc_ptr<char>
|
|
explicit_location_spec_lex_one (const char **inp,
|
|
const struct language_defn *language,
|
|
explicit_completion_info *completion_info)
|
|
{
|
|
const char *start = *inp;
|
|
|
|
if (*start == '\0')
|
|
return NULL;
|
|
|
|
/* If quoted, skip to the ending quote. */
|
|
if (strchr (get_gdb_linespec_parser_quote_characters (), *start))
|
|
{
|
|
if (completion_info != NULL)
|
|
completion_info->quoted_arg_start = start;
|
|
|
|
const char *end = find_end_quote (start + 1, *start);
|
|
|
|
if (end == NULL)
|
|
{
|
|
if (completion_info == NULL)
|
|
error (_("Unmatched quote, %s."), start);
|
|
|
|
end = start + strlen (start);
|
|
*inp = end;
|
|
return gdb::unique_xmalloc_ptr<char> (savestring (start + 1,
|
|
*inp - start - 1));
|
|
}
|
|
|
|
if (completion_info != NULL)
|
|
completion_info->quoted_arg_end = end;
|
|
*inp = end + 1;
|
|
return gdb::unique_xmalloc_ptr<char> (savestring (start + 1,
|
|
*inp - start - 2));
|
|
}
|
|
|
|
/* If the input starts with '-' or '+', the string ends with the next
|
|
whitespace or comma. */
|
|
if (*start == '-' || *start == '+')
|
|
{
|
|
while (*inp[0] != '\0' && *inp[0] != ',' && !isspace (*inp[0]))
|
|
++(*inp);
|
|
}
|
|
else
|
|
{
|
|
/* Handle numbers first, stopping at the next whitespace or ','. */
|
|
while (isdigit (*inp[0]))
|
|
++(*inp);
|
|
if (*inp[0] == '\0' || isspace (*inp[0]) || *inp[0] == ',')
|
|
return gdb::unique_xmalloc_ptr<char> (savestring (start,
|
|
*inp - start));
|
|
|
|
/* Otherwise stop at the next occurrence of whitespace, '\0',
|
|
keyword, or ','. */
|
|
*inp = start;
|
|
while ((*inp)[0]
|
|
&& (*inp)[0] != ','
|
|
&& !(isspace ((*inp)[0])
|
|
|| linespec_lexer_lex_keyword (&(*inp)[1])))
|
|
{
|
|
/* Special case: C++ operator,. */
|
|
if (language->la_language == language_cplus
|
|
&& startswith (*inp, CP_OPERATOR_STR))
|
|
(*inp) += CP_OPERATOR_LEN;
|
|
++(*inp);
|
|
}
|
|
}
|
|
|
|
if (*inp - start > 0)
|
|
return gdb::unique_xmalloc_ptr<char> (savestring (start, *inp - start));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Return true if COMMA points past "operator". START is the start of
|
|
the line that COMMAND points to, hence when reading backwards, we
|
|
must not read any character before START. */
|
|
|
|
static bool
|
|
is_cp_operator (const char *start, const char *comma)
|
|
{
|
|
if (comma != NULL
|
|
&& (comma - start) >= CP_OPERATOR_LEN)
|
|
{
|
|
const char *p = comma;
|
|
|
|
while (p > start && isspace (p[-1]))
|
|
p--;
|
|
if (p - start >= CP_OPERATOR_LEN)
|
|
{
|
|
p -= CP_OPERATOR_LEN;
|
|
if (strncmp (p, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0
|
|
&& (p == start
|
|
|| !(isalnum (p[-1]) || p[-1] == '_')))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* When scanning the input string looking for the next explicit
|
|
location spec option/delimiter, we jump to the next option by looking
|
|
for ",", and "-". Such a character can also appear in C++ symbols
|
|
like "operator," and "operator-". So when we find such a
|
|
character, we call this function to check if we found such a
|
|
symbol, meaning we had a false positive for an option string. In
|
|
that case, we keep looking for the next delimiter, until we find
|
|
one that is not a false positive, or we reach end of string. FOUND
|
|
is the character that scanning found (either '-' or ','), and START
|
|
is the start of the line that FOUND points to, hence when reading
|
|
backwards, we must not read any character before START. Returns a
|
|
pointer to the next non-false-positive delimiter character, or NULL
|
|
if none was found. */
|
|
|
|
static const char *
|
|
skip_op_false_positives (const char *start, const char *found)
|
|
{
|
|
while (found != NULL && is_cp_operator (start, found))
|
|
{
|
|
if (found[0] == '-' && found[1] == '-')
|
|
start = found + 2;
|
|
else
|
|
start = found + 1;
|
|
found = find_toplevel_char (start, *found);
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
/* Assuming both FIRST and NEW_TOK point into the same string, return
|
|
the pointer that is closer to the start of the string. If FIRST is
|
|
NULL, returns NEW_TOK. If NEW_TOK is NULL, returns FIRST. */
|
|
|
|
static const char *
|
|
first_of (const char *first, const char *new_tok)
|
|
{
|
|
if (first == NULL)
|
|
return new_tok;
|
|
else if (new_tok != NULL && new_tok < first)
|
|
return new_tok;
|
|
else
|
|
return first;
|
|
}
|
|
|
|
/* A lexer for functions in explicit location specs. This function will
|
|
advance INP past a function until the next option, or until end of
|
|
string. Returns a malloc'd copy of the lexed string or NULL if no
|
|
lexing was done. */
|
|
|
|
static gdb::unique_xmalloc_ptr<char>
|
|
explicit_location_spec_lex_one_function
|
|
(const char **inp,
|
|
const struct language_defn *language,
|
|
explicit_completion_info *completion_info)
|
|
{
|
|
const char *start = *inp;
|
|
|
|
if (*start == '\0')
|
|
return NULL;
|
|
|
|
/* If quoted, skip to the ending quote. */
|
|
if (strchr (get_gdb_linespec_parser_quote_characters (), *start))
|
|
{
|
|
char quote_char = *start;
|
|
|
|
/* If the input is not an Ada operator, skip to the matching
|
|
closing quote and return the string. */
|
|
if (!(language->la_language == language_ada
|
|
&& quote_char == '\"' && is_ada_operator (start)))
|
|
{
|
|
if (completion_info != NULL)
|
|
completion_info->quoted_arg_start = start;
|
|
|
|
const char *end = find_toplevel_char (start + 1, quote_char);
|
|
|
|
if (end == NULL)
|
|
{
|
|
if (completion_info == NULL)
|
|
error (_("Unmatched quote, %s."), start);
|
|
|
|
end = start + strlen (start);
|
|
*inp = end;
|
|
char *saved = savestring (start + 1, *inp - start - 1);
|
|
return gdb::unique_xmalloc_ptr<char> (saved);
|
|
}
|
|
|
|
if (completion_info != NULL)
|
|
completion_info->quoted_arg_end = end;
|
|
*inp = end + 1;
|
|
char *saved = savestring (start + 1, *inp - start - 2);
|
|
return gdb::unique_xmalloc_ptr<char> (saved);
|
|
}
|
|
}
|
|
|
|
const char *comma = find_toplevel_char (start, ',');
|
|
|
|
/* If we have "-function -myfunction", or perhaps better example,
|
|
"-function -[BasicClass doIt]" (objc selector), treat
|
|
"-myfunction" as the function name. I.e., skip the first char if
|
|
it is an hyphen. Don't skip the first char always, because we
|
|
may have C++ "operator<", and find_toplevel_char needs to see the
|
|
'o' in that case. */
|
|
const char *hyphen
|
|
= (*start == '-'
|
|
? find_toplevel_char (start + 1, '-')
|
|
: find_toplevel_char (start, '-'));
|
|
|
|
/* Check for C++ "operator," and "operator-". */
|
|
comma = skip_op_false_positives (start, comma);
|
|
hyphen = skip_op_false_positives (start, hyphen);
|
|
|
|
/* Pick the one that appears first. */
|
|
const char *end = first_of (hyphen, comma);
|
|
|
|
/* See if a linespec keyword appears first. */
|
|
const char *s = start;
|
|
const char *ws = find_toplevel_char (start, ' ');
|
|
while (ws != NULL && linespec_lexer_lex_keyword (ws + 1) == NULL)
|
|
{
|
|
s = ws + 1;
|
|
ws = find_toplevel_char (s, ' ');
|
|
}
|
|
if (ws != NULL)
|
|
end = first_of (end, ws + 1);
|
|
|
|
/* If we don't have any terminator, then take the whole string. */
|
|
if (end == NULL)
|
|
end = start + strlen (start);
|
|
|
|
/* Trim whitespace at the end. */
|
|
while (end > start && end[-1] == ' ')
|
|
end--;
|
|
|
|
*inp = end;
|
|
|
|
if (*inp - start > 0)
|
|
return gdb::unique_xmalloc_ptr<char> (savestring (start, *inp - start));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
location_spec_up
|
|
string_to_explicit_location_spec (const char **argp,
|
|
const struct language_defn *language,
|
|
explicit_completion_info *completion_info)
|
|
{
|
|
/* It is assumed that input beginning with '-' and a non-digit
|
|
character is an explicit location. "-p" is reserved, though,
|
|
for probe locations. */
|
|
if (argp == NULL
|
|
|| *argp == NULL
|
|
|| *argp[0] != '-'
|
|
|| !isalpha ((*argp)[1])
|
|
|| ((*argp)[0] == '-' && (*argp)[1] == 'p'))
|
|
return NULL;
|
|
|
|
std::unique_ptr<explicit_location_spec> locspec
|
|
(new explicit_location_spec ());
|
|
|
|
/* Process option/argument pairs. dprintf_command
|
|
requires that processing stop on ','. */
|
|
while ((*argp)[0] != '\0' && (*argp)[0] != ',')
|
|
{
|
|
int len;
|
|
const char *start;
|
|
|
|
/* Clear these on each iteration, since they should be filled
|
|
with info about the last option. */
|
|
if (completion_info != NULL)
|
|
{
|
|
completion_info->quoted_arg_start = NULL;
|
|
completion_info->quoted_arg_end = NULL;
|
|
}
|
|
|
|
/* If *ARGP starts with a keyword, stop processing
|
|
options. */
|
|
if (linespec_lexer_lex_keyword (*argp) != NULL)
|
|
break;
|
|
|
|
/* Mark the start of the string in case we need to rewind. */
|
|
start = *argp;
|
|
|
|
if (completion_info != NULL)
|
|
completion_info->last_option = start;
|
|
|
|
/* Get the option string. */
|
|
gdb::unique_xmalloc_ptr<char> opt
|
|
= explicit_location_spec_lex_one (argp, language, NULL);
|
|
|
|
/* Use the length of the option to allow abbreviations. */
|
|
len = strlen (opt.get ());
|
|
|
|
/* Get the argument string. */
|
|
*argp = skip_spaces (*argp);
|
|
|
|
/* All options have a required argument. Checking for this
|
|
required argument is deferred until later. */
|
|
gdb::unique_xmalloc_ptr<char> oarg;
|
|
/* True if we have an argument. This is required because we'll
|
|
move from OARG before checking whether we have an
|
|
argument. */
|
|
bool have_oarg = false;
|
|
|
|
/* True if the option needs an argument. */
|
|
bool need_oarg = false;
|
|
|
|
/* Convenience to consistently set both OARG/HAVE_OARG from
|
|
ARG. */
|
|
auto set_oarg = [&] (gdb::unique_xmalloc_ptr<char> arg)
|
|
{
|
|
if (completion_info != NULL)
|
|
{
|
|
/* We do this here because the set of options that take
|
|
arguments matches the set of explicit location
|
|
options. */
|
|
completion_info->saw_explicit_location_spec_option = true;
|
|
}
|
|
oarg = std::move (arg);
|
|
have_oarg = oarg != NULL;
|
|
need_oarg = true;
|
|
};
|
|
|
|
if (strncmp (opt.get (), "-source", len) == 0)
|
|
{
|
|
set_oarg (explicit_location_spec_lex_one (argp, language,
|
|
completion_info));
|
|
locspec->source_filename = std::move (oarg);
|
|
}
|
|
else if (strncmp (opt.get (), "-function", len) == 0)
|
|
{
|
|
set_oarg (explicit_location_spec_lex_one_function (argp, language,
|
|
completion_info));
|
|
locspec->function_name = std::move (oarg);
|
|
}
|
|
else if (strncmp (opt.get (), "-qualified", len) == 0)
|
|
{
|
|
locspec->func_name_match_type = symbol_name_match_type::FULL;
|
|
}
|
|
else if (strncmp (opt.get (), "-line", len) == 0)
|
|
{
|
|
set_oarg (explicit_location_spec_lex_one (argp, language, NULL));
|
|
*argp = skip_spaces (*argp);
|
|
if (have_oarg)
|
|
{
|
|
locspec->line_offset = linespec_parse_line_offset (oarg.get ());
|
|
continue;
|
|
}
|
|
}
|
|
else if (strncmp (opt.get (), "-label", len) == 0)
|
|
{
|
|
set_oarg (explicit_location_spec_lex_one (argp, language,
|
|
completion_info));
|
|
locspec->label_name = std::move (oarg);
|
|
}
|
|
/* Only emit an "invalid argument" error for options
|
|
that look like option strings. */
|
|
else if (opt.get ()[0] == '-' && !isdigit (opt.get ()[1]))
|
|
{
|
|
if (completion_info == NULL)
|
|
error (_("invalid explicit location argument, \"%s\""), opt.get ());
|
|
}
|
|
else
|
|
{
|
|
/* End of the explicit location specification.
|
|
Stop parsing and return whatever explicit location was
|
|
parsed. */
|
|
*argp = start;
|
|
break;
|
|
}
|
|
|
|
*argp = skip_spaces (*argp);
|
|
|
|
/* It's a little lame to error after the fact, but in this
|
|
case, it provides a much better user experience to issue
|
|
the "invalid argument" error before any missing
|
|
argument error. */
|
|
if (need_oarg && !have_oarg && completion_info == NULL)
|
|
error (_("missing argument for \"%s\""), opt.get ());
|
|
}
|
|
|
|
/* One special error check: If a source filename was given
|
|
without offset, function, or label, issue an error. */
|
|
if (locspec->source_filename != NULL
|
|
&& locspec->function_name == NULL
|
|
&& locspec->label_name == NULL
|
|
&& (locspec->line_offset.sign == LINE_OFFSET_UNKNOWN)
|
|
&& completion_info == NULL)
|
|
{
|
|
error (_("Source filename requires function, label, or "
|
|
"line offset."));
|
|
}
|
|
|
|
return location_spec_up (locspec.release ());
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
location_spec_up
|
|
string_to_location_spec_basic (const char **stringp,
|
|
const struct language_defn *language,
|
|
symbol_name_match_type match_type)
|
|
{
|
|
location_spec_up locspec;
|
|
const char *cs;
|
|
|
|
/* Try the input as a probe spec. */
|
|
cs = *stringp;
|
|
if (cs != NULL && probe_linespec_to_static_ops (&cs) != NULL)
|
|
{
|
|
locspec = new_probe_location_spec (*stringp);
|
|
*stringp += strlen (*stringp);
|
|
}
|
|
else
|
|
{
|
|
/* Try an address location spec. */
|
|
if (*stringp != NULL && **stringp == '*')
|
|
{
|
|
const char *arg, *orig;
|
|
CORE_ADDR addr;
|
|
|
|
orig = arg = *stringp;
|
|
addr = linespec_expression_to_pc (&arg);
|
|
locspec = new_address_location_spec (addr, orig, arg - orig);
|
|
*stringp += arg - orig;
|
|
}
|
|
else
|
|
{
|
|
/* Everything else is a linespec. */
|
|
locspec = new_linespec_location_spec (stringp, match_type);
|
|
}
|
|
}
|
|
|
|
return locspec;
|
|
}
|
|
|
|
/* See description in location.h. */
|
|
|
|
location_spec_up
|
|
string_to_location_spec (const char **stringp,
|
|
const struct language_defn *language,
|
|
symbol_name_match_type match_type)
|
|
{
|
|
const char *arg, *orig;
|
|
|
|
/* Try an explicit location spec. */
|
|
orig = arg = *stringp;
|
|
location_spec_up locspec
|
|
= string_to_explicit_location_spec (&arg, language, NULL);
|
|
if (locspec != nullptr)
|
|
{
|
|
/* It was a valid explicit location. Advance STRINGP to
|
|
the end of input. */
|
|
*stringp += arg - orig;
|
|
|
|
/* If the user really specified a location spec, then we're
|
|
done. */
|
|
if (!locspec->empty_p ())
|
|
return locspec;
|
|
|
|
/* Otherwise, the user _only_ specified optional flags like
|
|
"-qualified", otherwise string_to_explicit_location_spec
|
|
would have thrown an error. Save the flags for "basic"
|
|
linespec parsing below and discard the explicit location
|
|
spec. */
|
|
explicit_location_spec *xloc
|
|
= gdb::checked_static_cast<explicit_location_spec *> (locspec.get ());
|
|
match_type = xloc->func_name_match_type;
|
|
}
|
|
|
|
/* Everything else is a "basic" linespec, address, or probe location
|
|
spec. */
|
|
return string_to_location_spec_basic (stringp, language, match_type);
|
|
}
|