From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25065 invoked by alias); 18 Sep 2013 15:54:34 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 25055 invoked by uid 89); 18 Sep 2013 15:54:34 -0000 Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Sep 2013 15:54:34 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.0 required=5.0 tests=AWL,BAYES_00,KHOP_THREADED,RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r8IFsTUn015676 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 18 Sep 2013 11:54:30 -0400 Received: from [127.0.0.1] (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r8IFsRVP014164; Wed, 18 Sep 2013 11:54:28 -0400 Message-ID: <5239CCB3.605@redhat.com> Date: Wed, 18 Sep 2013 15:54:00 -0000 From: Pedro Alves User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130625 Thunderbird/17.0.7 MIME-Version: 1.0 To: Andrew Burgess CC: gdb-patches@sourceware.org, Mark Kettenis Subject: [PATCH+DOC] Print registers not saved in the frame as "", instead of "". References: <5200F55E.2050308@broadcom.com> <201308061318.r76DIMdd016369@glazunov.sibelius.xs4all.nl> <5200FECF.7030304@broadcom.com> <201308061541.r76FfYQN022875@glazunov.sibelius.xs4all.nl> <520142D9.4030304@redhat.com> <5208E3C8.7060107@broadcom.com> <5208E938.3080305@redhat.com> <201308122001.r7CK1862007934@glazunov.sibelius.xs4all.nl> <520E7255.7080206@redhat.com> <5211F25A.5070907@broadcom.com> <5228B15F.7060108@redhat.com> <5228B2D8.7060604@broadcom.com> <5237567C.8050406@redhat.com> <5239B2D8.4030403@broadcom.com> In-Reply-To: <5239B2D8.4030403@broadcom.com> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-SW-Source: 2013-09/txt/msg00606.txt.bz2 Eli, I've added NEWS and documentation changes to this patch. Are those OK? --------- Currently we print not saved registers as . That's confusing, because what this really means is that the register was not saved in the frame before calling another function. Before: (gdb) p/x $rax $1 = (gdb) info registers rax rax After: (gdb) p/x $rax $1 = (gdb) info registers rax rax However, if for some reason the debug info describes a variable as being in such a register, we still want to print . IOW, is reserved for inspecting registers at the machine level. The patch uses lval_register+optimized_out to encode the latter. frame_unwind_got_optimized creates not_lval optimized out registers, so by default, in most cases, we'll see . value_of_register is the function eval.c uses for evaluating OP_REGISTER (again, $pc, etc.), and related bits. It isn't used for anything else. This function makes sure to return lval_register values. The patch makes "info registers" and the MI equivalent use it too. I think it just makes a lot of sense, as this makes it so that when printing machine registers ($pc, etc.), we go through a central function. We're likely to need a different encoding at some point, if/when we support partially saved registers. Even then, I think value_of_register will still be the spot to tag the intention to print machine register values differently. value_from_register however may also return optimized out lval_register values, so at a couple places where we're computing a variable's location from a dwarf expression, we convert the resulting value away from lval_register to a regular optimized out value. Tested on x86_64 Fedora 17 gdb/ 2013-09-18 Pedro Alves * cp-valprint.c (cp_print_value_fields): Adjust calls to val_print_optimized_out. * jv-valprint.c (java_print_value_fields): Likewise. * p-valprint.c (pascal_object_print_value_fields): Likewise. * dwarf2loc.c (dwarf2_evaluate_loc_desc_full) : If the register was not saved, return a new optimized out value. * findvar.c (address_from_register): Likewise. * frame.c (put_frame_register): Tweak error string to say the register was not saved, rather than optimized out. * infcmd.c (default_print_one_register_info): Adjust call to val_print_optimized_out. Use value_of_register instead of get_frame_register_value. * mi/mi-main.c (output_register): Use value_of_register instead of get_frame_register_value. * valprint.c (valprint_check_validity): Likewise. (val_print_optimized_out): New value parameter. If the value is lval_register, print instead. (value_check_printable, val_print_scalar_formatted): Adjust calls to val_print_optimized_out. * valprint.h (val_print_optimized_out): New value parameter. * value.c (struct value) : Extend comment. (error_value_optimized_out): New function. (require_not_optimized_out): Use it. Use a different string for lval_register values. * value.h (error_value_optimized_out): New declaration. * NEWS: Mention . gdb/testsuite/ 2013-09-18 Pedro Alves * gdb.mi/mi-reg-undefined.exp (opt_out_pattern): Delete. (not_saved_pattern): New. Replace uses for the former with the latter. gdb/doc/ 2013-09-18 Pedro Alves * gdb.texinfo (Registers): Explain . --- gdb/NEWS | 9 +++++++++ gdb/cp-valprint.c | 4 ++-- gdb/doc/gdb.texinfo | 15 +++++++++++---- gdb/dwarf2loc.c | 16 +++++++++++++--- gdb/findvar.c | 9 +++++++++ gdb/frame.c | 2 +- gdb/infcmd.c | 4 ++-- gdb/jv-valprint.c | 4 ++-- gdb/mi/mi-main.c | 2 +- gdb/p-valprint.c | 4 ++-- gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp | 4 ++-- gdb/testsuite/gdb.mi/mi-reg-undefined.exp | 4 ++-- gdb/valprint.c | 13 ++++++++----- gdb/valprint.h | 3 ++- gdb/value.c | 22 +++++++++++++++++++--- gdb/value.h | 5 +++++ 16 files changed, 90 insertions(+), 30 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index af06a21..b06f90c 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -15,6 +15,15 @@ * The "catch syscall" command now works on arm*-linux* targets. +* GDB now shows "" when printing values of registers that + have not been saved in the frame: + + (gdb) p $rax $1 = + (gdb) info registers rax rax + + Before, the former would print "", and the latter + "*value not available*". + * Python scripting ** Frame filters and frame decorators have been added. diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c index e83d979..1d7147c 100644 --- a/gdb/cp-valprint.c +++ b/gdb/cp-valprint.c @@ -298,7 +298,7 @@ cp_print_value_fields (struct type *type, struct type *real_type, TYPE_FIELD_BITPOS (type, i), TYPE_FIELD_BITSIZE (type, i))) { - val_print_optimized_out (stream); + val_print_optimized_out (val, stream); } else { @@ -334,7 +334,7 @@ cp_print_value_fields (struct type *type, struct type *real_type, _(""), ex.message); else if (v == NULL) - val_print_optimized_out (stream); + val_print_optimized_out (NULL, stream); else cp_print_static_field (TYPE_FIELD_TYPE (type, i), v, stream, recurse + 1, diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 60d2877..80b6648 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -10031,10 +10031,17 @@ were exited and their saved registers restored. In order to see the true contents of hardware registers, you must select the innermost frame (with @samp{frame 0}). -However, @value{GDBN} must deduce where registers are saved, from the machine -code generated by your compiler. If some registers are not saved, or if -@value{GDBN} is unable to locate the saved registers, the selected stack -frame makes no difference. +In some ABIs, some registers may not be preserved, or saved, across +function calls. It may therefore not be possible for @value{GDBN} to +know the value a register had before the call (in other words, in a +outer frame). Values of registers that @value{GDBN} can tell were not +saved in their stack frames are shown as @w{@samp{}}. + +However, if debug or unwind information is missing, @value{GDBN} must +deduce where registers are saved, from the machine code generated by +your compiler. If some registers are not saved, or if @value{GDBN} is +unable to locate the saved registers, the selected stack frame makes +no difference. @node Floating Point Hardware @section Floating Point Hardware diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index 55d43f1..1313e17 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -2290,11 +2290,21 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, if (byte_offset != 0) error (_("cannot use offset on synthetic pointer to register")); do_cleanups (value_chain); - if (gdb_regnum != -1) - retval = value_from_register (type, gdb_regnum, frame); - else + if (gdb_regnum == -1) error (_("Unable to access DWARF register number %d"), dwarf_regnum); + retval = value_from_register (type, gdb_regnum, frame); + if (value_optimized_out (retval)) + { + /* This means the register has undefined value / was + not saved. As we're computing the location of some + variable etc. in the program, not a value for + inspecting a register ($pc, $sp, etc.), return a + generic optimized out value instead, so that we show + instead of . */ + do_cleanups (value_chain); + retval = allocate_optimized_out_value (type); + } } break; diff --git a/gdb/findvar.c b/gdb/findvar.c index 25242be..c3550b4 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -757,6 +757,15 @@ address_from_register (struct type *type, int regnum, struct frame_info *frame) value = value_from_register (type, regnum, frame); gdb_assert (value); + if (value_optimized_out (value)) + { + /* This function is used while computing a location expression. + Complain about the value being optimized out, rather than + letting value_as_address complain about some random register + the expression depends on not being saved. */ + error_value_optimized_out (); + } + result = value_as_address (value); release_value (value); value_free (value); diff --git a/gdb/frame.c b/gdb/frame.c index d52c26a..be1a1b1 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1140,7 +1140,7 @@ put_frame_register (struct frame_info *frame, int regnum, frame_register (frame, regnum, &optim, &unavail, &lval, &addr, &realnum, NULL); if (optim) - error (_("Attempt to assign to a value that was optimized out.")); + error (_("Attempt to assign to a register that was not saved.")); switch (lval) { case lval_memory: diff --git a/gdb/infcmd.c b/gdb/infcmd.c index e29dcde..46102a5 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -2035,7 +2035,7 @@ default_print_one_register_info (struct ui_file *file, } else if (value_optimized_out (val)) { - val_print_optimized_out (file); + val_print_optimized_out (val, file); fprintf_filtered (file, "\n"); return; } @@ -2142,7 +2142,7 @@ default_print_registers_info (struct gdbarch *gdbarch, default_print_one_register_info (file, gdbarch_register_name (gdbarch, i), - get_frame_register_value (frame, i)); + value_of_register (i, frame)); } } diff --git a/gdb/jv-valprint.c b/gdb/jv-valprint.c index 3b90e54..cb89a85 100644 --- a/gdb/jv-valprint.c +++ b/gdb/jv-valprint.c @@ -395,7 +395,7 @@ java_print_value_fields (struct type *type, const gdb_byte *valaddr, else if (!value_bits_valid (val, TYPE_FIELD_BITPOS (type, i), TYPE_FIELD_BITSIZE (type, i))) { - val_print_optimized_out (stream); + val_print_optimized_out (val, stream); } else { @@ -420,7 +420,7 @@ java_print_value_fields (struct type *type, const gdb_byte *valaddr, struct value *v = value_static_field (type, i); if (v == NULL) - val_print_optimized_out (stream); + val_print_optimized_out (NULL, stream); else { struct value_print_options opts; diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index e8c4744..5cde1ae 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -1161,7 +1161,7 @@ output_register (struct frame_info *frame, int regnum, int format, { struct gdbarch *gdbarch = get_frame_arch (frame); struct ui_out *uiout = current_uiout; - struct value *val = get_frame_register_value (frame, regnum); + struct value *val = value_of_register (regnum, frame); struct cleanup *tuple_cleanup; struct value_print_options opts; struct ui_file *stb; diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c index 05d4c6f..e6d4b91 100644 --- a/gdb/p-valprint.c +++ b/gdb/p-valprint.c @@ -629,7 +629,7 @@ pascal_object_print_value_fields (struct type *type, const gdb_byte *valaddr, else if (!value_bits_valid (val, TYPE_FIELD_BITPOS (type, i), TYPE_FIELD_BITSIZE (type, i))) { - val_print_optimized_out (stream); + val_print_optimized_out (val, stream); } else { @@ -657,7 +657,7 @@ pascal_object_print_value_fields (struct type *type, const gdb_byte *valaddr, v = value_field_bitfield (type, i, valaddr, offset, val); if (v == NULL) - val_print_optimized_out (stream); + val_print_optimized_out (NULL, stream); else pascal_object_print_static_field (v, stream, recurse + 1, options); diff --git a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp index 4686648..44bf8e9 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp +++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp @@ -45,8 +45,8 @@ for {set f 0} {$f < 3} {incr f} { set pattern_r8_r9_print "$hex" set pattern_r8_r9_info "$hex\\s+$decimal" } else { - set pattern_rax_rbx_rcx_print "" - set pattern_rax_rbx_rcx_info "" + set pattern_rax_rbx_rcx_print "" + set pattern_rax_rbx_rcx_info "" set pattern_r8_r9_print "$hex" set pattern_r8_r9_info "$hex\\s+$decimal" } diff --git a/gdb/testsuite/gdb.mi/mi-reg-undefined.exp b/gdb/testsuite/gdb.mi/mi-reg-undefined.exp index 8bcbb21..cb3a716 100644 --- a/gdb/testsuite/gdb.mi/mi-reg-undefined.exp +++ b/gdb/testsuite/gdb.mi/mi-reg-undefined.exp @@ -52,13 +52,13 @@ mi_gdb_test "111-stack-list-frames" \ "111\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"stop_frame\",.*\},frame=\{level=\"1\",addr=\"$hex\",func=\"first_frame\",.*\},frame=\{level=\"2\",addr=\"$hex\",func=\"main\",.*\}\\\]" \ "stack frame listing" -set opt_out_pattern "" +set not_saved_pattern "" for {set f 0} {$f < 3} {incr f} { if {${f} == 0} { set pattern_0_1_2 ${hex} } else { - set pattern_0_1_2 ${opt_out_pattern} + set pattern_0_1_2 ${not_saved_pattern} } mi_gdb_test "22${f}-data-list-register-values --thread 1 --frame ${f} x 0 1 2 8 9" \ diff --git a/gdb/valprint.c b/gdb/valprint.c index 0f6d65e..61492cc 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -314,7 +314,7 @@ valprint_check_validity (struct ui_file *stream, if (!value_bits_valid (val, TARGET_CHAR_BIT * embedded_offset, TARGET_CHAR_BIT * TYPE_LENGTH (type))) { - val_print_optimized_out (stream); + val_print_optimized_out (val, stream); return 0; } @@ -336,9 +336,12 @@ valprint_check_validity (struct ui_file *stream, } void -val_print_optimized_out (struct ui_file *stream) +val_print_optimized_out (const struct value *val, struct ui_file *stream) { - fprintf_filtered (stream, _("")); + if (val != NULL && value_lval_const (val) == lval_register) + fprintf_filtered (stream, _("")); + else + fprintf_filtered (stream, _("")); } void @@ -805,7 +808,7 @@ value_check_printable (struct value *val, struct ui_file *stream, if (options->summary && !val_print_scalar_type_p (value_type (val))) fprintf_filtered (stream, "..."); else - val_print_optimized_out (stream); + val_print_optimized_out (val, stream); return 0; } @@ -966,7 +969,7 @@ val_print_scalar_formatted (struct type *type, printed, because all bits contribute to its representation. */ if (!value_bits_valid (val, TARGET_CHAR_BIT * embedded_offset, TARGET_CHAR_BIT * TYPE_LENGTH (type))) - val_print_optimized_out (stream); + val_print_optimized_out (val, stream); else if (!value_bytes_available (val, embedded_offset, TYPE_LENGTH (type))) val_print_unavailable (stream); else diff --git a/gdb/valprint.h b/gdb/valprint.h index e7073b6..1d86ed7 100644 --- a/gdb/valprint.h +++ b/gdb/valprint.h @@ -160,7 +160,8 @@ extern int read_string (CORE_ADDR addr, int len, int width, enum bfd_endian byte_order, gdb_byte **buffer, int *bytes_read); -extern void val_print_optimized_out (struct ui_file *stream); +extern void val_print_optimized_out (const struct value *val, + struct ui_file *stream); extern void val_print_unavailable (struct ui_file *stream); diff --git a/gdb/value.c b/gdb/value.c index bc1239d..d96d285 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -197,8 +197,13 @@ struct value reset, be sure to consider this use as well! */ unsigned int lazy : 1; - /* If nonzero, this is the value of a variable which does not - actually exist in the program. */ + /* If nonzero, this is the value of a variable that does not + actually exist in the program. If nonzero, and LVAL is + lval_register, this is a register ($pc, $sp, etc., never a + program variable) that has not been saved in the frame. All + optimized-out values are treated pretty much the same, except + registers have a different string representation and related + error strings. */ unsigned int optimized_out : 1; /* If value is a variable, is it initialized or not. */ @@ -902,11 +907,22 @@ value_actual_type (struct value *value, int resolve_simple_types, return result; } +void +error_value_optimized_out (void) +{ + error (_("value has been optimized out")); +} + static void require_not_optimized_out (const struct value *value) { if (value->optimized_out) - error (_("value has been optimized out")); + { + if (value->lval == lval_register) + error (_("register has not been saved in frame")); + else + error_value_optimized_out (); + } } static void diff --git a/gdb/value.h b/gdb/value.h index 98dbadf..db964e3 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -273,6 +273,11 @@ extern void set_value_lazy (struct value *value, int val); extern int value_stack (struct value *); extern void set_value_stack (struct value *value, int val); +/* Throw an error complaining that the value has been optimized + out. */ + +extern void error_value_optimized_out (void); + /* value_contents() and value_contents_raw() both return the address of the gdb buffer used to hold a copy of the contents of the lval. value_contents() is used when the contents of the buffer are needed -- 1.7.11.7