forked from Imagelibrary/binutils-gdb
This patch introduces a new macro, INIT_GDB_FILE. This is used to
replace the current "_initialize_" idiom when introducing a per-file
initialization function. That is, rather than write:
void _initialize_something ();
void
_initialize_something ()
{
...
}
... now you would write:
INIT_GDB_FILE (something)
{
...
}
The macro handles both the declaration and definition of the function.
The point of this approach is that it makes it harder to accidentally
cause an initializer to be omitted; see commit 2711e475 ("Ensure
cooked_index_entry self-tests are run"). Specifically, the regexp now
used by make-init-c seems harder to trick.
New in v2: un-did some erroneous changes made by the script.
The bulk of this patch was written by script.
Regression tested on x86-64 Fedora 41.
243 lines
7.0 KiB
C
243 lines
7.0 KiB
C
/* Entry in the cooked index
|
|
|
|
Copyright (C) 2022-2025 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 "dwarf2/cooked-index-entry.h"
|
|
#include "dwarf2/tag.h"
|
|
#include "gdbsupport/gdb-safe-ctype.h"
|
|
#include "gdbsupport/selftest.h"
|
|
|
|
/* See cooked-index-entry.h. */
|
|
|
|
std::string
|
|
to_string (cooked_index_flag flags)
|
|
{
|
|
static constexpr cooked_index_flag::string_mapping mapping[] = {
|
|
MAP_ENUM_FLAG (IS_MAIN),
|
|
MAP_ENUM_FLAG (IS_STATIC),
|
|
MAP_ENUM_FLAG (IS_LINKAGE),
|
|
MAP_ENUM_FLAG (IS_TYPE_DECLARATION),
|
|
MAP_ENUM_FLAG (IS_PARENT_DEFERRED),
|
|
MAP_ENUM_FLAG (IS_SYNTHESIZED),
|
|
};
|
|
|
|
return flags.to_string (mapping);
|
|
}
|
|
|
|
/* See cooked-index-entry.h. */
|
|
|
|
int
|
|
cooked_index_entry::compare (const char *stra, const char *strb,
|
|
comparison_mode mode)
|
|
{
|
|
#if defined (__GNUC__) && !defined (__clang__) && __GNUC__ <= 7
|
|
/* Work around error with gcc 7.5.0. */
|
|
auto munge = [] (char c) -> unsigned char
|
|
#else
|
|
auto munge = [] (char c) constexpr -> unsigned char
|
|
#endif
|
|
{
|
|
/* Treat '<' as if it ended the string. This lets something
|
|
like "func<t>" match "func<t<int>>". See the "Breakpoints in
|
|
template functions" section in the manual. */
|
|
if (c == '<')
|
|
return '\0';
|
|
return TOLOWER ((unsigned char) c);
|
|
};
|
|
|
|
unsigned char a = munge (*stra);
|
|
unsigned char b = munge (*strb);
|
|
|
|
while (a != '\0' && b != '\0' && a == b)
|
|
{
|
|
a = munge (*++stra);
|
|
b = munge (*++strb);
|
|
}
|
|
|
|
if (a == b)
|
|
return 0;
|
|
|
|
/* When completing, if STRB ends earlier than STRA, consider them as
|
|
equal. */
|
|
if (mode == COMPLETE && b == '\0')
|
|
return 0;
|
|
|
|
return a < b ? -1 : 1;
|
|
}
|
|
|
|
#if GDB_SELF_TEST
|
|
|
|
namespace {
|
|
|
|
void
|
|
test_compare ()
|
|
{
|
|
/* Convenience aliases. */
|
|
const auto mode_compare = cooked_index_entry::MATCH;
|
|
const auto mode_sort = cooked_index_entry::SORT;
|
|
const auto mode_complete = cooked_index_entry::COMPLETE;
|
|
|
|
SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd",
|
|
mode_compare) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("abcd", "abcd",
|
|
mode_complete) == 0);
|
|
|
|
SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE",
|
|
mode_compare) < 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd",
|
|
mode_compare) > 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("abcd", "ABCDE",
|
|
mode_complete) < 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("ABCDE", "abcd",
|
|
mode_complete) == 0);
|
|
|
|
SELF_CHECK (cooked_index_entry::compare ("name", "name<>",
|
|
mode_compare) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("name<>", "name",
|
|
mode_compare) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("name", "name<>",
|
|
mode_complete) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("name<>", "name",
|
|
mode_complete) == 0);
|
|
|
|
SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>",
|
|
mode_compare) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>",
|
|
mode_compare) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<arg>",
|
|
mode_complete) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("name<arg>", "name<ag>",
|
|
mode_complete) == 0);
|
|
|
|
SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>",
|
|
"name<arg<more>>",
|
|
mode_compare) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("name<arg>",
|
|
"name<arg<more>>",
|
|
mode_compare) == 0);
|
|
|
|
SELF_CHECK (cooked_index_entry::compare ("name", "name<arg<more>>",
|
|
mode_compare) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name",
|
|
mode_compare) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<",
|
|
mode_compare) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("name<arg<more>>", "name<arg<",
|
|
mode_complete) == 0);
|
|
|
|
SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_compare) < 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("", "abcd", mode_complete) < 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_compare) > 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("abcd", "", mode_complete) == 0);
|
|
|
|
SELF_CHECK (cooked_index_entry::compare ("func", "func<type>",
|
|
mode_sort) == 0);
|
|
SELF_CHECK (cooked_index_entry::compare ("func<type>", "func1",
|
|
mode_sort) < 0);
|
|
}
|
|
|
|
} /* anonymous namespace */
|
|
|
|
#endif /* GDB_SELF_TEST */
|
|
|
|
/* See cooked-index-entry.h. */
|
|
|
|
bool
|
|
cooked_index_entry::matches (domain_search_flags kind) const
|
|
{
|
|
/* Just reject type declarations. */
|
|
if ((flags & IS_TYPE_DECLARATION) != 0)
|
|
return false;
|
|
|
|
return tag_matches_domain (tag, kind, lang);
|
|
}
|
|
|
|
/* See cooked-index-entry.h. */
|
|
|
|
const char *
|
|
cooked_index_entry::full_name (struct obstack *storage,
|
|
cooked_index_full_name_flag name_flags,
|
|
const char *default_sep) const
|
|
{
|
|
const char *local_name = ((name_flags & FOR_MAIN) != 0) ? name : canonical;
|
|
|
|
if ((flags & IS_LINKAGE) != 0 || get_parent () == nullptr)
|
|
return local_name;
|
|
|
|
const char *sep = default_sep;
|
|
switch (lang)
|
|
{
|
|
case language_cplus:
|
|
case language_rust:
|
|
case language_fortran:
|
|
sep = "::";
|
|
break;
|
|
|
|
case language_ada:
|
|
if ((name_flags & FOR_ADA_LINKAGE_NAME) != 0)
|
|
{
|
|
sep = "__";
|
|
break;
|
|
}
|
|
[[fallthrough]];
|
|
case language_go:
|
|
case language_d:
|
|
sep = ".";
|
|
break;
|
|
|
|
default:
|
|
if (sep == nullptr)
|
|
return local_name;
|
|
break;
|
|
}
|
|
|
|
/* The FOR_ADA_LINKAGE_NAME flag should only affect Ada entries, so
|
|
disable it here if we don't need it. */
|
|
if (lang != language_ada)
|
|
name_flags &= ~FOR_ADA_LINKAGE_NAME;
|
|
|
|
get_parent ()->write_scope (storage, sep, name_flags);
|
|
obstack_grow0 (storage, local_name, strlen (local_name));
|
|
return (const char *) obstack_finish (storage);
|
|
}
|
|
|
|
/* See cooked-index-entry.h. */
|
|
|
|
void
|
|
cooked_index_entry::write_scope (struct obstack *storage,
|
|
const char *sep,
|
|
cooked_index_full_name_flag flags) const
|
|
{
|
|
if (get_parent () != nullptr)
|
|
get_parent ()->write_scope (storage, sep, flags);
|
|
/* When computing the Ada linkage name, the entry might not have
|
|
been canonicalized yet, so use the 'name'. */
|
|
const char *local_name = ((flags & (FOR_MAIN | FOR_ADA_LINKAGE_NAME)) != 0
|
|
? name
|
|
: canonical);
|
|
obstack_grow (storage, local_name, strlen (local_name));
|
|
obstack_grow (storage, sep, strlen (sep));
|
|
}
|
|
|
|
INIT_GDB_FILE (dwarf2_entry)
|
|
{
|
|
#if GDB_SELF_TEST
|
|
selftests::register_test ("cooked_index_entry::compare", test_compare);
|
|
#endif
|
|
}
|