[v4,1/1] gdb, breakpoint: add breakpoint location debugging logs

Message ID 20230601163345.3895525-2-christina.schimpe@intel.com
State New
Headers
Series Add breakpoint location debugging logs |

Commit Message

Schimpe, Christina June 1, 2023, 4:33 p.m. UTC
  From: Mihails Strasuns <mihails.strasuns@intel.com>

Add new commands:

  set debug breakpoints on|off
  show debug breakpoints

This patch introduces new debugging information that prints
breakpoint location insertion and removal flow.

The debug output looks like:
~~~
(gdb) set debug breakpoints on
(gdb) disassemble main
Dump of assembler code for function main:
   0x0000555555555129 <+0>:	endbr64
   0x000055555555512d <+4>:	push   %rbp
   0x000055555555512e <+5>:	mov    %rsp,%rbp
=> 0x0000555555555131 <+8>:	mov    $0x0,%eax
   0x0000555555555136 <+13>:	pop    %rbp
   0x0000555555555137 <+14>:	ret
End of assembler dump.
(gdb) break *0x0000555555555137
Breakpoint 2 at 0x555555555137: file main.c, line 4.
[breakpoints] update_global_location_list: insert_mode = UGLL_MAY_INSERT
(gdb) c
Continuing.
[breakpoints] update_global_location_list: insert_mode = UGLL_INSERT
[breakpoints] insert_bp_location: Breakpoint 2, location (0x5572b98a6db0) at address 0x555555555137 in main at main.c:4
[breakpoints] insert_bp_location: Breakpoint -2, location (0x5572b961d450) at address 0x7ffff7fd37b5
[breakpoints] insert_bp_location: Breakpoint -5, location (0x5572b9634680) at address 0x7ffff7fe509e
[breakpoints] insert_bp_location: Breakpoint -7, location (0x5572b9634a00) at address 0x7ffff7fe63f4
[breakpoints] remove_breakpoint_1: Breakpoint 2, location (0x5572b98a6db0) at address 0x555555555137 in main at main.c:4 due to regular remove
[breakpoints] remove_breakpoint_1: Breakpoint -2, location (0x5572b961d450) at address 0x7ffff7fd37b5 due to regular remove
[breakpoints] remove_breakpoint_1: Breakpoint -5, location (0x5572b9634680) at address 0x7ffff7fe509e due to regular remove
[breakpoints] remove_breakpoint_1: Breakpoint -7, location (0x5572b9634a00) at address 0x7ffff7fe63f4 due to regular remove

Breakpoint 2, 0x0000555555555137 in main () at main.c:4
4	}
~~~

Co-Authored-By: Christina Schimpe <christina.schimpe@intel.com>
---
 gdb/NEWS            |   5 +++
 gdb/breakpoint.c    | 107 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/breakpoint.h    |   4 ++
 gdb/doc/gdb.texinfo |   8 ++++
 4 files changed, 124 insertions(+)
  

Comments

Andrew Burgess June 7, 2023, 8:45 a.m. UTC | #1
Christina Schimpe <christina.schimpe@intel.com> writes:

> From: Mihails Strasuns <mihails.strasuns@intel.com>
>
> Add new commands:
>
>   set debug breakpoints on|off
>   show debug breakpoints

I'd like to suggest (but don't require) that we drop the 's' here, so
breakpoints -> breakpoint.

I'd point to other debug settings like frame (not frames), expression
(not expressions), and target (not targets) for precedent.  However
there is also threads (not thread) which is why I don't think it would
be fair to require this change -- it's up to you.

