~ubuntu-support-team/binutils/+git/binutils-gdb:users/palves/enum-flags-rewrite

Last commit made on 2020-08-21
Get this branch:
git clone -b users/palves/enum-flags-rewrite https://git.launchpad.net/~ubuntu-support-team/binutils/+git/binutils-gdb

Branch merges

Branch information

Name:
users/palves/enum-flags-rewrite
Repository:
lp:~ubuntu-support-team/binutils/+git/binutils-gdb

Recent commits

32ef0ec... by Pedro Alves <email address hidden>

Rewrite enum_flags, add unit tests, fix problems

This patch started by adding comprehensive unit tests for enum_flags.

For the testing part, it adds:

 - tests of normal expected uses of the API.

 - checks that _invalid_ uses of the API would fail to compile. I.e.,
   it validates that enum_flags really is a strong type, and that
   incorrect mixing of enum types would be caught at compile time. It
   pulls that off making use of SFINEA and C++11's decltype/constexpr.

This revealed many holes in the enum_flags API. For example, the f1
assignment below currently incorrectly fails to compile:

 enum_flags<flags> f1 = FLAG1;
 enum_flags<flags> f2 = FLAG2 | f1;

The unit tests also revealed that this useful use case doesn't work:

    enum flag { FLAG1 = 1, FLAG2 = 2 };
    enum_flags<flag> src = FLAG1;
    enum_flags<flag> f1 = condition ? src : FLAG2;

It fails to compile because enum_flags<flag> and flag are convertible
to each other.

Turns out that making enum_flags be implicitly convertible to the
backing raw enum type was not a good idea.

If we make it convertible to the underlying type instead, we fix that
ternary operator use case, and, we find cases throughout the codebase
that should be using the enum_flags but were using the raw backing
enum instead. So it's a good change overall.

Also, several operators were missing.

These holes and more are plugged by this patch, by reworking how the
enum_flags operators are implemented, and making use of C++11's
feature of being able to delete methods/functions.

There are cases in gdb/compile/ where we need to call a function in a
C plugin API that expects the raw enum. To address cases like that,
this adds a "raw()" method to enum_flags. This way we can keep using
the safer enum_flags to construct the value, and then be explicit when
we need to get at the raw enum.

This makes most of the enum_flags operators constexpr. Beyond
enabling more compiler optimizations and enabling the new unit tests,
this has other advantages, like making it possible to use operator|
with enum_flags values in switch cases, where only compile-time
constants are allowed:

    enum_flags<flags> f = FLAG1 | FLAG2;
    switch (f)
      {
      case FLAG1 | FLAG2:
 break;
      }

Currently that fails to compile.

It also switches to a different mechanism of enabling the global
operators. The current mechanism isn't namespace friendly, the new
one is.

It also switches to C++11-style SFINAE -- instead of wrapping the
return type in a SFINAE-friently structure, we use an unnamed template
parameter. I.e., this:

  template <typename enum_type,
     typename = is_enum_flags_enum_type_t<enum_type>>
  enum_type
  operator& (enum_type e1, enum_type e2)

instead of:

  template <typename enum_type>
  typename enum_flags_type<enum_type>::type
  operator& (enum_type e1, enum_type e2)

Note that the static_assert inside operator~() was converted to a
couple overloads (signed vs unsigned), because static_assert is too
late for SFINAE-based tests, which is important for the CHECK_VALID
unit tests.

Tested with gcc {4.8, 7.1, 9.3} and clang {5.0.2, 10.0.0}.

gdb/ChangeLog:

 * Makefile.in (SELFTESTS_SRCS): Add
 unittests/enum-flags-selftests.c.
 * btrace.c (ftrace_update_caller, ftrace_fixup_calle): Use
 btrace_function_flags instead of enum btrace_function_flag.
 * compile/compile-c-types.c (convert_qualified): Use
 enum_flags::raw.
 * compile/compile-cplus-symbols.c (convert_one_symbol)
 (convert_symbol_bmsym):
 * compile/compile-cplus-types.c (compile_cplus_convert_method)
 (compile_cplus_convert_struct_or_union_methods)
 (compile_cplus_instance::convert_qualified_base):
 * go-exp.y (parse_string_or_char): Add cast to int.
 * unittests/enum-flags-selftests.c: New file.
 * record-btrace.c (btrace_thread_flag_to_str): Change parameter's
 type to btrace_thread_flags from btrace_thread_flag.
 (record_btrace_cancel_resume, record_btrace_step_thread): Change
 local's type to btrace_thread_flags from btrace_thread_flag. Add
 cast in DEBUG call.

