From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12380 invoked by alias); 19 Sep 2013 19:15:29 -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 12358 invoked by uid 89); 19 Sep 2013 19:15:28 -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; Thu, 19 Sep 2013 19:15:28 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.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-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r8JJFNKv027001 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 19 Sep 2013 15:15:23 -0400 Received: from [127.0.0.1] (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r8JJFLXH021934; Thu, 19 Sep 2013 15:15:21 -0400 Message-ID: <523B4D48.3050206@redhat.com> Date: Thu, 19 Sep 2013 19:15: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: gdb-patches@sourceware.org CC: Eli Zaretskii , Mark Kettenis , aburgess@broadcom.com Subject: [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [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> <5239CCB3.605@redhat.com> <83zjram6sw.fsf@gnu.org> <201309182047.r8IKlOGA010471@glazunov.sibelius.xs4all.nl> <83fvt1mems.fsf@gnu.org> <523B2D39.8060303@redhat.com> In-Reply-To: <523B2D39.8060303@redhat.com> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-SW-Source: 2013-09/txt/msg00697.txt.bz2 On 09/19/2013 05:58 PM, Pedro Alves wrote: > Now, GDB itself could just assume that call-clobbered registers > are always in frames other than the innermost, but > that'll be not very user friendly, I think. > > Perhaps... we should completely toss out this patch, and go > the other way around. When printing registers of an outer > frame, ignore DW_CFA_undefined, and read the registers > from the inner frame anyway... IOW, define the values of > call-clobbered registers in outer frames as "the values the > registers would have if the inner frame returned _now_". > Mark, what do you think? > (I didn't try implementing that, but I think that'll just > mean ignoring the optimized_out flag when dumping registers > (but not when printing variables marked as living in "optimized > out" registers). > Like this... -------------- Subject: [PATCH] Always print call-clobbered registers in outer frames. With older GCCs, when some variable lived on a call-clobbered register just before a call, GCC would mark such register as undefined across the function call, with DW_CFA_undefined. This is interpreted by the debugger as meaning the variable is optimized out at that point. That is, if the user does "up", and tries to print the variable. Newer GCCs stopped doing that. They now just don't emit a location for the variable, resulting in GDB printing "" all the same. (See .) The difference is that with binaries produced by those older GCCs, GDB will also print the registers themselves (info registers / p $reg) as "". This is confusing. See with the gdb.dwarf/dw2-op-out-param.exp test: Breakpoint 2, 0x000000000040058f in breakpt () (gdb) up #1 0x00000000004005a2 in int_param_single_reg_loc (operand0=, operand1=-2401054115373400575, operand2=) (gdb) info registers rax 0x323d7b35b0 215779849648 rbx 0xdeadbe00deadbe01 -2401054115373400575 rcx rdx 0xdeadbe04deadbe05 -2401054098193531387 rsi rdi rbp 0x0 0x0 rsp 0x7fffffffda20 0x7fffffffda20 r8 0x323d7b1f40 215779843904 r9 0x323d00f310 215771837200 r10 0x7fffffffd890 140737488345232 r11 0x323d421640 215776106048 r12 0x400430 4195376 r13 0x7fffffffdb10 140737488345872 r14 0x0 0 r15 0x0 0 rip 0x4005a2 0x4005a2 eflags 0x202 [ IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 This patch makes GDB always follow this rule (which is what the heuristic unwinders usually do by default): The values of call-clobbered registers in the outer frame, if not saved by the caller, are defined as being the values the registers would have if the inner frame was to return immediately. The documentation is updated to more clearly explain this. IOW, ignore DW_CFA_undefined _when printing frame registers_, but not when printing variables. This translates to, if value of a frame register, comes out as optimized out (that's what "not saved" lval_register values end up as), fetch it from the next frame. After the patch, we get: #0 0x000000000040058f in breakpt () (gdb) info registers rax 0x323d7b35b0 215779849648 rbx 0xdeadbe00deadbe01 -2401054115373400575 rcx 0xdeadbe02deadbe03 -2401054106783465981 rdx 0xdeadbe04deadbe05 -2401054098193531387 rsi 0xdeadbe06deadbe07 -2401054089603596793 rdi 0xdeadbe08deadbe09 -2401054081013662199 rbp 0x0 0x0 rsp 0x7fffffffda18 0x7fffffffda18 r8 0x323d7b1f40 215779843904 r9 0x323d00f310 215771837200 r10 0x7fffffffd890 140737488345232 r11 0x323d421640 215776106048 r12 0x400430 4195376 r13 0x7fffffffdb10 140737488345872 r14 0x0 0 r15 0x0 0 rip 0x40058f 0x40058f eflags 0x202 [ IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) up #1 0x00000000004005a2 in int_param_single_reg_loc (operand0=, operand1=-2401054115373400575, operand2=) (gdb) info registers rax 0x323d7b35b0 215779849648 rbx 0xdeadbe00deadbe01 -2401054115373400575 rcx 0xdeadbe02deadbe03 -2401054106783465981 rdx 0xdeadbe04deadbe05 -2401054098193531387 rsi 0xdeadbe06deadbe07 -2401054089603596793 rdi 0xdeadbe08deadbe09 -2401054081013662199 rbp 0x0 0x0 rsp 0x7fffffffda20 0x7fffffffda20 r8 0x323d7b1f40 215779843904 r9 0x323d00f310 215771837200 r10 0x7fffffffd890 140737488345232 r11 0x323d421640 215776106048 r12 0x400430 4195376 r13 0x7fffffffdb10 140737488345872 r14 0x0 0 r15 0x0 0 rip 0x4005a2 0x4005a2 eflags 0x202 [ IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) Which is what you'd get with a newer GCC. And, it's exactly what you get today if your force a return from frame #1, even with such an old binary, and _unpatched_ GDB: (gdb) return Make breakpt return now? (y or n) y #0 0x00000000004005a2 in int_param_single_reg_loc (operand0=-2401054106783465981, operand1=-2401054115373400575, operand2=-2401054089603596793) (gdb) info registers rax 0x323d7b35b0 215779849648 rbx 0xdeadbe00deadbe01 -2401054115373400575 rcx 0xdeadbe02deadbe03 -2401054106783465981 rdx 0xdeadbe04deadbe05 -2401054098193531387 rsi 0xdeadbe06deadbe07 -2401054089603596793 rdi 0xdeadbe08deadbe09 -2401054081013662199 rbp 0x0 0x0 rsp 0x7fffffffda20 0x7fffffffda20 r8 0x323d7b1f40 215779843904 r9 0x323d00f310 215771837200 r10 0x7fffffffd890 140737488345232 r11 0x323d421640 215776106048 r12 0x400430 4195376 r13 0x7fffffffdb10 140737488345872 r14 0x0 0 r15 0x0 0 rip 0x4005a2 0x4005a2 eflags 0x202 [ IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) This is rule is applied in value_of_register. This is the function eval.c uses for evaluating OP_REGISTER (again, $reg, $pc, etc.), and related bits. It isn't used for anything else. 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. Note how gdb.mi/mi-reg-undefined.exp and gdb.dwarf2/dw2-reg-undefined.exp tests needed adjustment, but not gdb.dwarf2/dw2-op-out-param.exp, as that prints an optimized out variable, not register. Tested on x86_64 Fedora 17 gdb/ 2013-09-18 Pedro Alves * findvar.c (value_of_register): Rename to ... (value_of_register_helper): ... this. (value_of_register): Reimplement. * infcmd.c (default_print_one_register_info): 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. gdb/testsuite/ 2013-09-18 Pedro Alves * gdb.dwarf2/dw2-reg-undefined.exp: Expect hex numbers instead of "" for all frames. * gdb.mi/mi-reg-undefined.exp (opt_out_pattern): Delete. (top level): Expect hex numbers instead of "" for all frames. gdb/doc/ 2013-09-18 Pedro Alves * gdb.texinfo (Registers): Expand explanation of not-saved call-clobbered registers in frames other than the innermost. --- gdb/doc/gdb.texinfo | 20 ++++++++++++---- gdb/findvar.c | 32 ++++++++++++++++++++++---- gdb/infcmd.c | 2 +- gdb/mi/mi-main.c | 2 +- gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp | 17 +++++--------- gdb/testsuite/gdb.mi/mi-reg-undefined.exp | 14 ++++------- 6 files changed, 55 insertions(+), 32 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 60d2877..23227af 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -10031,10 +10031,22 @@ 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. +Most ABIs reserve some registers as ``scratch'' registers that don't +need to be saved by the caller (a.k.a. caller-saved or call-clobbered +registers). It may therefore not be possible for @value{GDBN} to know +the value a register had before the call (in other words, in the outer +frame), if the register value has since been changed by the callee. +@value{GDBN} tries to deduce where registers are saved, from the debug +info, unwind info, or the machine code generated by your compiler. If +some register is not saved, or if @value{GDBN} is unable to locate the +saved register, @value{GDBN} will assume the register in the outer +frame had the same location and value it has in the inner frame. In +other words, the values of call-clobbered registers in the outer +frame, if not saved by the caller, are defined as being the values the +registers would have if the inner frame was to return immediately. +This is usually harmless, but note however that if you change a +register in the outer frame, you may also be affecting the inner +frame. @node Floating Point Hardware @section Floating Point Hardware diff --git a/gdb/findvar.c b/gdb/findvar.c index 25242be..5cbbc83 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -254,12 +254,11 @@ store_typed_address (gdb_byte *buf, struct type *type, CORE_ADDR addr) -/* Return a `value' with the contents of (virtual or cooked) register - REGNUM as found in the specified FRAME. The register's type is - determined by register_type(). */ +/* Helper for value_of_register; see value_of_register for description + of parameters/return. */ -struct value * -value_of_register (int regnum, struct frame_info *frame) +static struct value * +value_of_register_helper (int regnum, struct frame_info *frame) { struct gdbarch *gdbarch = get_frame_arch (frame); struct value *reg_val; @@ -277,6 +276,29 @@ value_of_register (int regnum, struct frame_info *frame) /* Return a `value' with the contents of (virtual or cooked) register REGNUM as found in the specified FRAME. The register's type is + determined by register_type(). */ + +struct value * +value_of_register (int regnum, struct frame_info *frame) +{ + while (1) + { + struct value *reg_val = value_of_register_helper (regnum, frame); + + if (!value_optimized_out (reg_val)) + return reg_val; + /* If a register has been marked as "optimized out"/"not saved" + in the unwind/debug info for this frame, fetch it from the + next/inner frame. The innermost frame fetches registers from + the regcache, so should never return an optimized out + register. */ + gdb_assert (frame_relative_level (frame) > 0); + frame = get_next_frame (frame); + } +} + +/* Return a `value' with the contents of (virtual or cooked) register + REGNUM as found in the specified FRAME. The register's type is determined by register_type(). The value is not fetched. */ struct value * diff --git a/gdb/infcmd.c b/gdb/infcmd.c index e29dcde..e9cd255 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -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/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/testsuite/gdb.dwarf2/dw2-reg-undefined.exp b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp index 4686648..58b50d5 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp +++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp @@ -39,17 +39,12 @@ gdb_test "bt" "#0 (0x\[0-9a-f\]+ in )?stop_frame \[^\r\n\]*\r\n#1 \[^\r\n\]*fi "backtrace from stop_frame" for {set f 0} {$f < 3} {incr f} { - if {${f} == 0} { - set pattern_rax_rbx_rcx_print "$hex" - set pattern_rax_rbx_rcx_info "$hex\\s+$decimal" - 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_r8_r9_print "$hex" - set pattern_r8_r9_info "$hex\\s+$decimal" - } + # Even though registers 0->6 are marked as being undefined in + # frames > 0, GDB should retrieve their values from inner frames. + set pattern_rax_rbx_rcx_print "$hex" + set pattern_rax_rbx_rcx_info "$hex\\s+$decimal" + set pattern_r8_r9_print "$hex" + set pattern_r8_r9_info "$hex\\s+$decimal" # Select frame. gdb_test "frame ${f}" "#${f}.*" "Switch to frame ${f}" diff --git a/gdb/testsuite/gdb.mi/mi-reg-undefined.exp b/gdb/testsuite/gdb.mi/mi-reg-undefined.exp index 8bcbb21..d0f275c 100644 --- a/gdb/testsuite/gdb.mi/mi-reg-undefined.exp +++ b/gdb/testsuite/gdb.mi/mi-reg-undefined.exp @@ -52,20 +52,14 @@ 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 "" - 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} - } - + # Even though registers 0->6 are marked as being undefined in + # frames > 0, GDB should retrieve their values from inner frames. mi_gdb_test "22${f}-data-list-register-values --thread 1 --frame ${f} x 0 1 2 8 9" \ - "22${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${pattern_0_1_2}\"\},\{number=\"1\",value=\"${pattern_0_1_2}\"\},\{number=\"2\",value=\"${pattern_0_1_2}\"\},\{number=\"8\",value=\"$hex\"\},\{number=\"9\",value=\"$hex\"\}\\\]" \ + "22${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${hex}\"\},\{number=\"1\",value=\"${hex}\"\},\{number=\"2\",value=\"${hex}\"\},\{number=\"8\",value=\"$hex\"\},\{number=\"9\",value=\"$hex\"\}\\\]" \ "register values, format x, frame ${f}" mi_gdb_test "33${f}-data-list-register-values --thread 1 --frame ${f} r 0 1 2 8 9" \ - "33${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${pattern_0_1_2}\"\},\{number=\"1\",value=\"${pattern_0_1_2}\"\},\{number=\"2\",value=\"${pattern_0_1_2}\"\},\{number=\"8\",value=\"$hex\"\},\{number=\"9\",value=\"$hex\"\}\\\]" \ + "33${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${hex}\"\},\{number=\"1\",value=\"${hex}\"\},\{number=\"2\",value=\"${hex}\"\},\{number=\"8\",value=\"$hex\"\},\{number=\"9\",value=\"$hex\"\}\\\]" \ "register values, format r, frame ${f}" } -- 1.7.11.7