Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Andrew Burgess <aburgess@redhat.com>
To: Guinevere Larsen <guinevere@redhat.com>, gdb-patches@sourceware.org
Subject: Re: [PATCH] gdb: allow 'until' to work in outermost frame
Date: Thu, 11 Jun 2026 21:40:30 +0100	[thread overview]
Message-ID: <87o6hgq08x.fsf@redhat.com> (raw)
In-Reply-To: <02e967d8-a06a-4774-8618-e8fddd665c26@redhat.com>

Guinevere Larsen <guinevere@redhat.com> writes:

> On 6/8/26 3:14 PM, Andrew Burgess wrote:
>> The 'until' command with an argument, e.g. 'until *ADDRESS', is
>> implemented by the until_break_command in breakpoint.c.
>>
>> The most important thing this function does is convert the location
>> argument '*ADDRESS' in my example, into a vector of symtab_and_line
>> objects.  Each of these symtab_and_line objects is then used to create
>> a temporary bp_until breakpoint.
>>
>> The other thing that until_break_command does is create a breakpoint
>> in the caller frame.  This breakpoint is there to ensure the inferior
>> stops upon exiting the frame in which the 'until' command was issued.
>>
>> When compiling an assembler file into a static test program, if I use
>> 'starti' to stop the inferior within the outermost frame, and then try
>> to use 'until *ADDRESS' I see the following error:
>>
>>    (gdb) starti
>>    Starting program: /tmp/hello
>>
>>    Program stopped.
>>    0x0000000000401000 in _start ()
>>    (gdb) bt
>>    #0  0x0000000000401000 in _start ()
>>    (gdb) until *0x0000000000401015
>>    Warning:
>>    Cannot insert breakpoint 0.
>>    Cannot access memory at address 0x1
>>
>>    Command aborted.
>>    (gdb)
>>
>> The problem here is the breakpoint that 'until' tries to create in the
>> caller frame.  Though the 'bt' in the above example indicates that
>> there is only a single frame, the outermost frame, this is only
>> because GDB has specific code in get_prev_frame to stop the backtrace
>> at the outermost frame.  If we turn this off and try 'bt' again:
>>
>>    (gdb) set backtrace past-entry on
>>    (gdb) bt
>>    #0  0x0000000000401000 in _start ()
>>    #1  0x0000000000000001 in ?? ()
>>    #2  0x00007fffffffac73 in ?? ()
>>    #3  0x0000000000000000 in ?? ()
>>    (gdb)
>>
>> What we are seeing here is the garbage values that happen to be in the
>> registers tricking GDB into thinking there are frames before _start.
>>
>> GDB's code to handle this is in get_prev_frame, however, when 'until'
>> creates the caller frame breakpoint it calls frame_unwind_caller_pc
>> which calls frame_unwind_caller_frame, which skips get_prev_frame and
>> calls get_prev_frame_always.  As a result, the 'until' command will
>> try to place a breakpoint in the bogus frame #1 shown above.  As the
>> frame is at address 0x1, which is non-writable, we see an error when
>> trying to insert the breakpoint.
>>
>> In this commit I propose that we share the outer frame detection logic
>> between get_prev_frame and frame_unwind_caller_frame.  When 'backtrace
>> past-entry' is off, which is the default, frame_unwind_caller_frame
>> will return NULL for the outermost frame.  This means that a command
>> like 'until *ADDRESS' will no longer try to create a breakpoint in the
>> caller frame when used in the outermost frame.
>
> Why not simply change frame_unwind_caller_frame to call get_prev_frame 
> instead of get_prev_frame_always? feels like it would be a better idea 
> to not assume that the caller is always available anyway, rather than 
> porting the bits of work-arounds back to it

That's a great question.  get_prev_frame presents a "user" configured
view of the backtrace, for example it will stop at 'main', or the user
can adjust the number of visible frame with 'set backtrace limit N'.  In
these cases it is possible that get_prev_frame will return NULL
indicating that there is no previous frame, when in reality, there is a
previous frame.

In the context of the "until" command, where we want to place a
breakpoint in the caller frame, we want that breakpoint created even if
the user wouldn't normally see the caller frame in the 'bt' output.

As a concrete example, if a user makes use of 'until' in the 'main'
function, but the 'until' line is not hit, then GDB should stop upon
return from 'main'.  If we used get_prev_frame that wouldn't happen as
the previous frame is usually hidden from the user.

The entry frame is different.  The entry frame is the very first frame,
and there are no earlier frames.  But, that doesn't mean that GDB
doesn't see earlier frames!  If the inferior starts with garbage in its
registers then GDB might think there are frames before the entry frame,
but the chances are these frames are completely bogus, and trying to
place a breakpoint in them will only cause problems (e.g. cannot write
to memory errors).

If we look at all the checks in get_prev_frame there are:

  1. Should the unwind stop at main?  This check should be ignored for
     things like 'until'.

  2. Has the user backtrace limit been reached?  This check should be
     ignored for things like 'until'.

  3. Has the entry frame been reached?  I think this check should apply
     in the 'until' case.

  4. Have we reached a frame with a zero $pc?  I'm unsure about this
     one, so chose to ignore it for now.  It's possible that this should
     also apply in the 'until' case, but I've chosen to ignore this case
     for now without a motivating example.

