[v5,2/5] gdb: add "unwinder class" to frame unwinders

Message ID 20241001184235.3710608-3-guinevere@redhat.com
State New
Headers
Series Modernize frame unwinders and add disable feature |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed

Commit Message

Guinevere Larsen Oct. 1, 2024, 6:42 p.m. UTC
  From: Guinevere Larsen <blarsen@redhat.com>

A future patch will add a way to disable certain unwinders based on
different characteristics. This patch aims to make it more convenient
to disable related unwinders in bulk, such as architecture specific
ones, by indentifying all unwinders by which part of the code adds it.
The classes, and explanations, are as follows:

* GDB: An internal unwinder, added by GDB core, such as the unwinder
  for dummy frames;
* EXTENSION: Unwinders added by extension languages;
* DEBUGINFO: Unwinders installed by the debug info reader;
* ARCH: Unwinders installed by the architecture specific code.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
 gdb/NEWS                    |  4 ++++
 gdb/aarch64-tdep.c          |  2 ++
 gdb/alpha-mdebug-tdep.c     |  1 +
 gdb/alpha-tdep.c            |  2 ++
 gdb/amd64-obsd-tdep.c       |  1 +
 gdb/amd64-tdep.c            |  4 ++++
 gdb/amd64-windows-tdep.c    |  1 +
 gdb/amdgpu-tdep.c           |  1 +
 gdb/arc-tdep.c              |  2 ++
 gdb/arm-tdep.c              |  5 +++++
 gdb/avr-tdep.c              |  1 +
 gdb/bfin-tdep.c             |  1 +
 gdb/bpf-tdep.c              |  1 +
 gdb/cris-tdep.c             |  2 ++
 gdb/csky-tdep.c             |  2 ++
 gdb/doc/gdb.texinfo         | 15 ++++++++++++++-
 gdb/dummy-frame.c           |  1 +
 gdb/dwarf2/frame-tailcall.c |  1 +
 gdb/dwarf2/frame.c          |  2 ++
 gdb/frame-unwind.c          | 24 +++++++++++++++++++++++-
 gdb/frame-unwind.h          | 17 +++++++++++++++++
 gdb/frv-linux-tdep.c        |  1 +
 gdb/frv-tdep.c              |  1 +
 gdb/ft32-tdep.c             |  1 +
 gdb/h8300-tdep.c            |  1 +
 gdb/hppa-linux-tdep.c       |  1 +
 gdb/hppa-tdep.c             |  3 +++
 gdb/i386-obsd-tdep.c        |  1 +
 gdb/i386-tdep.c             |  5 +++++
 gdb/ia64-tdep.c             |  4 ++++
 gdb/inline-frame.c          |  1 +
 gdb/iq2000-tdep.c           |  1 +
 gdb/jit.c                   |  1 +
 gdb/lm32-tdep.c             |  1 +
 gdb/loongarch-tdep.c        |  1 +
 gdb/m32c-tdep.c             |  1 +
 gdb/m32r-linux-tdep.c       |  1 +
 gdb/m32r-tdep.c             |  1 +
 gdb/m68hc11-tdep.c          |  1 +
 gdb/m68k-linux-tdep.c       |  1 +
 gdb/m68k-tdep.c             |  1 +
 gdb/mep-tdep.c              |  1 +
 gdb/microblaze-tdep.c       |  1 +
 gdb/mips-sde-tdep.c         |  1 +
 gdb/mips-tdep.c             |  4 ++++
 gdb/mn10300-tdep.c          |  1 +
 gdb/moxie-tdep.c            |  1 +
 gdb/msp430-tdep.c           |  1 +
 gdb/nds32-tdep.c            |  2 ++
 gdb/nios2-tdep.c            |  2 ++
 gdb/or1k-tdep.c             |  1 +
 gdb/ppc-fbsd-tdep.c         |  1 +
 gdb/ppc-obsd-tdep.c         |  1 +
 gdb/python/py-unwind.c      |  1 +
 gdb/record-btrace.c         |  2 ++
 gdb/riscv-tdep.c            |  1 +
 gdb/rl78-tdep.c             |  1 +
 gdb/rs6000-aix-tdep.c       |  1 +
 gdb/rs6000-tdep.c           |  2 ++
 gdb/rx-tdep.c               |  2 ++
 gdb/s12z-tdep.c             |  1 +
 gdb/s390-linux-tdep.c       |  1 +
 gdb/s390-tdep.c             |  2 ++
 gdb/sentinel-frame.c        |  1 +
 gdb/sh-tdep.c               |  2 ++
 gdb/sparc-netbsd-tdep.c     |  1 +
 gdb/sparc-obsd-tdep.c       |  1 +
 gdb/sparc-sol2-tdep.c       |  1 +
 gdb/sparc-tdep.c            |  1 +
 gdb/sparc64-fbsd-tdep.c     |  1 +
 gdb/sparc64-netbsd-tdep.c   |  1 +
 gdb/sparc64-obsd-tdep.c     |  2 ++
 gdb/sparc64-sol2-tdep.c     |  1 +
 gdb/sparc64-tdep.c          |  1 +
 gdb/tic6x-tdep.c            |  2 ++
 gdb/tilegx-tdep.c           |  1 +
 gdb/tramp-frame.c           |  1 +
 gdb/v850-tdep.c             |  1 +
 gdb/vax-tdep.c              |  1 +
 gdb/xstormy16-tdep.c        |  1 +
 gdb/xtensa-tdep.c           |  1 +
 gdb/z80-tdep.c              |  1 +
 82 files changed, 170 insertions(+), 2 deletions(-)
  

Comments

Thiago Jung Bauermann Oct. 2, 2024, 10:08 p.m. UTC | #1
Guinevere Larsen <guinevere@redhat.com> writes:

> From: Guinevere Larsen <blarsen@redhat.com>
>
> A future patch will add a way to disable certain unwinders based on
> different characteristics. This patch aims to make it more convenient
> to disable related unwinders in bulk, such as architecture specific
> ones, by indentifying all unwinders by which part of the code adds it.
> The classes, and explanations, are as follows:
>
> * GDB: An internal unwinder, added by GDB core, such as the unwinder
>   for dummy frames;
> * EXTENSION: Unwinders added by extension languages;
> * DEBUGINFO: Unwinders installed by the debug info reader;
> * ARCH: Unwinders installed by the architecture specific code.
>
> Reviewed-By: Eli Zaretskii <eliz@gnu.org>

Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
  
Simon Marchi Oct. 3, 2024, 6:46 p.m. UTC | #2
On 10/1/24 2:42 PM, Guinevere Larsen wrote:
> From: Guinevere Larsen <blarsen@redhat.com>
> 
> A future patch will add a way to disable certain unwinders based on
> different characteristics. This patch aims to make it more convenient
> to disable related unwinders in bulk, such as architecture specific
> ones, by indentifying all unwinders by which part of the code adds it.

indentifying -> identifying

> diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c
> index b69ae8596a2..afc1258c6a9 100644
> --- a/gdb/frame-unwind.c
> +++ b/gdb/frame-unwind.c
> @@ -30,6 +30,17 @@
>  #include "dwarf2/frame-tailcall.h"
>  #include "cli/cli-cmds.h"
>  #include "inferior.h"
> +#include <map>
> +
> +/* Conversion list between the enum for frame_unwind_class and
> +   string.  */
> +static std::map<enum frame_unwind_class, const char *> unwind_class_conversion =
> +{
> +  {FRAME_UNWIND_GDB, "GDB"},
> +  {FRAME_UNWIND_ARCH, "ARCH"},
> +  {FRAME_UNWIND_EXTENSION, "EXTENSION"},
> +  {FRAME_UNWIND_DEBUGINFO, "DEBUGINFO"},
> +};

It's not reaaally a big deal, but using an std::map for this is kind of
heavyweight.  It could probably be a simple array, still indexed by the
enum value.  Personally, I used functions with switches to handle cases
this (see target_waitkind_str), because compilers can warn you if you
forget to handle an enumerator (which can easily happen when a new one
is added).

Otherwise, a more medium-term but clean solution would be to integrate
one of these libs in GDB:

https://github.com/Neargye/magic_enum
https://github.com/quicknir/wise_enum

I use the latter in another project, and it works nicely.

Otherwise, LGTM:

Approved-By: Simon Marchi <simon.marchi@efficios.com>

Simon
  
