Use GCC5/DWARF5 DW_AT_noreturn to mark functions that don't return normally.

Add a flag field is_noreturn to struct func_type. Make calling_convention
a small bit field to not increase the size of the struct. Set is_noreturn
if the new GCC5/DWARF5 DW_AT_noreturn is set on a DW_TAG_subprogram.
Use this information to warn the user before doing a finish or return from
a function that does not return normally to its caller.

(gdb) finish
warning: Function endless does not return normally.
Try to finish anyway? (y or n)

(gdb) return
warning: Function does not return normally to caller.
Make endless return now? (y or n)

gdb/ChangeLog

	* dwarf2read.c (read_subroutine_type): Set TYPE_NO_RETURN from
	DW_AT_noreturn.
	* gdbtypes.h (struct func_type): Add is_noreturn field flag. Make
	calling_convention an 8 bit bit field.
	(TYPE_NO_RETURN): New macro.
	* infcmd.c (finish_command): Query if function does not return
	normally.
	* stack.c (return_command): Likewise.

gdb/testsuite/ChangeLog

	* gdb.base/noreturn-return.c: New file.
	* gdb.base/noreturn-return.exp: New file.
	* gdb.base/noreturn-finish.c: New file.
	* gdb.base/noreturn-finish.exp: New file.

include/ChangeLog

	* dwarf2.def (DW_AT_noreturn): New DWARF5 attribute.

The dwarf2.h addition and the code to emit the new attribute is already in
the gcc tree.
This commit is contained in:
Mark Wielaard 2014-12-09 11:45:41 +01:00
parent 198297aafb
commit 743649fd80
12 changed files with 218 additions and 5 deletions

View file

@ -1,3 +1,14 @@
2015-01-15 Mark Wielaard <mjw@redhat.com>
* dwarf2read.c (read_subroutine_type): Set TYPE_NO_RETURN from
DW_AT_noreturn.
* gdbtypes.h (struct func_type): Add is_noreturn field flag. Make
calling_convention an 8 bit bit field.
(TYPE_NO_RETURN): New macro.
* infcmd.c (finish_command): Query if function does not return
normally.
* stack.c (return_command): Likewise.
2015-01-23 Pedro Alves <palves@redhat.com> 2015-01-23 Pedro Alves <palves@redhat.com>
* linux-nat.c (linux_is_async_p): New macro. * linux-nat.c (linux_is_async_p): New macro.

View file

@ -14343,6 +14343,12 @@ read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu)
else else
TYPE_CALLING_CONVENTION (ftype) = DW_CC_normal; TYPE_CALLING_CONVENTION (ftype) = DW_CC_normal;
/* Record whether the function returns normally to its caller or not
if the DWARF producer set that information. */
attr = dwarf2_attr (die, DW_AT_noreturn, cu);
if (attr && (DW_UNSND (attr) != 0))
TYPE_NO_RETURN (ftype) = 1;
/* We need to add the subroutine type to the die immediately so /* We need to add the subroutine type to the die immediately so
we don't infinitely recurse when dealing with parameters we don't infinitely recurse when dealing with parameters
declared as the same subroutine type. */ declared as the same subroutine type. */

View file