>
> This patch introduces new debugging information that prints
> breakpoint location insertion and removal flow.
>
> The debug output looks like:
> ~~~
> (gdb) set debug breakpoints on
> (gdb) disassemble main
> Dump of assembler code for function main:
>    0x0000555555555129 <+0>:	endbr64
>    0x000055555555512d <+4>:	push   %rbp
>    0x000055555555512e <+5>:	mov    %rsp,%rbp
> => 0x0000555555555131 <+8>:	mov    $0x0,%eax
>    0x0000555555555136 <+13>:	pop    %rbp
>    0x0000555555555137 <+14>:	ret
> End of assembler dump.
> (gdb) break *0x0000555555555137
> Breakpoint 2 at 0x555555555137: file main.c, line 4.
> [breakpoints] update_global_location_list: insert_mode = UGLL_MAY_INSERT
> (gdb) c
> Continuing.
> [breakpoints] update_global_location_list: insert_mode = UGLL_INSERT
> [breakpoints] insert_bp_location: Breakpoint 2, location (0x5572b98a6db0) at address 0x555555555137 in main at main.c:4
> [breakpoints] insert_bp_location: Breakpoint -2, location (0x5572b961d450) at address 0x7ffff7fd37b5
> [breakpoints] insert_bp_location: Breakpoint -5, location (0x5572b9634680) at address 0x7ffff7fe509e
> [breakpoints] insert_bp_location: Breakpoint -7, location (0x5572b9634a00) at address 0x7ffff7fe63f4
> [breakpoints] remove_breakpoint_1: Breakpoint 2, location (0x5572b98a6db0) at address 0x555555555137 in main at main.c:4 due to regular remove
> [breakpoints] remove_breakpoint_1: Breakpoint -2, location (0x5572b961d450) at address 0x7ffff7fd37b5 due to regular remove
> [breakpoints] remove_breakpoint_1: Breakpoint -5, location (0x5572b9634680) at address 0x7ffff7fe509e due to regular remove
> [breakpoints] remove_breakpoint_1: Breakpoint -7, location (0x5572b9634a00) at address 0x7ffff7fe63f4 due to regular remove
>
> Breakpoint 2, 0x0000555555555137 in main () at main.c:4
> 4	}
> ~~~
>
> Co-Authored-By: Christina Schimpe <christina.schimpe@intel.com>
> ---
>  gdb/NEWS            |   5 +++
>  gdb/breakpoint.c    | 107 ++++++++++++++++++++++++++++++++++++++++++++
>  gdb/breakpoint.h    |   4 ++
>  gdb/doc/gdb.texinfo |   8 ++++
>  4 files changed, 124 insertions(+)
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 649a3a9824a..c66fde54e85 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,11 @@
>  
>  *** Changes since GDB 13
>  
> +* GDB now has some support for integer types larger than 64 bits.

I think this line was not intended to be part of this commit.

> +* set debug breakpoints on|off
> +  show debug breakpoints
> +  Print additional debug messages about breakpoint insertion and removal.

I think this should be moved into the '* New commands' section of the
NEWS file, see for example, how and where 'set always-read-ctf on|off'
is documented in this file.