Guinevere Larsen Oct. 8, 2024, 6:22 p.m. UTC | #3
On 10/3/24 3:46 PM, Simon Marchi wrote:
> On 10/1/24 2:42 PM, Guinevere Larsen wrote:
>> From: Guinevere Larsen <blarsen@redhat.com>
>>
>> A future patch will add a way to disable certain unwinders based on
>> different characteristics. This patch aims to make it more convenient
>> to disable related unwinders in bulk, such as architecture specific
>> ones, by indentifying all unwinders by which part of the code adds it.
> indentifying -> identifying
>
>> diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c
>> index b69ae8596a2..afc1258c6a9 100644
>> --- a/gdb/frame-unwind.c
>> +++ b/gdb/frame-unwind.c
>> @@ -30,6 +30,17 @@
>>   #include "dwarf2/frame-tailcall.h"
>>   #include "cli/cli-cmds.h"
>>   #include "inferior.h"
>> +#include <map>
>> +
>> +/* Conversion list between the enum for frame_unwind_class and
>> +   string.  */
>> +static std::map<enum frame_unwind_class, const char *> unwind_class_conversion =
>> +{
>> +  {FRAME_UNWIND_GDB, "GDB"},
>> +  {FRAME_UNWIND_ARCH, "ARCH"},
>> +  {FRAME_UNWIND_EXTENSION, "EXTENSION"},
>> +  {FRAME_UNWIND_DEBUGINFO, "DEBUGINFO"},
>> +};
> It's not reaaally a big deal, but using an std::map for this is kind of
> heavyweight.  It could probably be a simple array, still indexed by the
> enum value.  Personally, I used functions with switches to handle cases
> this (see target_waitkind_str), because compilers can warn you if you
> forget to handle an enumerator (which can easily happen when a new one
> is added).

Since I have 2 functions, one to convert from enum to string, and 
another from string to enum, I'll go with a simple array that makes it 
easy to do both.

This is my proposed change:

diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c
index ef05b658f94..10d9f2e9f88 100644
--- a/gdb/frame-unwind.c
+++ b/gdb/frame-unwind.c
@@ -34,12 +34,12 @@

  /* Conversion list between the enum for frame_unwind_class and
     string. */
-static std::map<enum frame_unwind_class, const char *> 
unwind_class_conversion =
+static const char * unwind_class_conversion[] =
  {
-  {FRAME_UNWIND_GDB, "GDB"},
-  {FRAME_UNWIND_ARCH, "ARCH"},
-  {FRAME_UNWIND_EXTENSION, "EXTENSION"},
-  {FRAME_UNWIND_DEBUGINFO, "DEBUGINFO"},
+ "GDB",
+ "ARCH",
+ "EXTENSION",
+ "DEBUGINFO",
  };

  /* Default sniffers, that must always be the first in the unwinder list,
@@ -88,9 +88,8 @@ get_frame_unwind_table (struct gdbarch *gdbarch)
  static const char *
  frame_unwinder_class_str (frame_unwind_class uclass)
  {
-  auto location = unwind_class_conversion.find (uclass);
-  gdb_assert (location != unwind_class_conversion.end ());
-  return location->second;
+  gdb_assert (uclass < UNWIND_CLASS_NUMBER);
+  return unwind_class_conversion[uclass];
  }

  /* Case insensitive search for a frame_unwind_class based on the given
@@ -102,10 +101,10 @@ str_to_frame_unwind_class (const char *class_str)
    /* Skip the prefix if present. */
    if (strncasecmp (class_str, prefix, strlen(prefix)) == 0)
      class_str += strlen (prefix);
-  for (const auto &it : unwind_class_conversion)
+  for (int i = 0; i < UNWIND_CLASS_NUMBER; i++)
{
-      if (strcasecmp (it.second, class_str) == 0)
-       return it.first;
+      if (strcasecmp (unwind_class_conversion[i], class_str) == 0)
+       return (frame_unwind_class) i;
}
    error (_("Unknown frame unwind class: %s"), class_str);
  }
diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h
index f5ea8d9f690..555a5d98d5b 100644
--- a/gdb/frame-unwind.h
+++ b/gdb/frame-unwind.h
@@ -167,6 +167,8 @@ enum frame_unwind_class
FRAME_UNWIND_DEBUGINFO,
    /* The unwinder was created and handles target dependent things.  */
FRAME_UNWIND_ARCH,
+  /* Meta enum value, to ensure we're always sent a valid unwinder 
class.  */
+ UNWIND_CLASS_NUMBER,
  };

>
> Otherwise, a more medium-term but clean solution would be to integrate
> one of these libs in GDB:
>
> https://github.com/Neargye/magic_enum
> https://github.com/quicknir/wise_enum
>
> I use the latter in another project, and it works nicely.
>
> Otherwise, LGTM:
>
> Approved-By: Simon Marchi <simon.marchi@efficios.com>
Can I add the tag with that change? (just making sure you're ok with my 
solution (: )
  
Simon Marchi Oct. 8, 2024, 6:37 p.m. UTC | #4
On 2024-10-08 14:22, Guinevere Larsen wrote:
> On 10/3/24 3:46 PM, Simon Marchi wrote:
>> On 10/1/24 2:42 PM, Guinevere Larsen wrote:
>>> From: Guinevere Larsen <blarsen@redhat.com>
>>>
>>> A future patch will add a way to disable certain unwinders based on
>>> different characteristics. This patch aims to make it more convenient
>>> to disable related unwinders in bulk, such as architecture specific
>>> ones, by indentifying all unwinders by which part of the code adds it.
>> indentifying -> identifying
>>
>>> diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c
>>> index b69ae8596a2..afc1258c6a9 100644
>>> --- a/gdb/frame-unwind.c
>>> +++ b/gdb/frame-unwind.c
>>> @@ -30,6 +30,17 @@
>>>   #include "dwarf2/frame-tailcall.h"
>>>   #include "cli/cli-cmds.h"
>>>   #include "inferior.h"
>>> +#include <map>
>>> +
>>> +/* Conversion list between the enum for frame_unwind_class and
>>> +   string.  */
>>> +static std::map<enum frame_unwind_class, const char *> unwind_class_conversion =
>>> +{
>>> +  {FRAME_UNWIND_GDB, "GDB"},
>>> +  {FRAME_UNWIND_ARCH, "ARCH"},
>>> +  {FRAME_UNWIND_EXTENSION, "EXTENSION"},
>>> +  {FRAME_UNWIND_DEBUGINFO, "DEBUGINFO"},
>>> +};
>> It's not reaaally a big deal, but using an std::map for this is kind of
>> heavyweight.  It could probably be a simple array, still indexed by the
>> enum value.  Personally, I used functions with switches to handle cases
>> this (see target_waitkind_str), because compilers can warn you if you
>> forget to handle an enumerator (which can easily happen when a new one
>> is added).
> 
> Since I have 2 functions, one to convert from enum to string, and another from string to enum, I'll go with a simple array that makes it easy to do both.
> 
> This is my proposed change:
> 
> diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c
> index ef05b658f94..10d9f2e9f88 100644
> --- a/gdb/frame-unwind.c
> +++ b/gdb/frame-unwind.c
> @@ -34,12 +34,12 @@
> 
>  /* Conversion list between the enum for frame_unwind_class and
>     string. */
> -static std::map<enum frame_unwind_class, const char *> unwind_class_conversion =
> +static const char * unwind_class_conversion[] =

I think we don't want a space after the `*`.

>  {
> -  {FRAME_UNWIND_GDB, "GDB"},
> -  {FRAME_UNWIND_ARCH, "ARCH"},
> -  {FRAME_UNWIND_EXTENSION, "EXTENSION"},
> -  {FRAME_UNWIND_DEBUGINFO, "DEBUGINFO"},
> + "GDB",
> + "ARCH",
> + "EXTENSION",
> + "DEBUGINFO",
>  };
> 
>  /* Default sniffers, that must always be the first in the unwinder list,
> @@ -88,9 +88,8 @@ get_frame_unwind_table (struct gdbarch *gdbarch)
>  static const char *
>  frame_unwinder_class_str (frame_unwind_class uclass)
>  {
> -  auto location = unwind_class_conversion.find (uclass);
> -  gdb_assert (location != unwind_class_conversion.end ());
> -  return location->second;
> +  gdb_assert (uclass < UNWIND_CLASS_NUMBER);
> +  return unwind_class_conversion[uclass];
>  }
> 
>  /* Case insensitive search for a frame_unwind_class based on the given
> @@ -102,10 +101,10 @@ str_to_frame_unwind_class (const char *class_str)
>    /* Skip the prefix if present. */
>    if (strncasecmp (class_str, prefix, strlen(prefix)) == 0)
>      class_str += strlen (prefix);
> -  for (const auto &it : unwind_class_conversion)
> +  for (int i = 0; i < UNWIND_CLASS_NUMBER; i++)
> {
> -      if (strcasecmp (it.second, class_str) == 0)
> -       return it.first;
> +      if (strcasecmp (unwind_class_conversion[i], class_str) == 0)
> +       return (frame_unwind_class) i;

I'd suggest using static_cast instead of a C-style cast, since we use
C++.  Otherwise this diff LGTM.

> }
>    error (_("Unknown frame unwind class: %s"), class_str);
>  }
> diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h
> index f5ea8d9f690..555a5d98d5b 100644
> --- a/gdb/frame-unwind.h
> +++ b/gdb/frame-unwind.h
> @@ -167,6 +167,8 @@ enum frame_unwind_class
> FRAME_UNWIND_DEBUGINFO,
>    /* The unwinder was created and handles target dependent things.  */
> FRAME_UNWIND_ARCH,
> +  /* Meta enum value, to ensure we're always sent a valid unwinder class.  */
> + UNWIND_CLASS_NUMBER,
>  };

