From: Tom de Vries <tdevries@suse.de>
To: Simon Marchi <simon.marchi@polymtl.ca>, gdb-patches@sourceware.org
Subject: Re: [PATCH][gdb/testsuite] Fix gdb.python/py-finish-breakpoint2.exp with -m32
Date: Thu, 21 Jan 2021 09:29:35 +0100 [thread overview]
Message-ID: <a44763bf-28f8-def1-1016-baf375eca2b3@suse.de> (raw)
In-Reply-To: <3dcf9e40-5409-9015-b09b-56e9fcf0e752@polymtl.ca>
On 1/21/21 8:04 AM, Simon Marchi wrote:
> On 2021-01-18 5:31 a.m., Tom de Vries wrote:
>> Hi,
>>
>> When running test-case gdb.python/py-finish-breakpoint2.exp with target board
>> unix/-m32, we run into:
>> ...
>> (gdb) continue^M
>> Continuing.^M
>> Exception #10^M
>> ^M
>> Breakpoint 3, throw_exception_1 (e=10) at py-finish-breakpoint2.cc:23^M
>> 23 throw new int (e);^M
>> (gdb) FAIL: gdb.python/py-finish-breakpoint2.exp: \
>> check FinishBreakpoint in catch()
>> ...
>> With -m64, the test passes.
>>
>> Relevant bit of the source:
>> ...
>> 36 try
>> 37 {
>> 38 throw_exception_1 (10);
>> 39 }
>> 40 catch (const int *e)
>> 41 {
>> 42 std::cerr << "Exception #" << *e << std::endl;
>> 43 }
>> 44 i += 1; /* Break after exception 1. */
>> ...
>>
>> The -m64 scenario in more detail:
>> - the test-case runs to throw_exception_1.
>> - it installs a FinishBreakpoint, which is a temporary breakpoint set at the
>> return address of a frame.
>> - for -m64, that address is:
>> 400c47: 83 45 e4 01 addl $0x1,-0x1c(%rbp)
>> which corresponds the "i += 1 at line 44"
>> - the test-case then continues
>> - an exception is throw in throw_exection_1
>> - the exception is caught at line 40, and a message is printed
>> - line 44 is executed, and the FinishBreakpoint triggers.
>>
>> With -m32, we have instead:
>> - the address where the finish breakpoint is set is:
>> 8048a0a: 83 c4 10 add $0x10,%esp
>> which is the lasn insn generated for the call at line 38
>> - the test-case continues
>> - an exception is throw in throw_exection_1
>> - consequently, the FinishBreakpoint is not triggered.
>>
>> In conclusion, the test worked by accident for -m64, because the first insn
>> after the call to throw_exception_1 is also the first insn after the try.
>> And that just happens to be not the case for -m32.
>>
>> Fix this by removing this part of the test.
>>
>> Tested on x86_64-linux.
>>
>> Any comments?
>>
>> Thanks,
>> - Tom
>>
>> [gdb/testsuite] Fix gdb.python/py-finish-breakpoint2.exp with -m32
>>
>> gdb/testsuite/ChangeLog:
>>
>> 2021-01-18 Tom de Vries <tdevries@suse.de>
>>
>> * gdb.python/py-finish-breakpoint2.exp: Remove part of test that
>> works by accident.
>>
>> ---
>> gdb/testsuite/gdb.python/py-finish-breakpoint2.exp | 6 ------
>> 1 file changed, 6 deletions(-)
>>
>> diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp b/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp
>> index 10c4b6e81b8..4193f073996 100644
>> --- a/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp
>> +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp
>> @@ -46,12 +46,6 @@ gdb_test "source $pyfile" ".*Python script imported.*" \
>>
>> gdb_breakpoint "throw_exception_1"
>> gdb_test "continue" "Breakpoint .*throw_exception_1.*" "run to exception 1"
>> -
>> -gdb_test "python print (len(gdb.breakpoints()))" "3" "check BP count"
>> -gdb_test "python ExceptionFinishBreakpoint(gdb.newest_frame())" "init ExceptionFinishBreakpoint" "set FinishBP after the exception"
>> -gdb_test "continue" ".*stopped at ExceptionFinishBreakpoint.*" "check FinishBreakpoint in catch()"
>> -gdb_test "python print (len(gdb.breakpoints()))" "3" "check finish BP removal"
>> -
>> gdb_test "continue" ".*Breakpoint.* throw_exception_1.*" "continue to second exception"
>> gdb_test "python ExceptionFinishBreakpoint(gdb.newest_frame())" "init ExceptionFinishBreakpoint" "set FinishBP after the exception"
>> gdb_test "continue" ".*exception did not finish.*" "FinishBreakpoint with exception thrown not caught"
>>
>
> Hmm I'd like to understand better the original intent of the test.
>
> Clearly, it tries to test two different things, because the first
> time it expects to see the print from the "stop" method, and the
> second time it expects to see the print from the "out_of_scope"
> method.
Agreed, the intent of the test is to test both scenarios, in the context
of throwing an exception.
> But I don't really understand what's different in both
> cases. Both times it just runs to throw_exception_1 and sets
> a FinishBreakpoint. The throw_exception_1 function just throws,
> so presumably, we should expect the same outcome both times,
> don't we? And that outcome should be that the out_of_scope
> method gets called, right?
>
Well, the difference between the two scenarios is in the call stack at
the point that we set the FinishBreakpoint:
- in the first scenario, the call stack is:
main -> throw_exception_1
- in the second scenario, the call stack is:
main -> throw_exception -> throw_exception_1
In the second scenario, the FinishBreakpoint is set in the
throw_exception function on the insn after the call to
throw_exception_1. This guarantees that FinishBreakpoint.stop will not
trigger, so FinishBreakpoint.out_of_scope will get called.
In the first scenario, the FinishBreakpoint is set on the insn after the
call to throw_exception_1 in main. For -m32, that happens to be an insn
in the try clause, and FinishBreakpoint.stop will not trigger. For
-m64, that happens to be the location after the try/catch, and
FinishBreakpoint.stop will trigger.
The different outcomes for -m32 and -m64 are both valid given the
semantics of FinishBreakpoint, which is "set at the return address of a
frame". It all depends where that return address is. There is no
guarantee that the return address is an insn that uniquely represent the
function return control path.
> When I try to replicate the bit you removed by hand, I indeed
> get two different things with -m32 and -m64, and both are not
> the one I expect. With -m64, "stop", gets called:
>
> $ ./gdb -q -nx --data-directory=data-directory m64 -ex "b throw_exception_1" -ex r -x ~/src/binutils-gdb/gdb/testsuite/gdb.python/py-finish-breakpoint2.py -ex "python ExceptionFinishBreakpoint(gdb.newest_frame())"
> Reading symbols from m64...
> Breakpoint 1 at 0x11f7: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-finish-breakpoint2.cc, line 23.
> Starting program: /home/simark/build/binutils-gdb/gdb/m64
>
> Breakpoint 1, throw_exception_1 (e=10) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-finish-breakpoint2.cc:23
> 23 throw new int (e);
> Python script imported
> init ExceptionFinishBreakpoint
> (gdb) continue
> Continuing.
> Exception #10
> stopped at ExceptionFinishBreakpoint
>
Right, the FinishBreakpoint is set at the insn after the try/catch and
the stop triggers.
> And with -m32, nothing gets gets called, the FinishBreakpoint
> just never hits (we just hit throw_exception_1 later):
>
Right, the FinishBreakpoint is set in the try clause and stop doesn't
trigger. If we run to exit, we'll hit out_of_scope.
> ./gdb -q -nx --data-directory=data-directory m32 -ex "b throw_exception_1" -ex r -x ~/src/binutils-gdb/gdb/testsuite/gdb.python/py-finish-breakpoint2.py -ex "python ExceptionFinishBreakpoint(gdb.newest_frame())"
> Reading symbols from m32...
> Breakpoint 1 at 0x1261: file /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-finish-breakpoint2.cc, line 23.
> Starting program: /home/simark/build/binutils-gdb/gdb/m32
>
> Breakpoint 1, throw_exception_1 (e=10) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-finish-breakpoint2.cc:23
> 23 throw new int (e);
> Python script imported
> init ExceptionFinishBreakpoint
> (gdb) continue
> Continuing.
> Exception #10
>
> Breakpoint 1, throw_exception_1 (e=10) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.python/py-finish-breakpoint2.cc:23
> 23 throw new int (e);
> (gdb)
>
>
> Surely, there is some bug in there. Shouldn't we at least
> see the same behavior for -m32 and -m64 for what I shown
> above? Can you help me understand what is happening here?
I don't see a bug here. I think different behaviour for -m32 and -m64
(and for other architectures) is possible. All I see here is a test
that depends on a coincidence.
Perhaps it helps to think of a Finish Breakpoint as a "Return address
Breakpoint".
Thanks,
- Tom
next prev parent reply other threads:[~2021-01-21 8:29 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-01-18 10:31 Tom de Vries
2021-01-21 7:04 ` Simon Marchi via Gdb-patches
2021-01-21 8:29 ` Tom de Vries [this message]
2021-01-21 8:45 ` Tom de Vries
2021-01-21 14:22 ` Simon Marchi via Gdb-patches
2021-09-28 14:33 ` [RFC][gdb/python] FinishBreakPoint update Tom de Vries via Gdb-patches
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=a44763bf-28f8-def1-1016-baf375eca2b3@suse.de \
--to=tdevries@suse.de \
--cc=gdb-patches@sourceware.org \
--cc=simon.marchi@polymtl.ca \
/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