@ -1019,9 +1019,16 @@ struct func_type
{ {
/* * The calling convention for targets supporting multiple ABIs. /* * The calling convention for targets supporting multiple ABIs.
Right now this is only fetched from the Dwarf-2 Right now this is only fetched from the Dwarf-2
DW_AT_calling_convention attribute. */ DW_AT_calling_convention attribute. The value is one of the
DW_CC enum dwarf_calling_convention constants. */
unsigned calling_convention; unsigned calling_convention : 8;
/* * Whether this function normally returns to its caller. It is
set from the DW_AT_noreturn attribute if set on the
DW_TAG_subprogram. */
unsigned int is_noreturn : 1;
/* * Only those DW_TAG_GNU_call_site's in this function that have /* * Only those DW_TAG_GNU_call_site's in this function that have
DW_AT_GNU_tail_call set are linked in this list. Function DW_AT_GNU_tail_call set are linked in this list. Function
@ -1245,6 +1252,7 @@ extern void allocate_gnat_aux_type (struct type *);
#define TYPE_GNAT_SPECIFIC(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.gnat_stuff #define TYPE_GNAT_SPECIFIC(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.gnat_stuff
#define TYPE_DESCRIPTIVE_TYPE(thistype) TYPE_GNAT_SPECIFIC(thistype)->descriptive_type #define TYPE_DESCRIPTIVE_TYPE(thistype) TYPE_GNAT_SPECIFIC(thistype)->descriptive_type
#define TYPE_CALLING_CONVENTION(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->calling_convention #define TYPE_CALLING_CONVENTION(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->calling_convention
#define TYPE_NO_RETURN(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->is_noreturn
#define TYPE_TAIL_CALL_LIST(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->tail_call_list #define TYPE_TAIL_CALL_LIST(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->tail_call_list
#define TYPE_BASECLASS(thistype,index) TYPE_FIELD_TYPE(thistype, index) #define TYPE_BASECLASS(thistype,index) TYPE_FIELD_TYPE(thistype, index)
#define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses #define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses

View file

@ -1872,7 +1872,14 @@ finish_command (char *arg, int from_tty)
if (execution_direction == EXEC_REVERSE) if (execution_direction == EXEC_REVERSE)
printf_filtered (_("Run back to call of ")); printf_filtered (_("Run back to call of "));
else else
printf_filtered (_("Run till exit from ")); {
if (function != NULL && TYPE_NO_RETURN (function->type)
&& !query (_("warning: Function %s does not return normally.\n"
"Try to finish anyway? "),
SYMBOL_PRINT_NAME (function)))
error (_("Not confirmed."));
printf_filtered (_("Run till exit from "));
}
print_stack_frame (get_selected_frame (NULL), 1, LOCATION, 0); print_stack_frame (get_selected_frame (NULL), 1, LOCATION, 0);
} }

View file

@ -2462,8 +2462,12 @@ return_command (char *retval_exp, int from_tty)
confirmed = query (_("%sMake selected stack frame return now? "), confirmed = query (_("%sMake selected stack frame return now? "),
query_prefix); query_prefix);
else else
confirmed = query (_("%sMake %s return now? "), query_prefix, {
SYMBOL_PRINT_NAME (thisfun)); if (TYPE_NO_RETURN (thisfun->type))
warning ("Function does not return normally to caller.");
confirmed = query (_("%sMake %s return now? "), query_prefix,
SYMBOL_PRINT_NAME (thisfun));
}
if (!confirmed) if (!confirmed)
error (_("Not confirmed")); error (_("Not confirmed"));
} }

View file

@ -1,3 +1,10 @@
2015-01-15 Mark Wielaard <mjw@redhat.com>
* gdb.base/noreturn-return.c: New file.
* gdb.base/noreturn-return.exp: New file.
* gdb.base/noreturn-finish.c: New file.
* gdb.base/noreturn-finish.exp: New file.
2015-01-23 Pedro Alves <palves@redhat.com> 2015-01-23 Pedro Alves <palves@redhat.com>
* gdb.threads/continue-pending-after-query.c: New file. * gdb.threads/continue-pending-after-query.c: New file.

View file

@ -0,0 +1,31 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2015 Free Software Foundation, Inc.
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>
void __attribute__((noreturn))
noreturn_func (void)
{
abort ();
}
int
main (void)
{
noreturn_func ();
return 0;
}

View file

@ -0,0 +1,51 @@
# Copyright 2015 Free Software Foundation, Inc.
# 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/>.
standard_testfile
if [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} {debug}] {
return -1
}
proc noreturn_finish_test { } {
global gdb_prompt
if { ! [ runto_main ] } then {
untested ${testfile}.exp
return -1
}
gdb_breakpoint "noreturn_func"
gdb_continue_to_breakpoint "noreturn_func"
set test "cancel finish from noreturn_func"
gdb_test_multiple "finish" $test {
-re "warning: Function noreturn_func does not return normally" {
verbose -log "saw warning"
exp_continue
}
-re "Try to finish anyway.*y or n.* $" {
send_gdb "n\n"
exp_continue
}
-re ".*$gdb_prompt $" {
pass $test
}
}
}
clean_restart ${binfile}
noreturn_finish_test

View file

@ -0,0 +1,31 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2015 Free Software Foundation, Inc.
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>
void __attribute__((noreturn))
noreturn_func (void)
{
abort ();
}
int
main (void)
{
noreturn_func ();
return 0;
}

View file

@ -0,0 +1,51 @@
# Copyright 2015 Free Software Foundation, Inc.
# 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/>.
standard_testfile
if [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} {debug}] {
return -1
}
proc noreturn_test { } {
global gdb_prompt
if { ! [ runto_main ] } then {
untested ${testfile}.exp
return -1
}
gdb_breakpoint "noreturn_func"
gdb_continue_to_breakpoint "noreturn_func"
set test "cancel return from noreturn_func"
gdb_test_multiple "return" $test {
-re "warning: Function does not return normally to caller" {
verbose -log "saw warning"
exp_continue
}
-re "Make noreturn_func return now.*y or n. $" {
send_gdb "n\n"
exp_continue
}
-re "Not confirmed.*$gdb_prompt $" {
pass $test
}
}
}
clean_restart ${binfile}
noreturn_test

View file

@ -1,3 +1,7 @@
2015-01-15 Mark Wielaard <mjw@redhat.com>
* dwarf2.def (DW_AT_noreturn): New DWARF5 attribute.
2015-01-14 Jan-Benedict Glaw <jbglaw@lug-owl.de> 2015-01-14 Jan-Benedict Glaw <jbglaw@lug-owl.de>
* libiberty.h: Merge from GCC. * libiberty.h: Merge from GCC.

View file

@ -306,6 +306,8 @@ DW_AT (DW_AT_data_bit_offset, 0x6b)
DW_AT (DW_AT_const_expr, 0x6c) DW_AT (DW_AT_const_expr, 0x6c)
DW_AT (DW_AT_enum_class, 0x6d) DW_AT (DW_AT_enum_class, 0x6d)
DW_AT (DW_AT_linkage_name, 0x6e) DW_AT (DW_AT_linkage_name, 0x6e)
/* DWARF 5. */
DW_AT (DW_AT_noreturn, 0x87)
DW_AT_DUP (DW_AT_lo_user, 0x2000) /* Implementation-defined range start. */ DW_AT_DUP (DW_AT_lo_user, 0x2000) /* Implementation-defined range start. */
DW_AT_DUP (DW_AT_hi_user, 0x3fff) /* Implementation-defined range end. */ DW_AT_DUP (DW_AT_hi_user, 0x3fff) /* Implementation-defined range end. */