I thought I made the suggestion to use "enum class" for new stuff, but
now I can't find it.

>> Approved-By: Simon Marchi <simon.marchi@efficios.com>
> Can I add the tag with that change? (just making sure you're ok with my solution (: )

Yes, I'm fine with you addressing these comments without a further
review (although I guess it would make sense to wait until the whole
series is approved before pushing, in case this needs to change):

Approved-By: Simon Marchi <simon.marchi@efficios.com>

Simon
  

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 3a0c8d1049f..6c5def83529 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -107,6 +107,10 @@  maintenance print remote-registers
   which registers were included in the last stop reply packet received by
   GDB.
 
+mainenance info frame-unwinders
+  Add a CLASS column to the output.  This class is a somewhat arbitrary
+  grouping of unwinders, based on which area of GDB adds the unwinder.
+
 * New remote packets
 
 vFile:stat
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 8a2a9b1e23c..3989c619e0b 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -1209,6 +1209,7 @@  static frame_unwind aarch64_prologue_unwind =
 {
   "aarch64 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   aarch64_prologue_frame_unwind_stop_reason,
   aarch64_prologue_this_id,
   aarch64_prologue_prev_register,
@@ -1304,6 +1305,7 @@  static frame_unwind aarch64_stub_unwind =
 {
   "aarch64 stub",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   aarch64_stub_frame_unwind_stop_reason,
   aarch64_stub_this_id,
   aarch64_prologue_prev_register,
diff --git a/gdb/alpha-mdebug-tdep.c b/gdb/alpha-mdebug-tdep.c
index abded2ac192..b087afabae7 100644
--- a/gdb/alpha-mdebug-tdep.c
+++ b/gdb/alpha-mdebug-tdep.c
@@ -334,6 +334,7 @@  static const struct frame_unwind alpha_mdebug_frame_unwind =
 {
   "alpha mdebug",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   alpha_mdebug_frame_this_id,
   alpha_mdebug_frame_prev_register,
diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c
index fa042b252b0..f55bf2c8661 100644
--- a/gdb/alpha-tdep.c
+++ b/gdb/alpha-tdep.c
@@ -1011,6 +1011,7 @@  static const struct frame_unwind alpha_sigtramp_frame_unwind =
 {
   "alpha sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   alpha_sigtramp_frame_this_id,
   alpha_sigtramp_frame_prev_register,
@@ -1430,6 +1431,7 @@  static const struct frame_unwind alpha_heuristic_frame_unwind =
 {
   "alpha prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   alpha_heuristic_frame_this_id,
   alpha_heuristic_frame_prev_register,
diff --git a/gdb/amd64-obsd-tdep.c b/gdb/amd64-obsd-tdep.c
index 5b1e77b3e86..5359959e3bb 100644
--- a/gdb/amd64-obsd-tdep.c
+++ b/gdb/amd64-obsd-tdep.c
@@ -409,6 +409,7 @@  static const struct frame_unwind amd64obsd_trapframe_unwind =
      which really is not what we want here.  */
   "amd64 openbsd trap",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   amd64obsd_trapframe_this_id,
   amd64obsd_trapframe_prev_register,
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index b63e35d522a..0701424e5a5 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -2670,6 +2670,7 @@  static const struct frame_unwind amd64_frame_unwind =
 {
   "amd64 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   amd64_frame_unwind_stop_reason,
   amd64_frame_this_id,
   amd64_frame_prev_register,
@@ -2816,6 +2817,7 @@  static const struct frame_unwind amd64_sigtramp_frame_unwind =
 {
   "amd64 sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   amd64_sigtramp_frame_unwind_stop_reason,
   amd64_sigtramp_frame_this_id,
   amd64_sigtramp_frame_prev_register,
@@ -3008,6 +3010,7 @@  static const struct frame_unwind amd64_epilogue_override_frame_unwind =
 {
   "amd64 epilogue override",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   amd64_epilogue_frame_unwind_stop_reason,
   amd64_epilogue_frame_this_id,
   amd64_frame_prev_register,
@@ -3019,6 +3022,7 @@  static const struct frame_unwind amd64_epilogue_frame_unwind =
 {
   "amd64 epilogue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   amd64_epilogue_frame_unwind_stop_reason,
   amd64_epilogue_frame_this_id,
   amd64_frame_prev_register,
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index 5adc7d57f4b..2e3996b7b47 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -1185,6 +1185,7 @@  static const struct frame_unwind amd64_windows_frame_unwind =
 {
   "amd64 windows",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   &amd64_windows_frame_this_id,
   &amd64_windows_frame_prev_register,
diff --git a/gdb/amdgpu-tdep.c b/gdb/amdgpu-tdep.c
index 6fe79732158..b8a5fd80fa0 100644
--- a/gdb/amdgpu-tdep.c
+++ b/gdb/amdgpu-tdep.c
@@ -892,6 +892,7 @@  amdgpu_frame_prev_register (const frame_info_ptr &this_frame, void **this_cache,
 static const frame_unwind amdgpu_frame_unwind = {
   "amdgpu",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   amdgpu_frame_this_id,
   amdgpu_frame_prev_register,
diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index 4fc1ea1dc46..ac77fcd7a3b 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -1913,6 +1913,7 @@  arc_sigtramp_frame_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind arc_frame_unwind = {
   "arc prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   arc_frame_this_id,
   arc_frame_prev_register,
@@ -1929,6 +1930,7 @@  static const struct frame_unwind arc_frame_unwind = {
 static const struct frame_unwind arc_sigtramp_frame_unwind = {
   "arc sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   arc_sigtramp_frame_this_id,
   arc_sigtramp_frame_prev_register,
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 6b235a057b0..3818716586b 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -2469,6 +2469,7 @@  arm_prologue_prev_register (const frame_info_ptr &this_frame,
 static frame_unwind arm_prologue_unwind = {
   "arm prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   arm_prologue_unwind_stop_reason,
   arm_prologue_this_id,
   arm_prologue_prev_register,
@@ -3188,6 +3189,7 @@  arm_exidx_unwind_sniffer (const struct frame_unwind *self,
 struct frame_unwind arm_exidx_unwind = {
   "arm exidx",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   arm_prologue_this_id,
   arm_prologue_prev_register,
@@ -3298,6 +3300,7 @@  static const struct frame_unwind arm_epilogue_frame_unwind =
 {
   "arm epilogue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   arm_epilogue_frame_this_id,
   arm_epilogue_frame_prev_register,
@@ -3427,6 +3430,7 @@  arm_stub_unwind_sniffer (const struct frame_unwind *self,
 struct frame_unwind arm_stub_unwind = {
   "arm stub",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   arm_stub_this_id,
   arm_prologue_prev_register,
@@ -3953,6 +3957,7 @@  struct frame_unwind arm_m_exception_unwind =
 {
   "arm m exception lockup sec_fnc",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   arm_m_exception_frame_unwind_stop_reason,
   arm_m_exception_this_id,
   arm_m_exception_prev_register,
diff --git a/gdb/avr-tdep.c b/gdb/avr-tdep.c
index 9c97d3cf1c7..08b3cb146f4 100644
--- a/gdb/avr-tdep.c
+++ b/gdb/avr-tdep.c
@@ -1158,6 +1158,7 @@  avr_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind avr_frame_unwind = {
   "avr prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   avr_frame_this_id,
   avr_frame_prev_register,
diff --git a/gdb/bfin-tdep.c b/gdb/bfin-tdep.c
index 1fa7a66d043..60838f0548e 100644
--- a/gdb/bfin-tdep.c
+++ b/gdb/bfin-tdep.c
@@ -376,6 +376,7 @@  static const struct frame_unwind bfin_frame_unwind =
 {
   "bfin prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   bfin_frame_this_id,
   bfin_frame_prev_register,
diff --git a/gdb/bpf-tdep.c b/gdb/bpf-tdep.c
index 79a442068b5..1f53d63c982 100644
--- a/gdb/bpf-tdep.c
+++ b/gdb/bpf-tdep.c
@@ -185,6 +185,7 @@  static const struct frame_unwind bpf_frame_unwind =
 {
   "bpf prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   bpf_frame_unwind_stop_reason,
   bpf_frame_this_id,
   bpf_frame_prev_register,
diff --git a/gdb/cris-tdep.c b/gdb/cris-tdep.c
index 769b9304165..f532c41d261 100644
--- a/gdb/cris-tdep.c
+++ b/gdb/cris-tdep.c
@@ -439,6 +439,7 @@  static const struct frame_unwind cris_sigtramp_frame_unwind =
 {
   "cris sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   cris_sigtramp_frame_this_id,
   cris_sigtramp_frame_prev_register,
@@ -904,6 +905,7 @@  static const struct frame_unwind cris_frame_unwind =
 {
   "cris prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   cris_frame_this_id,
   cris_frame_prev_register,
diff --git a/gdb/csky-tdep.c b/gdb/csky-tdep.c
index d69b8e5a2ca..6e8426fe2d8 100644
--- a/gdb/csky-tdep.c
+++ b/gdb/csky-tdep.c
@@ -2162,6 +2162,7 @@  csky_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind csky_unwind_cache = {
   "cski prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   csky_frame_this_id,
   csky_frame_prev_register,
@@ -2296,6 +2297,7 @@  csky_stub_prev_register (const frame_info_ptr &this_frame,
 static frame_unwind csky_stub_unwind = {
   "csky stub",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   csky_stub_this_id,
   csky_stub_prev_register,
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index cc1b69c6978..faca1e988fd 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -42207,7 +42207,20 @@  architecture, then enabling this flag does not cause them to be used.
 
 @kindex maint info frame-unwinders
 @item maint info frame-unwinders
-List the frame unwinders currently in effect, starting with the highest priority.
+List the frame unwinders currently in effect, starting with the highest
+priority.  This also lists the unwinder class, which is mostly defined by
+which area of @value{GDBN} uses it.  The currently available classes are:
+
+@table @samp
+@item GDB
+Internal unwinders, added by @value{GDBN} core.
+@item EXTENSION
+Unwinders added by extension languages.
+@item DEBUGINFO
+Unwinders installed by debug information readers.
+@item ARCH
+Unwinders installed by the architecture specific code.
+@end table
 
 @kindex maint set worker-threads
 @kindex maint show worker-threads
diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c
index 9f540d02f1a..e7de15b5c4d 100644
--- a/gdb/dummy-frame.c
+++ b/gdb/dummy-frame.c
@@ -379,6 +379,7 @@  const struct frame_unwind dummy_frame_unwind =
 {
   "dummy",
   DUMMY_FRAME,
+  FRAME_UNWIND_GDB,
   default_frame_unwind_stop_reason,
   dummy_frame_this_id,
   dummy_frame_prev_register,
diff --git a/gdb/dwarf2/frame-tailcall.c b/gdb/dwarf2/frame-tailcall.c
index 6ecf8a0b15d..50efd4eb5ff 100644
--- a/gdb/dwarf2/frame-tailcall.c
+++ b/gdb/dwarf2/frame-tailcall.c
@@ -472,6 +472,7 @@  const struct frame_unwind dwarf2_tailcall_frame_unwind =
 {
   "dwarf2 tailcall",
   TAILCALL_FRAME,
+  FRAME_UNWIND_DEBUGINFO,
   default_frame_unwind_stop_reason,
   tailcall_frame_this_id,
   tailcall_frame_prev_register,
diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
index 79ef065bfcb..c51e8c16147 100644
--- a/gdb/dwarf2/frame.c
+++ b/gdb/dwarf2/frame.c
@@ -1341,6 +1341,7 @@  static const struct frame_unwind dwarf2_frame_unwind =
 {
   "dwarf2",
   NORMAL_FRAME,
+  FRAME_UNWIND_DEBUGINFO,
   dwarf2_frame_unwind_stop_reason,
   dwarf2_frame_this_id,
   dwarf2_frame_prev_register,
@@ -1353,6 +1354,7 @@  static const struct frame_unwind dwarf2_signal_frame_unwind =
 {
   "dwarf2 signal",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_DEBUGINFO,
   dwarf2_frame_unwind_stop_reason,
   dwarf2_frame_this_id,
   dwarf2_frame_prev_register,
diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c
index b69ae8596a2..afc1258c6a9 100644
--- a/gdb/frame-unwind.c
+++ b/gdb/frame-unwind.c
@@ -30,6 +30,17 @@ 
 #include "dwarf2/frame-tailcall.h"
 #include "cli/cli-cmds.h"
 #include "inferior.h"
+#include <map>
+
+/* Conversion list between the enum for frame_unwind_class and
+   string.  */
+static std::map<enum frame_unwind_class, const char *> unwind_class_conversion =
+{
+  {FRAME_UNWIND_GDB, "GDB"},
+  {FRAME_UNWIND_ARCH, "ARCH"},
+  {FRAME_UNWIND_EXTENSION, "EXTENSION"},
+  {FRAME_UNWIND_DEBUGINFO, "DEBUGINFO"},
+};
 
 /* Default sniffers, that must always be the first in the unwinder list,
    no matter the architecture.  */
@@ -75,6 +86,14 @@  get_frame_unwind_table (struct gdbarch *gdbarch)
   return table;
 }
 
+static const char *
+frame_unwinder_class_str (frame_unwind_class uclass)
+{
+  auto location = unwind_class_conversion.find (uclass);
+  gdb_assert (location != unwind_class_conversion.end ());
+  return location->second;
+}
+
 void
 frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
 				const struct frame_unwind *unwinder)
@@ -322,19 +341,22 @@  maintenance_info_frame_unwinders (const char *args, int from_tty)
   std::vector<const frame_unwind *> &table = get_frame_unwind_table (gdbarch);
 
   ui_out *uiout = current_uiout;
-  ui_out_emit_table table_emitter (uiout, 2, -1, "FrameUnwinders");
+  ui_out_emit_table table_emitter (uiout, 3, -1, "FrameUnwinders");
   uiout->table_header (27, ui_left, "name", "Name");
   uiout->table_header (25, ui_left, "type", "Type");
+  uiout->table_header (9, ui_left, "class", "Class");
   uiout->table_body ();
 
   for (auto unwinder : table)
     {
       const char *name = unwinder->name;
       const char *type = frame_type_str (unwinder->type);
+      const char *uclass = frame_unwinder_class_str (unwinder->unwinder_class);
 
       ui_out_emit_list tuple_emitter (uiout, nullptr);
       uiout->field_string ("name", name);
       uiout->field_string ("type", type);
+      uiout->field_string ("class", uclass);
       uiout->text ("\n");
     }
 }
diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h
index 53fcd6869e9..deab4f7dbfb 100644
--- a/gdb/frame-unwind.h
+++ b/gdb/frame-unwind.h
@@ -156,12 +156,29 @@  typedef void (frame_dealloc_cache_ftype) (frame_info *self,
 typedef gdbarch *(frame_prev_arch_ftype) (const frame_info_ptr &this_frame,
 					  void **this_prologue_cache);
 
+/* Unwinders are classified by what part of GDB code created it.  */
+enum frame_unwind_class
+{
+  /* This is mostly handled by core GDB code.  */
+  FRAME_UNWIND_GDB,
+  /* This unwinder was added by one of GDB's extension languages.  */
+  FRAME_UNWIND_EXTENSION,
+  /* The unwinder was created and mostly handles debug information.  */
+  FRAME_UNWIND_DEBUGINFO,
+  /* The unwinder was created and handles target dependent things.  */
+  FRAME_UNWIND_ARCH,
+};
+
 struct frame_unwind
 {
   const char *name;
   /* The frame's type.  Should this instead be a collection of
      predicates that test the frame for various attributes?  */
   enum frame_type type;
+  /* What kind of unwinder is this.  It generally follows from where
+     the unwinder was added or where it looks for information to do the
+     unwinding.  */
+  enum frame_unwind_class unwinder_class;
   /* Should an attribute indicating the frame's address-in-block go
      here?  */
   frame_unwind_stop_reason_ftype *stop_reason;
diff --git a/gdb/frv-linux-tdep.c b/gdb/frv-linux-tdep.c
index 46424453ef0..7a7c4904475 100644
--- a/gdb/frv-linux-tdep.c
+++ b/gdb/frv-linux-tdep.c
@@ -336,6 +336,7 @@  static const struct frame_unwind frv_linux_sigtramp_frame_unwind =
 {
   "frv linux sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   frv_linux_sigtramp_frame_this_id,
   frv_linux_sigtramp_frame_prev_register,
diff --git a/gdb/frv-tdep.c b/gdb/frv-tdep.c
index 6ae3f0d0f55..a1845a25750 100644
--- a/gdb/frv-tdep.c
+++ b/gdb/frv-tdep.c
@@ -1407,6 +1407,7 @@  frv_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind frv_frame_unwind = {
   "frv prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   frv_frame_this_id,
   frv_frame_prev_register,
diff --git a/gdb/ft32-tdep.c b/gdb/ft32-tdep.c
index 15a585a356e..e3827ad96e7 100644
--- a/gdb/ft32-tdep.c
+++ b/gdb/ft32-tdep.c
@@ -529,6 +529,7 @@  static const struct frame_unwind ft32_frame_unwind =
 {
   "ft32 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   ft32_frame_this_id,
   ft32_frame_prev_register,
diff --git a/gdb/h8300-tdep.c b/gdb/h8300-tdep.c
index e91d664ffa3..5b4466ed316 100644
--- a/gdb/h8300-tdep.c
+++ b/gdb/h8300-tdep.c
@@ -503,6 +503,7 @@  h8300_frame_prev_register (const frame_info_ptr &this_frame, void **this_cache,
 static const struct frame_unwind h8300_frame_unwind = {
   "h8300 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   h8300_frame_this_id,
   h8300_frame_prev_register,
diff --git a/gdb/hppa-linux-tdep.c b/gdb/hppa-linux-tdep.c
index 8f73f8d2374..2619b60655a 100644
--- a/gdb/hppa-linux-tdep.c
+++ b/gdb/hppa-linux-tdep.c
@@ -311,6 +311,7 @@  hppa_linux_sigtramp_frame_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind hppa_linux_sigtramp_frame_unwind = {
   "hppa linux sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   hppa_linux_sigtramp_frame_this_id,
   hppa_linux_sigtramp_frame_prev_register,
diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index ad93c2b2048..2447b87ebae 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -2286,6 +2286,7 @@  static const struct frame_unwind hppa_frame_unwind =
 {
   "hppa unwind table",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   hppa_frame_this_id,
   hppa_frame_prev_register,
@@ -2399,6 +2400,7 @@  static const struct frame_unwind hppa_fallback_frame_unwind =
 {
   "hppa prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   hppa_fallback_frame_this_id,
   hppa_fallback_frame_prev_register,
@@ -2480,6 +2482,7 @@  hppa_stub_unwind_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind hppa_stub_frame_unwind = {
   "hppa stub",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   hppa_stub_frame_this_id,
   hppa_stub_frame_prev_register,
diff --git a/gdb/i386-obsd-tdep.c b/gdb/i386-obsd-tdep.c
index 3539c6599a0..1d2b1a09d16 100644
--- a/gdb/i386-obsd-tdep.c
+++ b/gdb/i386-obsd-tdep.c
@@ -396,6 +396,7 @@  static const struct frame_unwind i386obsd_trapframe_unwind = {
      frame, but SIGTRAMP_FRAME would print <signal handler called>,
      which really is not what we want here.  */
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   i386obsd_trapframe_this_id,
   i386obsd_trapframe_prev_register,
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index ba047fc6da7..b554e9ad9b0 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -2143,6 +2143,7 @@  static const struct frame_unwind i386_frame_unwind =
 {
   "i386 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   i386_frame_unwind_stop_reason,
   i386_frame_this_id,
   i386_frame_prev_register,
@@ -2298,6 +2299,7 @@  static const struct frame_unwind i386_epilogue_override_frame_unwind =
 {
   "i386 epilogue override",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   i386_epilogue_frame_unwind_stop_reason,
   i386_epilogue_frame_this_id,
   i386_epilogue_frame_prev_register,
@@ -2309,6 +2311,7 @@  static const struct frame_unwind i386_epilogue_frame_unwind =
 {
   "i386 epilogue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   i386_epilogue_frame_unwind_stop_reason,
   i386_epilogue_frame_this_id,
   i386_epilogue_frame_prev_register,
@@ -2391,6 +2394,7 @@  static const struct frame_unwind i386_stack_tramp_frame_unwind =
 {
   "i386 stack tramp",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   i386_epilogue_frame_unwind_stop_reason,
   i386_epilogue_frame_this_id,
   i386_epilogue_frame_prev_register,
@@ -2540,6 +2544,7 @@  static const struct frame_unwind i386_sigtramp_frame_unwind =
 {
   "i386 sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   i386_sigtramp_frame_unwind_stop_reason,
   i386_sigtramp_frame_this_id,
   i386_sigtramp_frame_prev_register,
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index b0c1ad3d0ab..b10cc251bf1 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -2166,6 +2166,7 @@  static const struct frame_unwind ia64_frame_unwind =
 {
   "ia64 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   &ia64_frame_this_id,
   &ia64_frame_prev_register,
@@ -2355,6 +2356,7 @@  static const struct frame_unwind ia64_sigtramp_frame_unwind =
 {
   "ia64 sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   ia64_sigtramp_frame_this_id,
   ia64_sigtramp_frame_prev_register,
@@ -3015,6 +3017,7 @@  static const struct frame_unwind ia64_libunwind_frame_unwind =
 {
   "ia64 libunwind",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   ia64_libunwind_frame_this_id,
   ia64_libunwind_frame_prev_register,
@@ -3104,6 +3107,7 @@  static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind =
 {
   "ia64 libunwind sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   ia64_libunwind_sigtramp_frame_this_id,
   ia64_libunwind_sigtramp_frame_prev_register,
diff --git a/gdb/inline-frame.c b/gdb/inline-frame.c
index 8ba886c3efc..ec80fabe611 100644
--- a/gdb/inline-frame.c
+++ b/gdb/inline-frame.c
@@ -272,6 +272,7 @@  inline_frame_sniffer (const struct frame_unwind *self,
 const struct frame_unwind inline_frame_unwind = {
   "inline",
   INLINE_FRAME,
+  FRAME_UNWIND_GDB,
   default_frame_unwind_stop_reason,
   inline_frame_this_id,
   inline_frame_prev_register,
diff --git a/gdb/iq2000-tdep.c b/gdb/iq2000-tdep.c
index 5776c66f78a..e0db1b0de4e 100644
--- a/gdb/iq2000-tdep.c
+++ b/gdb/iq2000-tdep.c
@@ -427,6 +427,7 @@  iq2000_frame_this_id (const frame_info_ptr &this_frame, void **this_cache,
 static const struct frame_unwind iq2000_frame_unwind = {
   "iq2000 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   iq2000_frame_this_id,
   iq2000_frame_prev_register,
diff --git a/gdb/jit.c b/gdb/jit.c
index 78b3d984041..63c496ba0b5 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -1109,6 +1109,7 @@  static const struct frame_unwind jit_frame_unwind =
 {
   "jit",
   NORMAL_FRAME,
+  FRAME_UNWIND_EXTENSION,
   default_frame_unwind_stop_reason,
   jit_frame_this_id,
   jit_frame_prev_register,
diff --git a/gdb/lm32-tdep.c b/gdb/lm32-tdep.c
index 98a07281051..4eb5f2ad426 100644
--- a/gdb/lm32-tdep.c
+++ b/gdb/lm32-tdep.c
@@ -450,6 +450,7 @@  lm32_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind lm32_frame_unwind = {
   "lm32 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   lm32_frame_this_id,
   lm32_frame_prev_register,
diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c
index c50dd7f4b78..6bb6d31c7a6 100644
--- a/gdb/loongarch-tdep.c
+++ b/gdb/loongarch-tdep.c
@@ -453,6 +453,7 @@  loongarch_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind loongarch_frame_unwind = {
   "loongarch prologue",
   /*.type	   =*/NORMAL_FRAME,
+  /*.unwinder_class=*/FRAME_UNWIND_ARCH,
   /*.stop_reason   =*/default_frame_unwind_stop_reason,
   /*.this_id	   =*/loongarch_frame_this_id,
   /*.prev_register =*/loongarch_frame_prev_register,
diff --git a/gdb/m32c-tdep.c b/gdb/m32c-tdep.c
index 28dfb2fb7c6..bce12c5fae7 100644
--- a/gdb/m32c-tdep.c
+++ b/gdb/m32c-tdep.c
@@ -1958,6 +1958,7 @@  m32c_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind m32c_unwind = {
   "m32c prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   m32c_this_id,
   m32c_prev_register,
diff --git a/gdb/m32r-linux-tdep.c b/gdb/m32r-linux-tdep.c
index 8eea6620df9..11a150a92b8 100644
--- a/gdb/m32r-linux-tdep.c
+++ b/gdb/m32r-linux-tdep.c
@@ -304,6 +304,7 @@  m32r_linux_sigtramp_frame_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind m32r_linux_sigtramp_frame_unwind = {
   "m32r linux sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   m32r_linux_sigtramp_frame_this_id,
   m32r_linux_sigtramp_frame_prev_register,
diff --git a/gdb/m32r-tdep.c b/gdb/m32r-tdep.c
index c6428f6db6f..aadb8c00d86 100644
--- a/gdb/m32r-tdep.c
+++ b/gdb/m32r-tdep.c
@@ -834,6 +834,7 @@  m32r_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind m32r_frame_unwind = {
   "m32r prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   m32r_frame_this_id,
   m32r_frame_prev_register,
diff --git a/gdb/m68hc11-tdep.c b/gdb/m68hc11-tdep.c
index 12cd0efbbe7..e14ac622fda 100644
--- a/gdb/m68hc11-tdep.c
+++ b/gdb/m68hc11-tdep.c
@@ -936,6 +936,7 @@  m68hc11_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind m68hc11_frame_unwind = {
   "m68hc11 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   m68hc11_frame_this_id,
   m68hc11_frame_prev_register,
diff --git a/gdb/m68k-linux-tdep.c b/gdb/m68k-linux-tdep.c
index 7250ce09826..7cca4f86394 100644
--- a/gdb/m68k-linux-tdep.c
+++ b/gdb/m68k-linux-tdep.c
@@ -318,6 +318,7 @@  static const struct frame_unwind m68k_linux_sigtramp_frame_unwind =
 {
   "m68k linux sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   m68k_linux_sigtramp_frame_this_id,
   m68k_linux_sigtramp_frame_prev_register,
diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c
index 375d5e6e54c..2ff507e7816 100644
--- a/gdb/m68k-tdep.c
+++ b/gdb/m68k-tdep.c
@@ -1011,6 +1011,7 @@  static const struct frame_unwind m68k_frame_unwind =
 {
   "m68k prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   m68k_frame_this_id,
   m68k_frame_prev_register,
diff --git a/gdb/mep-tdep.c b/gdb/mep-tdep.c
index a4ef343f9dc..7dd6371f995 100644
--- a/gdb/mep-tdep.c
+++ b/gdb/mep-tdep.c
@@ -2064,6 +2064,7 @@  mep_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind mep_frame_unwind = {
   "mep prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   mep_frame_this_id,
   mep_frame_prev_register,
diff --git a/gdb/microblaze-tdep.c b/gdb/microblaze-tdep.c
index 3d768d7e161..94e8b0cee53 100644
--- a/gdb/microblaze-tdep.c
+++ b/gdb/microblaze-tdep.c
@@ -482,6 +482,7 @@  static const struct frame_unwind microblaze_frame_unwind =
 {
   "microblaze prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   microblaze_frame_this_id,
   microblaze_frame_prev_register,
diff --git a/gdb/mips-sde-tdep.c b/gdb/mips-sde-tdep.c
index 90988cdfdac..18cb9485639 100644
--- a/gdb/mips-sde-tdep.c
+++ b/gdb/mips-sde-tdep.c
@@ -164,6 +164,7 @@  static const struct frame_unwind mips_sde_frame_unwind =
 {
   "mips sde sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   mips_sde_frame_this_id,
   mips_sde_frame_prev_register,
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 006bc9270ca..c51eeecdfef 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -2929,6 +2929,7 @@  static const struct frame_unwind mips_insn16_frame_unwind =
 {
   "mips insn16 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   mips_insn16_frame_this_id,
   mips_insn16_frame_prev_register,
@@ -3365,6 +3366,7 @@  static const struct frame_unwind mips_micro_frame_unwind =
 {
   "mips micro prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   mips_micro_frame_this_id,
   mips_micro_frame_prev_register,
@@ -3744,6 +3746,7 @@  static const struct frame_unwind mips_insn32_frame_unwind =
 {
   "mips insn32 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   mips_insn32_frame_this_id,
   mips_insn32_frame_prev_register,
@@ -3860,6 +3863,7 @@  static const struct frame_unwind mips_stub_frame_unwind =
 {
   "mips stub",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   mips_stub_frame_this_id,
   mips_stub_frame_prev_register,
diff --git a/gdb/mn10300-tdep.c b/gdb/mn10300-tdep.c
index d44eebfcb17..565300afd3c 100644
--- a/gdb/mn10300-tdep.c
+++ b/gdb/mn10300-tdep.c
@@ -1130,6 +1130,7 @@  mn10300_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind mn10300_frame_unwind = {
   "mn10300 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   mn10300_frame_this_id, 
   mn10300_frame_prev_register,
diff --git a/gdb/moxie-tdep.c b/gdb/moxie-tdep.c
index 29ad1f2bb2e..82d3478ed68 100644
--- a/gdb/moxie-tdep.c
+++ b/gdb/moxie-tdep.c
@@ -588,6 +588,7 @@  moxie_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind moxie_frame_unwind = {
   "moxie prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   moxie_frame_this_id,
   moxie_frame_prev_register,
diff --git a/gdb/msp430-tdep.c b/gdb/msp430-tdep.c
index 41a8f990a16..6d7fee230c1 100644
--- a/gdb/msp430-tdep.c
+++ b/gdb/msp430-tdep.c
@@ -545,6 +545,7 @@  msp430_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind msp430_unwind = {
   "msp430 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   msp430_this_id,
   msp430_prev_register,
diff --git a/gdb/nds32-tdep.c b/gdb/nds32-tdep.c
index 8ad51d0798b..910a6f7a1d0 100644
--- a/gdb/nds32-tdep.c
+++ b/gdb/nds32-tdep.c
@@ -992,6 +992,7 @@  static const struct frame_unwind nds32_frame_unwind =
 {
   "nds32 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   nds32_frame_this_id,
   nds32_frame_prev_register,
@@ -1376,6 +1377,7 @@  static const struct frame_unwind nds32_epilogue_frame_unwind =
 {
   "nds32 epilogue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   nds32_epilogue_frame_this_id,
   nds32_epilogue_frame_prev_register,
diff --git a/gdb/nios2-tdep.c b/gdb/nios2-tdep.c
index 130c0154a60..5e68764bd6a 100644
--- a/gdb/nios2-tdep.c
+++ b/gdb/nios2-tdep.c
@@ -1981,6 +1981,7 @@  static const struct frame_unwind nios2_frame_unwind =
 {
   "nios2 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   nios2_frame_this_id,
   nios2_frame_prev_register,
@@ -2082,6 +2083,7 @@  static const struct frame_unwind nios2_stub_frame_unwind =
 {
   "nios2 stub",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   nios2_stub_frame_this_id,
   nios2_stub_frame_prev_register,
diff --git a/gdb/or1k-tdep.c b/gdb/or1k-tdep.c
index 290f748cc56..6e0466c3408 100644
--- a/gdb/or1k-tdep.c
+++ b/gdb/or1k-tdep.c
@@ -1128,6 +1128,7 @@  or1k_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind or1k_frame_unwind = {
   "or1k prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   or1k_frame_this_id,
   or1k_frame_prev_register,
diff --git a/gdb/ppc-fbsd-tdep.c b/gdb/ppc-fbsd-tdep.c
index 3f0f93f1ac0..12eb396a0e3 100644
--- a/gdb/ppc-fbsd-tdep.c
+++ b/gdb/ppc-fbsd-tdep.c
@@ -265,6 +265,7 @@  ppcfbsd_sigtramp_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind ppcfbsd_sigtramp_frame_unwind = {
   "ppc freebsd sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   ppcfbsd_sigtramp_frame_this_id,
   ppcfbsd_sigtramp_frame_prev_register,
diff --git a/gdb/ppc-obsd-tdep.c b/gdb/ppc-obsd-tdep.c
index 1bd79b3b3e1..ceb8b5d85db 100644
--- a/gdb/ppc-obsd-tdep.c
+++ b/gdb/ppc-obsd-tdep.c
@@ -234,6 +234,7 @@  ppcobsd_sigtramp_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind ppcobsd_sigtramp_frame_unwind = {
   "ppc openbsd sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   ppcobsd_sigtramp_frame_this_id,
   ppcobsd_sigtramp_frame_prev_register,
diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c
index 68deaf98d81..ab32f5057f9 100644
--- a/gdb/python/py-unwind.c
+++ b/gdb/python/py-unwind.c
@@ -984,6 +984,7 @@  pyuw_on_new_gdbarch (gdbarch *newarch)
 
       unwinder->name = "python";
       unwinder->type = NORMAL_FRAME;
+      unwinder->unwinder_class = FRAME_UNWIND_EXTENSION;
       unwinder->stop_reason = default_frame_unwind_stop_reason;
       unwinder->this_id = pyuw_this_id;
       unwinder->prev_register = pyuw_prev_register;
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 8fcf63830b8..a8ed0acf365 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1944,6 +1944,7 @@  const struct frame_unwind record_btrace_frame_unwind =
 {
   "record-btrace",
   NORMAL_FRAME,
+  FRAME_UNWIND_GDB,
   record_btrace_frame_unwind_stop_reason,
   record_btrace_frame_this_id,
   record_btrace_frame_prev_register,
@@ -1956,6 +1957,7 @@  const struct frame_unwind record_btrace_tailcall_frame_unwind =
 {
   "record-btrace tailcall",
   TAILCALL_FRAME,
+  FRAME_UNWIND_GDB,
   record_btrace_frame_unwind_stop_reason,
   record_btrace_frame_this_id,
   record_btrace_frame_prev_register,
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 932708ca4e9..2a292cc4ff8 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -3904,6 +3904,7 @@  static const struct frame_unwind riscv_frame_unwind =
 {
   /*.name          =*/ "riscv prologue",
   /*.type          =*/ NORMAL_FRAME,
+  /*.unwinder_class=*/FRAME_UNWIND_ARCH,
   /*.stop_reason   =*/ default_frame_unwind_stop_reason,
   /*.this_id       =*/ riscv_frame_this_id,
   /*.prev_register =*/ riscv_frame_prev_register,
diff --git a/gdb/rl78-tdep.c b/gdb/rl78-tdep.c
index 46a7ee9c3d4..0fcd5f9f1f3 100644
--- a/gdb/rl78-tdep.c
+++ b/gdb/rl78-tdep.c
@@ -1187,6 +1187,7 @@  static const struct frame_unwind rl78_unwind =
 {
   "rl78 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   rl78_this_id,
   rl78_prev_register,
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index 3faefe58ceb..3e5c8acff21 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -331,6 +331,7 @@  aix_sighandle_frame_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind aix_sighandle_frame_unwind = {
   "rs6000 aix sighandle",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   aix_sighandle_frame_this_id,
   aix_sighandle_frame_prev_register,
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index ed6a21b7146..6dad9ccf98a 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -3841,6 +3841,7 @@  static const struct frame_unwind rs6000_frame_unwind =
 {
   "rs6000 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   rs6000_frame_this_id,
   rs6000_frame_prev_register,
@@ -3982,6 +3983,7 @@  static const struct frame_unwind rs6000_epilogue_frame_unwind =
 {
   "rs6000 epilogue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   rs6000_epilogue_frame_this_id, rs6000_epilogue_frame_prev_register,
   NULL,
diff --git a/gdb/rx-tdep.c b/gdb/rx-tdep.c
index 6b12fe0a314..6cb74c23a3c 100644
--- a/gdb/rx-tdep.c
+++ b/gdb/rx-tdep.c
@@ -634,6 +634,7 @@  rx_exception_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind rx_frame_unwind = {
   "rx prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   rx_frame_this_id,
   rx_frame_prev_register,
@@ -648,6 +649,7 @@  static const struct frame_unwind rx_exception_unwind = {
   "rx exception",
   /* SIGTRAMP_FRAME could be used here, but backtraces are less informative.  */
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   rx_frame_this_id,
   rx_frame_prev_register,
diff --git a/gdb/s12z-tdep.c b/gdb/s12z-tdep.c
index c24c75665ed..7fa73cf6b8c 100644
--- a/gdb/s12z-tdep.c
+++ b/gdb/s12z-tdep.c
@@ -444,6 +444,7 @@  s12z_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind s12z_frame_unwind = {
   "s12z prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   s12z_frame_this_id,
   s12z_frame_prev_register,
diff --git a/gdb/s390-linux-tdep.c b/gdb/s390-linux-tdep.c
index bc1db550d2e..556fad64926 100644
--- a/gdb/s390-linux-tdep.c
+++ b/gdb/s390-linux-tdep.c
@@ -544,6 +544,7 @@  s390_sigtramp_frame_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind s390_sigtramp_frame_unwind = {
   "s390 linux sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   s390_sigtramp_frame_this_id,
   s390_sigtramp_frame_prev_register,
diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
index 6687127d0aa..bbf88dbcab1 100644
--- a/gdb/s390-tdep.c
+++ b/gdb/s390-tdep.c
@@ -2649,6 +2649,7 @@  s390_frame_prev_register (const frame_info_ptr &this_frame,
 static const struct frame_unwind s390_frame_unwind = {
   "s390 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   s390_frame_this_id,
   s390_frame_prev_register,
@@ -2743,6 +2744,7 @@  s390_stub_frame_sniffer (const struct frame_unwind *self,
 static const struct frame_unwind s390_stub_frame_unwind = {
   "s390 stub",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   s390_stub_frame_this_id,
   s390_stub_frame_prev_register,
diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c
index 4eaeae0d254..9fe4036dbbe 100644
--- a/gdb/sentinel-frame.c
+++ b/gdb/sentinel-frame.c
@@ -82,6 +82,7 @@  const struct frame_unwind sentinel_frame_unwind =
 {
   "sentinel",
   SENTINEL_FRAME,
+  FRAME_UNWIND_GDB,
   default_frame_unwind_stop_reason,
   sentinel_frame_this_id,
   sentinel_frame_prev_register,
diff --git a/gdb/sh-tdep.c b/gdb/sh-tdep.c
index 050f7bffa0c..5c23e5c43fc 100644
--- a/gdb/sh-tdep.c
+++ b/gdb/sh-tdep.c
@@ -1953,6 +1953,7 @@  sh_frame_this_id (const frame_info_ptr &this_frame, void **this_cache,
 static const struct frame_unwind sh_frame_unwind = {
   "sh prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sh_frame_this_id,
   sh_frame_prev_register,
@@ -2020,6 +2021,7 @@  static const struct frame_unwind sh_stub_unwind =
 {
   "sh stub",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sh_stub_this_id,
   sh_frame_prev_register,
diff --git a/gdb/sparc-netbsd-tdep.c b/gdb/sparc-netbsd-tdep.c
index fc22e66826f..5b3dd067375 100644
--- a/gdb/sparc-netbsd-tdep.c
+++ b/gdb/sparc-netbsd-tdep.c
@@ -252,6 +252,7 @@  static const struct frame_unwind sparc32nbsd_sigcontext_frame_unwind =
 {
   "sparc32 netbsd sigcontext",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sparc32nbsd_sigcontext_frame_this_id,
   sparc32nbsd_sigcontext_frame_prev_register,
diff --git a/gdb/sparc-obsd-tdep.c b/gdb/sparc-obsd-tdep.c
index 3182a7778d3..049c315fa14 100644
--- a/gdb/sparc-obsd-tdep.c
+++ b/gdb/sparc-obsd-tdep.c
@@ -138,6 +138,7 @@  static const struct frame_unwind sparc32obsd_sigtramp_frame_unwind =
 {
   "sparc32 openbsd sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sparc32obsd_sigtramp_frame_this_id,
   sparc32obsd_sigtramp_frame_prev_register,
diff --git a/gdb/sparc-sol2-tdep.c b/gdb/sparc-sol2-tdep.c
index aea3766d9b5..bb9c8a549b1 100644
--- a/gdb/sparc-sol2-tdep.c
+++ b/gdb/sparc-sol2-tdep.c
@@ -183,6 +183,7 @@  static const struct frame_unwind sparc32_sol2_sigtramp_frame_unwind =
 {
   "sparc32 solaris sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sparc32_sol2_sigtramp_frame_this_id,
   sparc32_sol2_sigtramp_frame_prev_register,
diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c
index edbc03878dc..30dd061d8c9 100644
--- a/gdb/sparc-tdep.c
+++ b/gdb/sparc-tdep.c
@@ -1350,6 +1350,7 @@  static const struct frame_unwind sparc32_frame_unwind =
 {
   "sparc32 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sparc32_frame_this_id,
   sparc32_frame_prev_register,
diff --git a/gdb/sparc64-fbsd-tdep.c b/gdb/sparc64-fbsd-tdep.c
index a30c7c448e5..1d4c075a961 100644
--- a/gdb/sparc64-fbsd-tdep.c
+++ b/gdb/sparc64-fbsd-tdep.c
@@ -200,6 +200,7 @@  static const struct frame_unwind sparc64fbsd_sigtramp_frame_unwind =
 {
   "sparc64 freebsd sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sparc64fbsd_sigtramp_frame_this_id,
   sparc64fbsd_sigtramp_frame_prev_register,
diff --git a/gdb/sparc64-netbsd-tdep.c b/gdb/sparc64-netbsd-tdep.c
index b101f4970d9..82eb99f57c1 100644
--- a/gdb/sparc64-netbsd-tdep.c
+++ b/gdb/sparc64-netbsd-tdep.c
@@ -226,6 +226,7 @@  static const struct frame_unwind sparc64nbsd_sigcontext_frame_unwind =
 {
   "sparc64 netbsd sigcontext",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sparc64nbsd_sigcontext_frame_this_id,
   sparc64nbsd_sigcontext_frame_prev_register,
diff --git a/gdb/sparc64-obsd-tdep.c b/gdb/sparc64-obsd-tdep.c
index cef6efd3379..e81afa604e7 100644
--- a/gdb/sparc64-obsd-tdep.c
+++ b/gdb/sparc64-obsd-tdep.c
@@ -224,6 +224,7 @@  static const struct frame_unwind sparc64obsd_frame_unwind =
 {
   "sparc64 openbsd sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sparc64obsd_frame_this_id,
   sparc64obsd_frame_prev_register,
@@ -308,6 +309,7 @@  static const struct frame_unwind sparc64obsd_trapframe_unwind =
 {
   "sparc64 openbsd trap",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sparc64obsd_trapframe_this_id,
   sparc64obsd_trapframe_prev_register,
diff --git a/gdb/sparc64-sol2-tdep.c b/gdb/sparc64-sol2-tdep.c
index b7ca4ca1f5b..e8d09e2516e 100644
--- a/gdb/sparc64-sol2-tdep.c
+++ b/gdb/sparc64-sol2-tdep.c
@@ -186,6 +186,7 @@  static const struct frame_unwind sparc64_sol2_sigtramp_frame_unwind =
 {
   "sparc64 solaris sigtramp",
   SIGTRAMP_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sparc64_sol2_sigtramp_frame_this_id,
   sparc64_sol2_sigtramp_frame_prev_register,
diff --git a/gdb/sparc64-tdep.c b/gdb/sparc64-tdep.c
index 7d44b1e16a0..09774ebcee6 100644
--- a/gdb/sparc64-tdep.c
+++ b/gdb/sparc64-tdep.c
@@ -1139,6 +1139,7 @@  static const struct frame_unwind sparc64_frame_unwind =
 {
   "sparc64 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   sparc64_frame_this_id,
   sparc64_frame_prev_register,
diff --git a/gdb/tic6x-tdep.c b/gdb/tic6x-tdep.c
index 6732478eb09..bac8ba84ed0 100644
--- a/gdb/tic6x-tdep.c
+++ b/gdb/tic6x-tdep.c
@@ -456,6 +456,7 @@  static const struct frame_unwind tic6x_frame_unwind =
 {
   "tic6x prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   tic6x_frame_this_id,
   tic6x_frame_prev_register,
@@ -519,6 +520,7 @@  static const struct frame_unwind tic6x_stub_unwind =
 {
   "tic6x stub",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   tic6x_stub_this_id,
   tic6x_frame_prev_register,
diff --git a/gdb/tilegx-tdep.c b/gdb/tilegx-tdep.c
index 92f2be0b208..16cd25f4635 100644
--- a/gdb/tilegx-tdep.c
+++ b/gdb/tilegx-tdep.c
@@ -903,6 +903,7 @@  tilegx_frame_base_address (const frame_info_ptr &this_frame, void **this_cache)
 static const struct frame_unwind tilegx_frame_unwind = {
   "tilegx prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   tilegx_frame_this_id,
   tilegx_frame_prev_register,
diff --git a/gdb/tramp-frame.c b/gdb/tramp-frame.c
index 4f7c62d11fa..6368f67a2e7 100644
--- a/gdb/tramp-frame.c
+++ b/gdb/tramp-frame.c
@@ -166,6 +166,7 @@  tramp_frame_prepend_unwinder (struct gdbarch *gdbarch,
   data->tramp_frame = tramp_frame;
   unwinder->type = tramp_frame->frame_type;
   unwinder->unwind_data = data;
+  unwinder->unwinder_class = FRAME_UNWIND_GDB;
   unwinder->sniffer = tramp_frame_sniffer;
   unwinder->stop_reason = default_frame_unwind_stop_reason;
   unwinder->this_id = tramp_frame_this_id;
diff --git a/gdb/v850-tdep.c b/gdb/v850-tdep.c
index 531fdb48ab0..9300aeccf6f 100644
--- a/gdb/v850-tdep.c
+++ b/gdb/v850-tdep.c
@@ -1323,6 +1323,7 @@  v850_frame_this_id (const frame_info_ptr &this_frame, void **this_cache,
 static const struct frame_unwind v850_frame_unwind = {
   "v850 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   v850_frame_this_id,
   v850_frame_prev_register,
diff --git a/gdb/vax-tdep.c b/gdb/vax-tdep.c
index a42c872feff..25d07c59376 100644
--- a/gdb/vax-tdep.c
+++ b/gdb/vax-tdep.c
@@ -390,6 +390,7 @@  static const struct frame_unwind vax_frame_unwind =
 {
   "vax prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   vax_frame_this_id,
   vax_frame_prev_register,
diff --git a/gdb/xstormy16-tdep.c b/gdb/xstormy16-tdep.c
index 766d1d144be..e01da4ecab4 100644
--- a/gdb/xstormy16-tdep.c
+++ b/gdb/xstormy16-tdep.c
@@ -731,6 +731,7 @@  xstormy16_frame_base_address (const frame_info_ptr &this_frame, void **this_cach
 static const struct frame_unwind xstormy16_frame_unwind = {
   "xstormy16 prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   xstormy16_frame_this_id,
   xstormy16_frame_prev_register,
diff --git a/gdb/xtensa-tdep.c b/gdb/xtensa-tdep.c
index 840768b65c7..b8b7efb38b0 100644
--- a/gdb/xtensa-tdep.c
+++ b/gdb/xtensa-tdep.c
@@ -1501,6 +1501,7 @@  xtensa_unwind =
 {
   "xtensa prologue",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   xtensa_frame_this_id,
   xtensa_frame_prev_register,
diff --git a/gdb/z80-tdep.c b/gdb/z80-tdep.c
index c442b60623b..66a12cd3be7 100644
--- a/gdb/z80-tdep.c
+++ b/gdb/z80-tdep.c
@@ -1068,6 +1068,7 @@  z80_frame_unwind =
 {
   "z80",
   NORMAL_FRAME,
+  FRAME_UNWIND_ARCH,
   default_frame_unwind_stop_reason,
   z80_frame_this_id,
   z80_frame_prev_register,