A final note, I'm about to post a V2 for this patch, as what I posted
here still has some problems.

Thanks,
Andrew


  reply	other threads:[~2026-06-11 20:41 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-08 18:14 Andrew Burgess
2026-06-11 19:24 ` Guinevere Larsen
2026-06-11 20:40   ` Andrew Burgess [this message]
2026-06-12 12:49     ` Guinevere Larsen
2026-06-11 21:59 ` [PATCHv2 0/3] " Andrew Burgess
2026-06-11 21:59   ` [PATCHv2 1/3] gdb: rename program_space::entry_point_address* functions Andrew Burgess
2026-06-12 15:41     ` Pedro Alves
2026-06-11 21:59   ` [PATCHv2 2/3] gdb: introduce program_space::get_entry_point_info function Andrew Burgess
2026-06-12  6:07     ` Eli Zaretskii
2026-06-15 10:14       ` Andrew Burgess
2026-06-15 12:01         ` Eli Zaretskii
2026-06-12 15:41     ` Pedro Alves
2026-06-15 10:29       ` Andrew Burgess
2026-06-16 18:36         ` Pedro Alves
2026-06-23  9:46           ` Andrew Burgess
2026-06-23 10:20             ` Pedro Alves
2026-06-11 21:59   ` [PATCHv2 3/3] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-06-12 15:57     ` Pedro Alves
2026-06-16 19:47   ` [PATCHv3 0/4] " Andrew Burgess
2026-06-16 19:47     ` [PATCHv3 1/4] gdb: rename program_space::entry_point_address* functions Andrew Burgess
2026-06-16 19:47     ` [PATCHv3 2/4] gdb: introduce program_space::get_entry_point_info function Andrew Burgess
2026-06-17 11:52       ` Eli Zaretskii
2026-06-16 19:47     ` [PATCHv3 3/4] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-06-16 19:47     ` [PATCHv3 4/4] gdb: cache program space entry point information Andrew Burgess
2026-06-23 10:47     ` [PATCHv4 0/4] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-06-23 10:47       ` [PATCHv4 1/4] gdb: rename program_space::entry_point_address* functions Andrew Burgess
2026-06-23 10:47       ` [PATCHv4 2/4] gdb: introduce program_space::get_entry_point_info function Andrew Burgess
2026-06-23 10:47       ` [PATCHv4 3/4] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-06-23 10:47       ` [PATCHv4 4/4] gdb: cache program space entry point information Andrew Burgess
2026-06-25 15:26       ` [PATCHv5 0/4] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-06-25 15:26         ` [PATCHv5 1/4] gdb: rename program_space::entry_point_address* functions Andrew Burgess
2026-06-25 15:26         ` [PATCHv5 2/4] gdb: introduce program_space::get_entry_point_info function Andrew Burgess
2026-06-25 15:26         ` [PATCHv5 3/4] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-06-25 15:26         ` [PATCHv5 4/4] gdb: cache program space entry point information Andrew Burgess
2026-07-10 14:24         ` [PATCHv6 0/4] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-07-10 14:24           ` [PATCHv6 1/4] gdb: rename program_space::entry_point_address* functions Andrew Burgess
2026-07-10 14:24           ` [PATCHv6 2/4] gdb: introduce program_space::get_entry_point_info function Andrew Burgess
2026-07-10 15:39             ` Simon Marchi
2026-07-10 14:24           ` [PATCHv6 3/4] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-07-10 17:00             ` Simon Marchi
2026-07-10 17:01               ` Simon Marchi
2026-07-16 15:06               ` Andrew Burgess
2026-07-10 14:24           ` [PATCHv6 4/4] gdb: cache program space entry point information Andrew Burgess
2026-07-10 17:07             ` Simon Marchi
2026-07-18 13:11           ` [PATCHv7 0/4] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-07-18 13:11             ` [PATCHv7 1/4] gdb: rename program_space::entry_point_address* functions Andrew Burgess
2026-07-18 13:11             ` [PATCHv7 2/4] gdb: introduce program_space::get_entry_point_info function Andrew Burgess
2026-07-18 13:11             ` [PATCHv7 3/4] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-07-18 13:11             ` [PATCHv7 4/4] gdb: cache program space entry point information Andrew Burgess
2026-07-20  9:52             ` [PATCHv8 0/4] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-07-20  9:52               ` [PATCHv8 1/4] gdb: rename program_space::entry_point_address* functions Andrew Burgess
2026-07-20  9:52               ` [PATCHv8 2/4] gdb: introduce program_space::get_entry_point_info function Andrew Burgess
2026-07-20  9:52               ` [PATCHv8 3/4] gdb: allow 'until' to work in outermost frame Andrew Burgess
2026-07-20  9:52               ` [PATCHv8 4/4] gdb: cache program space entry point information Andrew Burgess

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87o6hgq08x.fsf@redhat.com \
    --to=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    --cc=guinevere@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox