forked from Imagelibrary/binutils-gdb
I noticed that attempting to select a tail-call frame using 'frame function NAME' wouldn't work: (gdb) bt #0 func_that_never_returns () at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/frame-selection.c:49 #1 0x0000000000401183 in func_that_tail_calls () at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/frame-selection.c:59 #2 0x00000000004011a5 in main () at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/frame-selection.c:70 (gdb) frame function func_that_tail_calls No frame for function "func_that_tail_calls". (gdb) up #1 0x0000000000401183 in func_that_tail_calls () at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/frame-selection.c:59 59 func_that_never_returns (); (gdb) disassemble Dump of assembler code for function func_that_tail_calls: 0x000000000040117a <+0>: push %rbp 0x000000000040117b <+1>: mov %rsp,%rbp 0x000000000040117e <+4>: call 0x40116c <func_that_never_returns> End of assembler dump. (gdb) The problem is that the 'function' mechanism uses get_frame_pc() and then compares the address returned with the bounds of the function we're looking for. So in this case, the bounds of func_that_tail_calls are 0x40117a to 0x401183, with 0x401183 being the first address _after_ the function. However, because func_that_tail_calls ends in a tail call, then the get_frame_pc() is 0x401183, the first address after the function. As a result, GDB fails to realise that frame #1 is inside the function we're looking for, and the lookup fails. The fix is to use get_frame_address_in_block, which will return an adjusted address, in this case, 0x401182, which is within the function bounds. Now the lookup works: (gdb) frame function func_that_tail_calls #1 0x0000000000401183 in func_that_tail_calls () at /tmp/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/frame-selection.c:59 59 func_that_never_returns (); (gdb) I've extended the gdb.base/frame-selection.exp test to cover this case.
74 lines
1.4 KiB
C
74 lines
1.4 KiB
C
/* Copyright 2018-2024 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include <stdlib.h>
|
|
|
|
int
|
|
frame_2 (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
frame_1 (void)
|
|
{
|
|
return frame_2 ();
|
|
}
|
|
|
|
int
|
|
recursive (int arg)
|
|
{
|
|
int v;
|
|
|
|
if (arg < 2)
|
|
v = recursive (arg + 1);
|
|
else
|
|
v = frame_2 ();
|
|
|
|
return v;
|
|
}
|
|
|
|
/* A function that never returns. */
|
|
void __attribute__((noreturn))
|
|
func_that_never_returns (void)
|
|
{
|
|
exit (0);
|
|
}
|
|
|
|
/* A function that tail calls. Calling a 'noreturn' function isn't
|
|
required for a tail call, but at low optimisation levels, gcc will apply
|
|
the tail call optimisation only for 'noreturn' calls. */
|
|
|
|
void
|
|
func_that_tail_calls (void)
|
|
{
|
|
func_that_never_returns ();
|
|
}
|
|
|
|
int
|
|
main (void)
|
|
{
|
|
int i, j;
|
|
|
|
i = frame_1 ();
|
|
j = recursive (0);
|
|
|
|
func_that_tail_calls ();
|
|
|
|
return i + j;
|
|
}
|