This is the mail archive of the
gdb-patches@sourceware.cygnus.com
mailing list for the GDB project.
Handle_inferior_event() problem
- To: shebs at apple dot com, gdb-patches at sourceware dot cygnus dot com
- Subject: Handle_inferior_event() problem
- From: Elena Zannoni <ezannoni at cygnus dot com>
- Date: Tue, 7 Mar 2000 16:04:43 -0500 (EST)
Hi Stan,
how are things at Apple?
Remember WFI/handle_inferior_event() ?
There is a problem doing nexti while in a function prologue.
Say you have stepped your way to the first instruction of the prologue
of a function (using stepi, for instance) and now you do a 'nexti'.
The programs runs away to the end of the function or somewhere else and
gdb gets really confused.
What happens is this. After having issued a nexti, the target runs,
and it stops at the termporary breakpoint at the correct location, but
in handle_inferior_event there is this code:
if (stop_pc == ecs->stop_func_start /* Quick test */
|| (in_prologue (stop_pc, ecs->stop_func_start) &&
!IN_SOLIB_RETURN_TRAMPOLINE (stop_pc, ecs->stop_func_name))
|| IN_SOLIB_CALL_TRAMPOLINE (stop_pc, ecs->stop_func_name)
|| ecs->stop_func_name == 0)
{
/* It's a subroutine call. */
if (step_over_calls == 0)
{
/* I presume that step_over_calls is only 0 when we're
supposed to be stepping at the assembly language level
("stepi"). Just stop. */
stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
return;
}
if (step_over_calls > 0 || IGNORE_HELPER_CALL (stop_pc))
{
/* We're doing a "next". */
step_over_function (ecs);
keep_going (ecs);
return;
}
The first if is true, because
|| (in_prologue (stop_pc, ecs->stop_func_start) &&
!IN_SOLIB_RETURN_TRAMPOLINE (stop_pc, ecs->stop_func_name))
is true.
Then, if (step_over_calls > 0 || IGNORE_HELPER_CALL (stop_pc))
is true if you have just done a nexti.
So we get to keep_going, which continues the inferior.
Which is not what we want.
Looking at the old cvs versions of infrun.c, there once was a very
complicated test to check whether we are in a function call or not.
That test was disabled by Stu Grossman, ifdeffed out, end eventually
deleted. That test seems to have been doing things right for this case.
Here it is:
/* I disabled this test because it was too complicated and slow.
The SKIP_PROLOGUE was especially slow, because it caused
unnecessary prologue examination on various architectures.
The code in the #else clause has been tested on the Sparc,
Mips, PA, and Power architectures, so it's pretty likely to
be correct. -Stu 10/24/95 */
/* See if we left the step range due to a subroutine call that
we should proceed to the end of. */
if (stop_func_start)
{
struct symtab *s;
/* Do this after the IN_SIGTRAMP check; it might give
an error. */
prologue_pc = stop_func_start;
/* Don't skip the prologue if this is assembly source */
s = find_pc_symtab (stop_pc);
if (s && s->language != language_asm)
SKIP_PROLOGUE (prologue_pc);
}
if (!(INNER_THAN (step_sp, read_sp ())) /* don't mistake (sig)return
as a call */
&& ( /* Might be a non-recursive call. If the symbols are missing
enough that stop_func_start == prev_func_start even though
they are really two functions, we will treat some calls as
jumps. */
stop_func_start != prev_func_start
/* Might be a recursive call if either we have a prologue
or the call instruction itself saves the PC on the stack. */
|| prologue_pc != stop_func_start
|| read_sp () != step_sp)
&& ( /* PC is completely out of bounds of any known objfiles. Treat
like a subroutine call. */
!stop_func_start
/* If we do a call, we will be at the start of a function... */
|| stop_pc == stop_func_start
/* ...except on the Alpha with -O (and also Irix 5 and
perhaps others), in which we might call the address
after the load of gp. Since prologues don't contain
calls, we can't return to within one, and we don't
jump back into them, so this check is OK. */
|| stop_pc < prologue_pc
/* ...and if it is a leaf function, the prologue might
consist of gp loading only, so the call transfers to
the first instruction after the prologue. */
|| (stop_pc == prologue_pc
/* Distinguish this from the case where we jump back
to the first instruction after the prologue,
within a function. */
&& stop_func_start != prev_func_start)
/* If we end up in certain places, it means we did a subroutine
call. I'm not completely sure this is necessary now that we
have the above checks with stop_func_start (and now that
find_pc_partial_function is pickier). */
|| IN_SOLIB_CALL_TRAMPOLINE (stop_pc, stop_func_name)
/* If none of the above apply, it is a jump within a function,
or a return from a subroutine. The other case is longjmp,
which can no longer happen here as long as the
handling_longjmp stuff is working. */
))
Anyway, long story short... How about this patch? It doesn't take
care of everything, but it solves that immediate problem. Probably
other bugs have been introduced by eliminating that complex test. I am
not sure what should be done though.
Elena
Index: infrun.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/infrun.c,v
retrieving revision 1.277
diff -c -r1.277 infrun.c
*** infrun.c 2000/02/29 07:17:52 1.277
--- infrun.c 2000/03/07 20:47:57
***************
*** 2699,2705 ****
if (stop_pc == ecs->stop_func_start /* Quick test */
|| (in_prologue (stop_pc, ecs->stop_func_start) &&
! !IN_SOLIB_RETURN_TRAMPOLINE (stop_pc, ecs->stop_func_name))
|| IN_SOLIB_CALL_TRAMPOLINE (stop_pc, ecs->stop_func_name)
|| ecs->stop_func_name == 0)
{
--- 2710,2717 ----
if (stop_pc == ecs->stop_func_start /* Quick test */
|| (in_prologue (stop_pc, ecs->stop_func_start) &&
! !IN_SOLIB_RETURN_TRAMPOLINE (stop_pc, ecs->stop_func_name) &&
! ecs->stop_func_start != prev_func_start)
|| IN_SOLIB_CALL_TRAMPOLINE (stop_pc, ecs->stop_func_name)
|| ecs->stop_func_name == 0)
{