gdbsupport/ChangeLog:

 * common/enum-flags.h: Include "traits.h".
 (DEF_ENUM_FLAGS_TYPE): Declare a function instead of defining a
 structure.
 (enum_underlying_type): Update comment.
 (namespace enum_flags_detail): New. Move struct zero_type here.
 (EnumIsUnsigned, EnumIsSigned): New.
 (class enum_flags): Make most methods constexpr.
 (operator&=, operator|=, operator^=): Take an enum_flags instead
 of an enum_type.
 (operator enum_type()): Delete.
 (operator&, operator|, operator^, operator~): Delete, moved out of
 class.
 (raw()): New method.
 (is_enum_flags_enum_type_t): Declare.
 (ENUM_FLAGS_GEN_BINOP, ENUM_FLAGS_GEN_COMPOUND_ASSIGN)
 (ENUM_FLAGS_GEN_COMP): New. Use them to reimplement global
 operators.
 (operator~): Now constexpr and reimplemented.
 (operator<<, operator>>): New deleted functions.
 * valid-expr.h (CHECK_VALID_EXPR_5, CHECK_VALID_EXPR_6): New.

3b64e70... by Pedro Alves <email address hidden>

Use type_instance_flags more throughout

The next patch in this series will rewrites enum_flags fixing some API
holes. That would cause build failures around code using
type_instance_flags. Or rather, that should be using it, but wasn't.

This patch fixes it by using type_instance_flags throughout instead of
plain integers.

Note that we can't make the seemingly obvious change to struct
type::instance_flags:

 - unsigned instance_flags : 9;
 + ENUM_BITFIELD (type_instance_flag_value) instance_flags : 9;

Because G++ complains then that 9 bits isn't sufficient for holding
all values of type_instance_flag_value.

So the patch adds a cast to TYPE_INSTANCE_FLAGS, and adds a separate
SET_TYPE_INSTANCE_FLAGS macro.

gdb/ChangeLog:

 * dwarf2/read.c (read_tag_pointer_type): Use type_instance_flags.
 * eval.c (fake_method::fake_method): Use SET_TYPE_INSTANCE_FLAGS.
 * gdbarch.h, gdbarch.c: Regenerate.
 * gdbarch.sh (address_class_type_flags): Use type_instance_flags.
 (address_class_name_to_type_flags): Use type_instance_flags and
 bool.
 * gdbtypes.c (address_space_name_to_int)
 (address_space_int_to_name, make_qualified_type): Use
 type_instance_flags.
 (make_qualified_type): Use type_instance_flags and
 SET_TYPE_INSTANCE_FLAGS.
 (make_type_with_address_space, make_cv_type, make_vector_type)
 (check_typedef): Use type_instance_flags.
 (recursive_dump_type): Cast type_instance_flags to unsigned for
 printing.
 (copy_type_recursive): Use SET_TYPE_INSTANCE_FLAGS.
 * gdbtypes.h (TYPE_INSTANCE_FLAGS): Return a type_instance_flags.
 (SET_TYPE_INSTANCE_FLAGS): New.
 (address_space_name_to_int, address_space_int_to_name)
 (make_type_with_address_space): Pass flags using
 type_instance_flags instead of int.
 * stabsread.c (cleanup_undefined_types_noname): Use
 SET_TYPE_INSTANCE_FLAGS.
 * type-stack.c (type_stack::follow_types): Use type_instance_flags.

d4049ba... by Pedro Alves <email address hidden>

Rewrite valid-expr.h's internals in terms of the detection idiom (C++17/N4502)

An earlier attempt at doing this had failed (wouldn't work in GCCs
around 4.8, IIRC), but now that I try again, it works. I suspect that
my previous attempt did not use the pre C++14-safe void_t (in
traits.h).