> +
>  * The AArch64 'org.gnu.gdb.aarch64.pauth' Pointer Authentication feature string
>    has been deprecated in favor of the 'org.gnu.gdb.aarch64.pauth_v2' feature
>    string.
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 0a520cfc169..dd8fac2f1ba 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -83,6 +83,7 @@
>  #include "progspace-and-thread.h"
>  #include "gdbsupport/array-view.h"
>  #include "gdbsupport/gdb_optional.h"
> +#include "gdbsupport/common-utils.h"
>  
>  /* Prototypes for local functions.  */
>  
> @@ -200,6 +201,68 @@ enum ugll_insert_mode
>    UGLL_INSERT
>  };
>  
> +/* Return a textual version of INSERT_MODE.  */
> +
> +static const char *
> +ugll_insert_mode_text (ugll_insert_mode insert_mode)
> +{
> +/* Make sure the compiler warns if a new ugll_insert_mode enumerator is added
> +   but not handled here.  */
> +DIAGNOSTIC_PUSH
> +DIAGNOSTIC_ERROR_SWITCH
> +  switch (insert_mode)
> +    {
> +    case UGLL_DONT_INSERT:
> +      return "UGLL_DONT_INSERT";
> +    case UGLL_MAY_INSERT:
> +      return "UGLL_MAY_INSERT";
> +    case UGLL_INSERT:
> +      return "UGLL_INSERT";
> +    }
> +DIAGNOSTIC_POP
> +
> +  gdb_assert_not_reached ("must handle all enum values");
> +}
> +
> +/* Return a textual version of REASON.  */
> +
> +static const char *
> +remove_bp_reason_str (remove_bp_reason reason)
> +{
> +/* Make sure the compiler warns if a new remove_bp_reason enumerator is added
> +   but not handled here.  */
> +DIAGNOSTIC_PUSH
> +DIAGNOSTIC_ERROR_SWITCH
> +  switch (reason)
> +    {
> +    case REMOVE_BREAKPOINT:
> +      return "regular remove";
> +    case DETACH_BREAKPOINT:
> +      return "detach";
> +    }
> +DIAGNOSTIC_POP
> +
> +  gdb_assert_not_reached ("must handle all enum values");
> +}
> +
> +/* Return a textual version of breakpoint BL describing number, location and
> +   address.  */
> +
> +static std::string
> +breakpoint_location_address_str (const bp_location* bl)
> +{
> +  std::string str = string_printf ("Breakpoint %d, location (%s) at address %s",
> +				   bl->owner->number,
> +				   host_address_to_string (bl),
> +				   paddress (bl->gdbarch, bl->address));

I can't help but think using 'location' in this string is a bad idea,
'location' already has a meaning for GDB breakpoints.  How about just
dropping the work 'location'?

> +
> +  std::string loc_string = bl->to_string ();
> +  if (!loc_string.empty ())
> +    str += string_printf (" %s", loc_string.c_str ());
> +
> +  return str;
> +}
> +
>  static void update_global_location_list (enum ugll_insert_mode);
>  
>  static void update_global_location_list_nothrow (enum ugll_insert_mode);
> @@ -510,6 +573,22 @@ show_always_inserted_mode (struct ui_file *file, int from_tty,
>  	      value);
>  }
>  
> +/* True if breakpoints debug output is enabled.  */
> +static bool debug_breakpoints = false;
> +
> +/* Print a "breakpoints" debug statement.  */
> +#define breakpoint_debug_printf(fmt, ...) \
> +  debug_prefixed_printf_cond (debug_breakpoints, "breakpoints", fmt, \
> +			      ##__VA_ARGS__)
> +
> +/* "show debug breakpoints" implementation.  */
> +static void
> +show_debug_breakpoints (struct ui_file *file, int from_tty,
> +			struct cmd_list_element *c, const char *value)
> +{
> +  gdb_printf (file, _("Breakpoint location debugging is %s.\n"), value);
> +}
> +
>  /* See breakpoint.h.  */
>  
>  int
> @@ -2728,6 +2807,8 @@ insert_bp_location (struct bp_location *bl,
>    if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
>      return 0;
>  
> +  breakpoint_debug_printf ("%s", breakpoint_location_address_str (bl).c_str ());
> +
>    /* Note we don't initialize bl->target_info, as that wipes out
>       the breakpoint location's shadow_contents if the breakpoint
>       is still inserted at that location.  This in turn breaks
> @@ -3270,6 +3351,8 @@ remove_breakpoints_inf (inferior *inf)
>  {
>    int val;
>  
> +  breakpoint_debug_printf ("inf->num = %d", inf->num);
> +
>    for (bp_location *bl : all_bp_locations ())
>      {
>        if (bl->pspace != inf->pspace)
> @@ -3914,6 +3997,10 @@ detach_breakpoints (ptid_t ptid)
>  static int
>  remove_breakpoint_1 (struct bp_location *bl, enum remove_bp_reason reason)
>  {
> +  breakpoint_debug_printf ("%s due to %s",
> +			   breakpoint_location_address_str (bl).c_str (),
> +			   remove_bp_reason_str (reason));
> +
>    int val;
>  
>    /* BL is never in moribund_locations by our callers.  */
> @@ -7424,6 +7511,14 @@ bp_location::bp_location (breakpoint *owner)
>  {
>  }
>  

Missing a comment '/* See breakpoint.h.  */'.

Thanks,
Andrew

> +std::string bp_location::to_string () const
> +{
> +  string_file stb;
> +  ui_out_redirect_pop redir (current_uiout, &stb);
> +  print_breakpoint_location (this->owner, this);
> +  return stb.string ();
> +}
> +
>  /* Decrement reference count.  If the reference count reaches 0,
>     destroy the bp_location.  Sets *BLP to NULL.  */
>  
> @@ -11157,6 +11252,9 @@ update_global_location_list (enum ugll_insert_mode insert_mode)
>    /* Last breakpoint location program space that was marked for update.  */
>    int last_pspace_num = -1;
>  
> +  breakpoint_debug_printf ("insert_mode = %s",
> +			   ugll_insert_mode_text (insert_mode));
> +
>    /* Used in the duplicates detection below.  When iterating over all
>       bp_locations, points to the first bp_location of a given address.
>       Breakpoints and watchpoints of different types are never
> @@ -14899,6 +14997,15 @@ when execution stops."),
>  				&breakpoint_set_cmdlist,
>  				&breakpoint_show_cmdlist);
>  
> +  add_setshow_boolean_cmd ("breakpoints", class_maintenance,
> +			   &debug_breakpoints, _("\
> +Set breakpoint location debugging."), _("\
> +Show breakpoint location debugging."), _("\
> +When on, breakpoint location specific debugging is enabled."),
> +			   NULL,
> +			   show_debug_breakpoints,
> +			   &setdebuglist, &showdebuglist);
> +
>    add_setshow_enum_cmd ("condition-evaluation", class_breakpoint,
>  			condition_evaluation_enums,
>  			&condition_evaluation_mode_1, _("\
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index da150585f73..f4896293bb7 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -509,6 +509,10 @@ class bp_location : public refcounted_object, public intrusive_list_node<bp_loca
>  
>    /* The objfile the symbol or minimal symbol were found in.  */
>    const struct objfile *objfile = NULL;
> +
> +  /* Return a string representation of the bp_location.
> +     This is only meant to be used in debug messages.  */
> +  std::string to_string () const;
>  };
>  
>  /* A policy class for bp_location reference counting.  */
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index fc55c4e7b43..8c91ecab209 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -28356,6 +28356,14 @@ debugging info.
>  Turn on or off debugging messages for built-in XML parsers.
>  @item show debug xml
>  Displays the current state of XML debugging messages.
> +
> +@item set debug breakpoints
> +@cindex breakpoint debugging info
> +Turns on or off display of @value{GDBN} debugging info for breakpoint insertion
> +and removal.  The default is off.
> +@item show debug breakpoints
> +Displays the current state of displaying @value{GDBN} debugging info for
> +breakpoint insertion and removal.
>  @end table
>  
>  @node Other Misc Settings
> -- 
> 2.25.1
>
> Intel Deutschland GmbH
> Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
> Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
> Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
> Chairperson of the Supervisory Board: Nicole Lau
> Registered Office: Munich
> Commercial Register: Amtsgericht Muenchen HRB 186928
  
Terekhov, Mikhail via Gdb-patches June 7, 2023, 12:20 p.m. UTC | #2
Hi Andrew, 

Thanks a lot for your review. 
I only have one small question, else I agree with all of your feedback.

> > +
> > +static std::string
> > +breakpoint_location_address_str (const bp_location* bl) {
> > +  std::string str = string_printf ("Breakpoint %d, location (%s) at address %s",
> > +				   bl->owner->number,
> > +				   host_address_to_string (bl),
> > +				   paddress (bl->gdbarch, bl->address));
> 
> I can't help but think using 'location' in this string is a bad idea, 'location' already
> has a meaning for GDB breakpoints.  How about just dropping the work
> 'location'?

Just to be sure that I understand correctly - do you suggest dropping the word 'location' in string_printf as follows:

static std::string
breakpoint_location_address_str (const bp_location* bl) {
  std::string str = string_printf ("Breakpoint %d (%s) at address %s",
			             bl->owner->number,
			             host_address_to_string (bl),
			             paddress (bl->gdbarch, bl->address));

This would be fine for me.

Best Regards,
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
  
Eli Zaretskii June 7, 2023, 12:38 p.m. UTC | #3
> From: Andrew Burgess <aburgess@redhat.com>
> Cc: eliz@gnu.org, simark@simark.ca
> Date: Wed, 07 Jun 2023 09:45:42 +0100
> 
> Christina Schimpe <christina.schimpe@intel.com> writes:
> 
> > From: Mihails Strasuns <mihails.strasuns@intel.com>
> >
> > Add new commands:
> >
> >   set debug breakpoints on|off
> >   show debug breakpoints

Sorry for missing this, but where's the original submission?  I don't
see it in my inbox.
  
Andrew Burgess June 7, 2023, 2:37 p.m. UTC | #4
"Schimpe, Christina" <christina.schimpe@intel.com> writes:

> Hi Andrew, 
>
> Thanks a lot for your review. 
> I only have one small question, else I agree with all of your feedback.
>
>> > +
>> > +static std::string
>> > +breakpoint_location_address_str (const bp_location* bl) {
>> > +  std::string str = string_printf ("Breakpoint %d, location (%s) at address %s",
>> > +				   bl->owner->number,
>> > +				   host_address_to_string (bl),
>> > +				   paddress (bl->gdbarch, bl->address));
>> 
>> I can't help but think using 'location' in this string is a bad idea, 'location' already
>> has a meaning for GDB breakpoints.  How about just dropping the work
>> 'location'?
>
> Just to be sure that I understand correctly - do you suggest dropping the word 'location' in string_printf as follows:
>
> static std::string
> breakpoint_location_address_str (const bp_location* bl) {
>   std::string str = string_printf ("Breakpoint %d (%s) at address %s",
> 			             bl->owner->number,
> 			             host_address_to_string (bl),
> 			             paddress (bl->gdbarch, bl->address));

Yes.  For me a location would either be something like '1.1' or maybe
just '1' if (given context) it is obvious we're talking about breakpoint
#1, thus 1.1 would be implied.

Or a location could be an address within the inferior for where the
location has been placed -- which is what I would naturally assume if I
saw an address labelled as a location.

There's also a benefit for removing extra text that the debug message
have more chance of fitting on the terminal without wrapping too much!

Thanks,
Andrew

>
> This would be fine for me.
>
> Best Regards,
> Christina
> Intel Deutschland GmbH
> Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
> Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
> Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
> Chairperson of the Supervisory Board: Nicole Lau
> Registered Office: Munich
> Commercial Register: Amtsgericht Muenchen HRB 186928
  
Andrew Burgess June 7, 2023, 2:40 p.m. UTC | #5
Eli Zaretskii <eliz@gnu.org> writes:

>> From: Andrew Burgess <aburgess@redhat.com>
>> Cc: eliz@gnu.org, simark@simark.ca
>> Date: Wed, 07 Jun 2023 09:45:42 +0100
>> 
>> Christina Schimpe <christina.schimpe@intel.com> writes:
>> 
>> > From: Mihails Strasuns <mihails.strasuns@intel.com>
>> >
>> > Add new commands:
>> >
>> >   set debug breakpoints on|off
>> >   show debug breakpoints
>
> Sorry for missing this, but where's the original submission?  I don't
> see it in my inbox.

Does this help at all?

  https://inbox.sourceware.org/gdb-patches/20230601163345.3895525-2-christina.schimpe@intel.com/

Thanks,
Andrew
  
Eli Zaretskii June 7, 2023, 3:32 p.m. UTC | #6
> From: Andrew Burgess <aburgess@redhat.com>
> Cc: christina.schimpe@intel.com, gdb-patches@sourceware.org, simark@simark.ca
> Date: Wed, 07 Jun 2023 15:40:01 +0100
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> >   set debug breakpoints on|off
> >> >   show debug breakpoints
> >
> > Sorry for missing this, but where's the original submission?  I don't
> > see it in my inbox.
> 
> Does this help at all?
> 
>   https://inbox.sourceware.org/gdb-patches/20230601163345.3895525-2-christina.schimpe@intel.com/

Yes, thanks.  The documentation parts are approved.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
  

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 649a3a9824a..c66fde54e85 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,11 @@ 
 
 *** Changes since GDB 13
 
+* GDB now has some support for integer types larger than 64 bits.
+* set debug breakpoints on|off
+  show debug breakpoints
+  Print additional debug messages about breakpoint insertion and removal.
+
 * The AArch64 'org.gnu.gdb.aarch64.pauth' Pointer Authentication feature string
   has been deprecated in favor of the 'org.gnu.gdb.aarch64.pauth_v2' feature
   string.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 0a520cfc169..dd8fac2f1ba 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -83,6 +83,7 @@ 
 #include "progspace-and-thread.h"
 #include "gdbsupport/array-view.h"
 #include "gdbsupport/gdb_optional.h"
+#include "gdbsupport/common-utils.h"
 
 /* Prototypes for local functions.  */
 
@@ -200,6 +201,68 @@  enum ugll_insert_mode
   UGLL_INSERT
 };
 
+/* Return a textual version of INSERT_MODE.  */
+
+static const char *
+ugll_insert_mode_text (ugll_insert_mode insert_mode)
+{
+/* Make sure the compiler warns if a new ugll_insert_mode enumerator is added
+   but not handled here.  */
+DIAGNOSTIC_PUSH
+DIAGNOSTIC_ERROR_SWITCH
+  switch (insert_mode)
+    {
+    case UGLL_DONT_INSERT:
+      return "UGLL_DONT_INSERT";
+    case UGLL_MAY_INSERT:
+      return "UGLL_MAY_INSERT";
+    case UGLL_INSERT:
+      return "UGLL_INSERT";
+    }
+DIAGNOSTIC_POP
+
+  gdb_assert_not_reached ("must handle all enum values");
+}
+
+/* Return a textual version of REASON.  */
+
+static const char *
+remove_bp_reason_str (remove_bp_reason reason)
+{
+/* Make sure the compiler warns if a new remove_bp_reason enumerator is added
+   but not handled here.  */
+DIAGNOSTIC_PUSH
+DIAGNOSTIC_ERROR_SWITCH
+  switch (reason)
+    {
+    case REMOVE_BREAKPOINT:
+      return "regular remove";
+    case DETACH_BREAKPOINT:
+      return "detach";
+    }
+DIAGNOSTIC_POP
+
+  gdb_assert_not_reached ("must handle all enum values");
+}
+
+/* Return a textual version of breakpoint BL describing number, location and
+   address.  */
+
+static std::string
+breakpoint_location_address_str (const bp_location* bl)
+{
+  std::string str = string_printf ("Breakpoint %d, location (%s) at address %s",
+				   bl->owner->number,
+				   host_address_to_string (bl),
+				   paddress (bl->gdbarch, bl->address));
+
+  std::string loc_string = bl->to_string ();
+  if (!loc_string.empty ())
+    str += string_printf (" %s", loc_string.c_str ());
+
+  return str;
+}
+
 static void update_global_location_list (enum ugll_insert_mode);
 
 static void update_global_location_list_nothrow (enum ugll_insert_mode);
@@ -510,6 +573,22 @@  show_always_inserted_mode (struct ui_file *file, int from_tty,
 	      value);
 }
 
+/* True if breakpoints debug output is enabled.  */
+static bool debug_breakpoints = false;
+
+/* Print a "breakpoints" debug statement.  */
+#define breakpoint_debug_printf(fmt, ...) \
+  debug_prefixed_printf_cond (debug_breakpoints, "breakpoints", fmt, \
+			      ##__VA_ARGS__)
+
+/* "show debug breakpoints" implementation.  */
+static void
+show_debug_breakpoints (struct ui_file *file, int from_tty,
+			struct cmd_list_element *c, const char *value)
+{
+  gdb_printf (file, _("Breakpoint location debugging is %s.\n"), value);
+}
+
 /* See breakpoint.h.  */
 
 int
@@ -2728,6 +2807,8 @@  insert_bp_location (struct bp_location *bl,
   if (!should_be_inserted (bl) || (bl->inserted && !bl->needs_update))
     return 0;
 
+  breakpoint_debug_printf ("%s", breakpoint_location_address_str (bl).c_str ());
+
   /* Note we don't initialize bl->target_info, as that wipes out
      the breakpoint location's shadow_contents if the breakpoint
      is still inserted at that location.  This in turn breaks
@@ -3270,6 +3351,8 @@  remove_breakpoints_inf (inferior *inf)
 {
   int val;
 
+  breakpoint_debug_printf ("inf->num = %d", inf->num);
+
   for (bp_location *bl : all_bp_locations ())
     {
       if (bl->pspace != inf->pspace)
@@ -3914,6 +3997,10 @@  detach_breakpoints (ptid_t ptid)
 static int
 remove_breakpoint_1 (struct bp_location *bl, enum remove_bp_reason reason)
 {
+  breakpoint_debug_printf ("%s due to %s",
+			   breakpoint_location_address_str (bl).c_str (),
+			   remove_bp_reason_str (reason));
+
   int val;
 
   /* BL is never in moribund_locations by our callers.  */
@@ -7424,6 +7511,14 @@  bp_location::bp_location (breakpoint *owner)
 {
 }
 
+std::string bp_location::to_string () const
+{
+  string_file stb;
+  ui_out_redirect_pop redir (current_uiout, &stb);
+  print_breakpoint_location (this->owner, this);
+  return stb.string ();
+}
+
 /* Decrement reference count.  If the reference count reaches 0,
    destroy the bp_location.  Sets *BLP to NULL.  */
 
@@ -11157,6 +11252,9 @@  update_global_location_list (enum ugll_insert_mode insert_mode)
   /* Last breakpoint location program space that was marked for update.  */
   int last_pspace_num = -1;
 
+  breakpoint_debug_printf ("insert_mode = %s",
+			   ugll_insert_mode_text (insert_mode));
+
   /* Used in the duplicates detection below.  When iterating over all
      bp_locations, points to the first bp_location of a given address.
      Breakpoints and watchpoints of different types are never
@@ -14899,6 +14997,15 @@  when execution stops."),
 				&breakpoint_set_cmdlist,
 				&breakpoint_show_cmdlist);
 
+  add_setshow_boolean_cmd ("breakpoints", class_maintenance,
+			   &debug_breakpoints, _("\
+Set breakpoint location debugging."), _("\
+Show breakpoint location debugging."), _("\
+When on, breakpoint location specific debugging is enabled."),
+			   NULL,
+			   show_debug_breakpoints,
+			   &setdebuglist, &showdebuglist);
+
   add_setshow_enum_cmd ("condition-evaluation", class_breakpoint,
 			condition_evaluation_enums,
 			&condition_evaluation_mode_1, _("\
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index da150585f73..f4896293bb7 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -509,6 +509,10 @@  class bp_location : public refcounted_object, public intrusive_list_node<bp_loca
 
   /* The objfile the symbol or minimal symbol were found in.  */
   const struct objfile *objfile = NULL;
+
+  /* Return a string representation of the bp_location.
+     This is only meant to be used in debug messages.  */
+  std::string to_string () const;
 };
 
 /* A policy class for bp_location reference counting.  */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index fc55c4e7b43..8c91ecab209 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -28356,6 +28356,14 @@  debugging info.
 Turn on or off debugging messages for built-in XML parsers.
 @item show debug xml
 Displays the current state of XML debugging messages.
+
+@item set debug breakpoints
+@cindex breakpoint debugging info
+Turns on or off display of @value{GDBN} debugging info for breakpoint insertion
+and removal.  The default is off.
+@item show debug breakpoints
+Displays the current state of displaying @value{GDBN} debugging info for
+breakpoint insertion and removal.
 @end table
 
 @node Other Misc Settings