* stack.c (return_command <retval_exp>): New variables retval_expr
	and old_chain.  Inline parse_and_eval to initialize retval_expr.  Check
	RETVAL_EXPR for UNOP_CAST and set RETURN_TYPE to the RETURN_VALUE type
	if RETURN_TYPE is NULL.

gdb/doc/
	* gdb.texinfo (Returning): New description for missing debug info.

gdb/testsuite/
	* gdb.base/return-nodebug.exp, gdb.base/return-nodebug.c: New.
This commit is contained in:
Jan Kratochvil 2009-03-15 09:19:40 +00:00
parent 30c665df3f
commit 61ff14c69a
7 changed files with 191 additions and 10 deletions

View file

@ -1,3 +1,10 @@
2009-03-15 Jan Kratochvil <jan.kratochvil@redhat.com>
* stack.c (return_command <retval_exp>): New variables retval_expr
and old_chain. Inline parse_and_eval to initialize retval_expr. Check
RETVAL_EXPR for UNOP_CAST and set RETURN_TYPE to the RETURN_VALUE type
if RETURN_TYPE is NULL.
2009-03-14 Pedro Alves <pedro@codesourcery.com>
* remote.c (PACKET_qAttached): New.

View file

@ -1,3 +1,7 @@
2009-03-15 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.texinfo (Returning): New description for missing debug info.
2009-03-14 Pedro Alves <pedro@codesourcery.com>
* gdb.texinfo (Remote Configuration): Document query-attached.

View file

@ -12494,6 +12494,53 @@ returned. In contrast, the @code{finish} command (@pxref{Continuing
and Stepping, ,Continuing and Stepping}) resumes execution until the
selected stack frame returns naturally.
@value{GDBN} needs to know how the @var{expression} argument should be set for
the inferior. The concrete registers assignment depends on the OS ABI and the
type being returned by the selected stack frame. For example it is common for
OS ABI to return floating point values in FPU registers while integer values in
CPU registers. Still some ABIs return even floating point values in CPU
registers. Larger integer widths (such as @code{long long int}) also have
specific placement rules. @value{GDBN} already knows the OS ABI from its
current target so it needs to find out also the type being returned to make the
assignment into the right register(s).
Normally, the selected stack frame has debug info. @value{GDBN} will always
use the debug info instead of the implicit type of @var{expression} when the
debug info is available. For example, if you type @kbd{return -1}, and the
function in the current stack frame is declared to return a @code{long long
int}, @value{GDBN} transparently converts the implicit @code{int} value of -1
into a @code{long long int}:
@smallexample
Breakpoint 1, func () at gdb.base/return-nodebug.c:29
29 return 31;
(@value{GDBP}) return -1
Make func return now? (y or n) y
#0 0x004004f6 in main () at gdb.base/return-nodebug.c:43
43 printf ("result=%lld\n", func ());
(@value{GDBP})
@end smallexample
However, if the selected stack frame does not have a debug info, e.g., if the
function was compiled without debug info, @value{GDBN} has to find out the type
to return from user. Specifying a different type by mistake may set the value
in different inferior registers than the caller code expects. For example,
typing @kbd{return -1} with its implicit type @code{int} would set only a part
of a @code{long long int} result for a debug info less function (on 32-bit
architectures). Therefore the user is required to specify the return type by
an appropriate cast explicitly:
@smallexample
Breakpoint 2, 0x0040050b in func ()
(@value{GDBP}) return -1
Return value type not available for selected stack frame.
Please use an explicit cast of the value to return.
(@value{GDBP}) return (long long int) -1
Make selected stack frame return now? (y or n) y
#0 0x00400526 in main ()
(@value{GDBP})
@end smallexample
@node Calling
@section Calling Program Functions

View file

@ -1796,18 +1796,27 @@ return_command (char *retval_exp, int from_tty)
message. */
if (retval_exp)
{
struct expression *retval_expr = parse_expression (retval_exp);
struct cleanup *old_chain = make_cleanup (xfree, retval_expr);
struct type *return_type = NULL;
/* Compute the return value. Should the computation fail, this
call throws an error. */
return_value = parse_and_eval (retval_exp);
return_value = evaluate_expression (retval_expr);
/* Cast return value to the return type of the function. Should
the cast fail, this call throws an error. */
if (thisfun != NULL)
return_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (thisfun));
if (return_type == NULL)
return_type = builtin_type (get_frame_arch (thisframe))->builtin_int;
{
if (retval_expr->elts[0].opcode != UNOP_CAST)
error (_("Return value type not available for selected "
"stack frame.\n"
"Please use an explicit cast of the value to return."));
return_type = value_type (return_value);
}
do_cleanups (old_chain);
CHECK_TYPEDEF (return_type);
return_value = value_cast (return_type, return_value);

View file

@ -1,3 +1,7 @@
2009-03-15 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.base/return-nodebug.exp, gdb.base/return-nodebug.c: New.
2009-03-14 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix a racy FAIL.

View file

@ -0,0 +1,49 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2009 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 <stdio.h>
static TYPE
init (void)
{
return 0;
}
static TYPE
func (void)
{
return 31;
}
static void
marker (void)
{
}
int
main (void)
{
/* Preinitialize registers to 0 to avoid false PASS by leftover garbage. */
init ();
printf ("result=" FORMAT "\n", CAST func ());
/* Cannot `next' with no debug info. */
marker ();
return 0;
}

View file

@ -0,0 +1,61 @@
# Copyright (C) 2009 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/>.
proc do_test {type} {
set typenospace [string map {{ } -} $type]
global pf_prefix
set old_prefix $pf_prefix
lappend pf_prefix "$typenospace:"
if {[runto "func"]} {
# Verify that we do not crash when using "return" from a function with
# no debugging info. Such function has no `struct symbol'. It may
# still have an associated `struct minimal_symbol'.
gdb_test "return -1" \
"Return value type not available for selected stack frame\\.\r\nPlease use an explicit cast of the value to return\\." \
"return from function with no debug info without a cast"
# Cast of the result to the proper width must be done explicitely.
gdb_test "return ($type) -1" "#0 .* main \\(.*" \
"return from function with no debug info with a cast" \
"Make selected stack frame return now\\? \\(y or n\\) " "y"
# And if it returned the full width of the result.
gdb_test "adv marker" "\r\nresult=-1\r\n.* in marker \\(.*" \
"full width of the returned result"
}
set pf_prefix $old_prefix
}
foreach case {{{signed char} %d (int)} \
{{short} %d (int)} \
{{int} %d} \
{{long} %ld} \
{{long long} %lld}} {
set type [lindex $case 0]
set format [lindex $case 1]
set cast [lindex $case 2]
set typeesc [string map {{ } {\ }} $type]
set typenospace [string map {{ } -} $type]
if {[prepare_for_testing return-nodebug.exp "return-nodebug-$typenospace" "return-nodebug.c" \
[list "additional_flags=-DFORMAT=\"$format\" -DTYPE=$typeesc -DCAST=$cast"]] == 0} {
do_test $type
}
}