I want to switch to this model because:

 - It's the standard detection idiom that folks will learn starting
   with C++17.

 - In the enum_flags unit tests, I have a static_assert that triggers
   a warning (resulting in build error), which GCC does not suppress
   because the warning is not being triggered in the SFINAE context.
   Switching to the detection idiom fixes that. Alternatively,
   switching to the C++03-style expression-validity checking with a
   varargs overload would allow addressing that, but I think that
   would be going backwards idiomatically speaking.

 - While this patch shows a net increase of lines of code, the magic
   being added to traits.h can be removed in a few years when we start
   requiring C++17.

gdbsupport/ChangeLog:

 * traits.h (struct nonesuch, struct detector, detected_or)
 (detected_or_t, is_detected, detected_t, detected_or)
 (detected_or_t, is_detected_exact, is_detected_convertible): New.
 * valid-expr.h (CHECK_VALID_EXPR_INT): Use gdb::is_detected_exact.

b70e516... by Simon Marchi

gdb: handle the `ptid.is_pid ()` case in registers_changed_ptid

As reported by Tom here [1], commit 888bdb2b7445 ("gdb: change regcache
list to be a map") overlooked an important case, causing a regression.
When registers_changed_ptid is called with a pid-like ptid, it used to
clear all the regcaches for that pid. That commit accidentally removed
that behavior. We need to handle the `ptid.is_pid ()` case in
registers_changed_ptid.

The most trivial way of fixing it would be to iterate on all ptids of a
target and delete the entries where the ptid match the pid. But the
point of that commit was to avoid having to iterate on ptids to
invalidate regcaches, so that would feel like a step backwards.

The only logical solution I see is to add yet another map level, so that
we now have:

  target -> (pid -> (ptid -> regcaches))

This patch implements that and adds a test for the case of calling
registers_changed_ptid with a pid-like ptid.

[1] https://sourceware.org/pipermail/gdb-patches/2020-August/171222.html

gdb/ChangeLog:

 * regcache.c (pid_ptid_regcache_map): New type.
 (target_ptid_regcache_map): Remove.
 (target_pid_ptid_regcache_map): New type.
 (regcaches): Change type to target_pid_ptid_regcache_map.
 (get_thread_arch_aspace_regcache): Update.
 (regcache_thread_ptid_changed): Update, handle pid-like ptid
 case.
 (regcaches_size): Update.
 (regcache_count): Update.
 (registers_changed_ptid_target_pid_test): New.
 (_initialize_regcache): Register new test.

Change-Id: I4c46e26d8225c177dbac9488b549eff4c68fa0d8

cdd9148... by Simon Marchi

gdb: split regcaches management selftest

The selftest `regcaches` selftest is a bit too broad for my taste,
testing the behavior of get_thread_arch_aspace_regcache and various
cases of registers_changed_ptid. Since I'll want to test even more
scenarios of registers_changed_ptid, passing different sets of
parameters, it will be difficult to do in a single test case. It is
difficult to change something at some point in the test case while make
sure it doesn't compromise what comes after, that we still test the
scenarios that we intended to test. So, split the test case in multiple
smaller ones.

- Split the test case in multiple, where each test case starts from
  scratch and tests one specific scenario.

- Introduce the populate_regcaches_for_test function, which is used by
  the various test cases to start with a regcache container populated
  with a few regcaches for two different targets.

- populate_regcaches_for_test returns a regcache_test_data object, which
  contains the test targets that were used to create the regcaches. It
  also takes care to call registers_changed at the beginning and end of
  the test to ensure the test isn't influenced by existing regcaches,
  and cleans up after itself.

- Move the regcache_count lambda function out of
  regcache_thread_ptid_changed, so it can be used in
  other tests.

- For get_thread_arch_aspace_regcache, test that getting a regcache that
  already exists does not increase the count of existing regcaches.

- For registers_changed_ptid, test the three cases we handle today:
  (nullptr, minus_one_ptid), (target, minus_one_ptid) and (target,
  ptid). The (target, minus_one_ptid) case was not tested prior to this
  patch.

gdb/ChangeLog:

 * regcache.c (regcache_count): New.
 (struct regcache_test_data): New.
 (regcache_test_data_up): New.
 (populate_regcaches_for_test): New.
 (regcaches_test): Remove.
 (get_thread_arch_aspace_regcache_test): New.
 (registers_changed_ptid_all_test): New.
 (registers_changed_ptid_target_test): New.
 (registers_changed_ptid_target_ptid_test): New.
 (regcache_thread_ptid_changed): Remove regcache_count lambda.
 (_initialize_regcache): Register new tests.

Change-Id: Id4280879fb40ff3aeae49b01b95359e1359c3d4b

dd12534... by Simon Marchi

gdb: refactor test_get_thread_arch_aspace_regcache

Do these misc changes to test_get_thread_arch_aspace_regcache:

- Rename to get_thread_arch_aspace_regcache_and_check. The following
  patch introduces a selftest for get_thread_arch_aspace_regcache, named
  get_thread_arch_aspace_regcache_test. To avoid confusion between the
  two functions, rename this one to
  get_thread_arch_aspace_regcache_and_check, I think it describes better
  what it does.

- Remove gdbarch parameter. We always pass the same gdbarch (the
  current inferior's gdbarch), so having a parameter is not useful. It
  would be interesting to actually test with multiple gdbarches, to
  verify that the regcache container can hold multiple regcaches (with
  different architectures) for a same (target, ptid). But it's not the
  case as of this patch.

- Verify that the regcache's arch is correctly set.

- Remove the aspace parameter. We always pass NULL here, so it's not
  useful to have it as a parameter. Also, instead of passing a NULL
  aspace to get_thread_arch_aspace_regcache and verifying that we get a
  NULL aspace back, pass the current inferior's aspace (just like we use
  the current inferior's gdbarch).

gdb/ChangeLog:

 * regcache.c (test_get_thread_arch_aspace_regcache): Rename to...
 (get_thread_arch_aspace_regcache_and_check): ... this. Remove
 gdbarch and aspace parameter. Use current inferior's aspace.
 Validate regcache's arch value.
 (regcaches_test): Update.

Change-Id: I8b4c2303b4f91f062269043d1f7abe1650232010

3ee9397... by Simon Marchi

gdb: clear regcaches at the start of regcaches selftest

It currently does not work to run the `regcaches` selftest while
debugging something. This is because we expect that there exists no
regcache at the start of the test. If we are debugging something, there
might exist some regcaches.

Fix it by making the test clear regcaches at the start.

While at it, make the test clean up after it self and clear the
regcaches at the end too.

gdb/ChangeLog:

 * regcache.c (regcaches_test): Call registers_changed.

Change-Id: I9d4f83ecb0ff9721a71e2c5cbd19e6e6d4e6c30c

01147b2... by Nick Clifton <email address hidden>

Ensure that compressed sections that have an ELF compression header structure at the start are correctly aligned.

 PR 26428
bfd * bfd.c (bfd_update_compression_header): Also set the sh_addralign
 field in the ELF header of the compressed sections.

ld * testsuite/ld-elf/zlibbegin.rS: Update expected output.
 * testsuite/ld-elf/zlibnormal.rS: Likewise.

33bf4c5... by Tankut Baris Aktemur <email address hidden>

gdb: fix typo "breapoint" -> "breakpoint"

gdb/ChangeLog:
2020-08-20 Tankut Baris Aktemur <email address hidden>

 * infrun.c (process_event_stop_test): Fix typo "breapoint".

gdb/testsuite/ChangeLog:
2020-08-20 Tankut Baris Aktemur <email address hidden>

 * gdb.base/print-file-var.exp: Fix typo "breapoint".
 * gdb.trace/strace.exp: Ditto.

44466e4... by Nick Clifton <email address hidden>

Apply a workaround to mitigate a quadratic performance hit in the linker when writing out secondary reloc sections.

 PR 26406
 * elf-bfd.h (struct bfd_elf_section_data): Add
 has_secondary_relocs field.
 * elf.c (_bfd_elf_copy_special_section_fields): Set the
 has_secondary_relocs field for sections which have associated
 secondary relocs.
 * elfcode.h (elf_write_relocs): Only call write_secondary_relocs
 on sections which have associated secondary relocs.