* [PATCH] Consistent display of "<optimized out>" @ 2013-08-06 13:09 Andrew Burgess 2013-08-06 13:18 ` Mark Kettenis 0 siblings, 1 reply; 43+ messages in thread From: Andrew Burgess @ 2013-08-06 13:09 UTC (permalink / raw) To: gdb-patches In some cases we report optimized out registers as "*value not available*" rather than "<optimized out>", the patch below makes this more consistent in the case I've spotted. Here's an example: (gdb) up #1 0x0000000000400800 in first_frame () at dw2-reg-undefined.c:27 27 in dw2-reg-undefined.c (gdb) info registers rax rax *value not available* (gdb) p/x $rax $1 = <optimized out> After the patch the behaviour is now: (gdb) up #1 0x0000000000400800 in first_frame () at dw2-reg-undefined.c:27 27 in dw2-reg-undefined.c (gdb) info registers rax rax <optimized out> (gdb) p/x $rax $1 = <optimized out> The behaviour for values that are unavailable is currently unchanged, though I have a follow up patch for this too. OK to apply? Thanks, Andrew gdb/ChangeLog 2013-08-06 Andrew Burgess <aburgess@broadcom.com> * infcmd.c (default_print_one_register_info): Add detection of optimized out values. (default_print_registers_info): Switch to using get_frame_register_value. gdb/testsuite/ChangeLog 2013-08-06 Andrew Burgess <aburgess@broadcom.com> * gdb.dwarf2/dw2-reg-undefined.exp: Change pattern for info register to "<optimized out>", and also print the registers. diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 154cde2..f6a5290 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -2033,6 +2033,12 @@ default_print_one_register_info (struct ui_file *file, fprintf_filtered (file, "*value not available*\n"); return; } + else if (value_optimized_out (val)) + { + val_print_optimized_out (file); + fprintf_filtered (file, "\n"); + return; + } /* If virtual format is floating, print it that way, and in raw hex. */ @@ -2107,9 +2113,6 @@ default_print_registers_info (struct gdbarch *gdbarch, for (i = 0; i < numregs; i++) { - struct type *regtype; - struct value *val; - /* Decide between printing all regs, non-float / vector regs, or specific reg. */ if (regnum == -1) @@ -2137,16 +2140,9 @@ default_print_registers_info (struct gdbarch *gdbarch, || *(gdbarch_register_name (gdbarch, i)) == '\0') continue; - regtype = register_type (gdbarch, i); - val = allocate_value (regtype); - - /* Get the data in raw format. */ - if (! deprecated_frame_register_read (frame, i, value_contents_raw (val))) - mark_value_bytes_unavailable (val, 0, TYPE_LENGTH (value_type (val))); - default_print_one_register_info (file, gdbarch_register_name (gdbarch, i), - val); + get_frame_register_value (frame, i)); } } diff --git a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp index 7b7b4d1..4686648 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp +++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp @@ -38,22 +38,34 @@ if ![runto stop_frame] { gdb_test "bt" "#0 (0x\[0-9a-f\]+ in )?stop_frame \[^\r\n\]*\r\n#1 \[^\r\n\]*first_frame \[^\r\n\]*\r\n#2 \[^\r\n\]*main\[^\r\n\]*" \ "backtrace from stop_frame" -set value_pattern "0x\[0-9a-f\]+\\s+\[0-9\]+" -set opt_out_pattern "\\*value not available\\*" - for {set f 0} {$f < 3} {incr f} { if {${f} == 0} { - set pattern_rax_rbx_rcx ${value_pattern} - set pattern_r8_r9 ${value_pattern} + 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 ${opt_out_pattern} - set pattern_r8_r9 ${value_pattern} + set pattern_rax_rbx_rcx_print "<optimized out>" + set pattern_rax_rbx_rcx_info "<optimized out>" + 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}" + gdb_test "p/x \$rax" ".*$pattern_rax_rbx_rcx_print.*" \ + "print \$rax in frame ${f}" + gdb_test "p/x \$rbx" "$pattern_rax_rbx_rcx_print" \ + "print \$rbx in frame ${f}" + gdb_test "p/x \$rcx" "$pattern_rax_rbx_rcx_print" \ + "print \$rcx in frame ${f}" + + gdb_test "p/x \$r8" "$pattern_r8_r9_print" "print \$r8 in frame ${f}" + gdb_test "p/x \$r9" "$pattern_r8_r9_print" "print \$r9 in frame ${f}" + + # Display register values. - gdb_test "info registers rax rbx rcx r8 r9" "rax\\s+${pattern_rax_rbx_rcx}\\s*\r\nrbx\\s+${pattern_rax_rbx_rcx}\\s*\r\nrcx\\s+${pattern_rax_rbx_rcx}\\s*\r\nr8\\s+${pattern_r8_r9}\\s*\r\nr9\\s+${pattern_r8_r9}\\s*" \ + gdb_test "info registers rax rbx rcx r8 r9" "rax\\s+${pattern_rax_rbx_rcx_info}\\s*\r\nrbx\\s+${pattern_rax_rbx_rcx_info}\\s*\r\nrcx\\s+${pattern_rax_rbx_rcx_info}\\s*\r\nr8\\s+${pattern_r8_r9_info}\\s*\r\nr9\\s+${pattern_r8_r9_info}\\s*" \ "Check values of rax, rbx, rcx, r8, r9 in frame ${f}" } ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-06 13:09 [PATCH] Consistent display of "<optimized out>" Andrew Burgess @ 2013-08-06 13:18 ` Mark Kettenis 2013-08-06 13:49 ` Andrew Burgess 0 siblings, 1 reply; 43+ messages in thread From: Mark Kettenis @ 2013-08-06 13:18 UTC (permalink / raw) To: aburgess; +Cc: gdb-patches > Date: Tue, 6 Aug 2013 14:08:46 +0100 > From: "Andrew Burgess" <aburgess@broadcom.com> > > In some cases we report optimized out registers as "*value not available*" > rather than "<optimized out>", the patch below makes this more consistent > in the case I've spotted. > > Here's an example: > > (gdb) up > #1 0x0000000000400800 in first_frame () at dw2-reg-undefined.c:27 > 27 in dw2-reg-undefined.c > (gdb) info registers rax > rax *value not available* > (gdb) p/x $rax > $1 = <optimized out> > > After the patch the behaviour is now: > > (gdb) up > #1 0x0000000000400800 in first_frame () at dw2-reg-undefined.c:27 > 27 in dw2-reg-undefined.c > (gdb) info registers rax > rax <optimized out> > (gdb) p/x $rax > $1 = <optimized out> > > The behaviour for values that are unavailable is currently unchanged, > though I have a follow up patch for this too. > > OK to apply? I'd say no. There is a difference between "unavailable" and "optimized out". Registers will be unavailable even if you compile without any optimization, because the ABI specifies that their contents are not saved across function calls. So "optimized out" makes very little sense for registers. ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-06 13:18 ` Mark Kettenis @ 2013-08-06 13:49 ` Andrew Burgess 2013-08-06 15:41 ` Mark Kettenis 0 siblings, 1 reply; 43+ messages in thread From: Andrew Burgess @ 2013-08-06 13:49 UTC (permalink / raw) To: Mark Kettenis; +Cc: gdb-patches On 06/08/2013 2:18 PM, Mark Kettenis wrote: >> Date: Tue, 6 Aug 2013 14:08:46 +0100 >> From: "Andrew Burgess" <aburgess@broadcom.com> >> >> In some cases we report optimized out registers as "*value not available*" >> rather than "<optimized out>", the patch below makes this more consistent >> in the case I've spotted. >> >> Here's an example: >> >> (gdb) up >> #1 0x0000000000400800 in first_frame () at dw2-reg-undefined.c:27 >> 27 in dw2-reg-undefined.c >> (gdb) info registers rax >> rax *value not available* >> (gdb) p/x $rax >> $1 = <optimized out> >> >> After the patch the behaviour is now: >> >> (gdb) up >> #1 0x0000000000400800 in first_frame () at dw2-reg-undefined.c:27 >> 27 in dw2-reg-undefined.c >> (gdb) info registers rax >> rax <optimized out> >> (gdb) p/x $rax >> $1 = <optimized out> >> >> The behaviour for values that are unavailable is currently unchanged, >> though I have a follow up patch for this too. >> >> OK to apply? > > I'd say no. There is a difference between "unavailable" and > "optimized out". Registers will be unavailable even if you compile > without any optimization, because the ABI specifies that their > contents are not saved across function calls. So "optimized out" > makes very little sense for registers. I disagree for 3 reasons. 1. This patch is about consistency, having "print <reg>" report one thing and "info register <reg>" report another seems like a bad thing to me. 2. We previously fetched the register by calling deprecated_frame_register_read, this eventually gets a value object by called frame_unwind_register_value, we then extract the unavailable and optimized-out attributes from the value object and for no good reason I can see create a new value object and mark it as unavailable. My patch side-steps this middle ground of calling deprecated_frame_register_read, and instead works with the value we get back by reading the register, this is already marked optimized out. My interpretation of your concern would be that you don't think it /should/ be marked as optimized out, I believe however, that this is not really an issue for this patch, if this changes later then we'd revert back to printing unavailable rather than optimized out, my patch doesn't prevent that, it just prints the real state of the value object. 3. My understanding was that values lost due to the ABI of a call site were recorded as optimized out. For evidence I would present dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. For these reasons I believe my patch should still be considered, what do you think? Thanks, Andrew ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-06 13:49 ` Andrew Burgess @ 2013-08-06 15:41 ` Mark Kettenis 2013-08-06 16:02 ` Andrew Burgess 2013-08-06 18:39 ` Pedro Alves 0 siblings, 2 replies; 43+ messages in thread From: Mark Kettenis @ 2013-08-06 15:41 UTC (permalink / raw) To: aburgess; +Cc: gdb-patches > Date: Tue, 6 Aug 2013 14:49:03 +0100 > From: "Andrew Burgess" <aburgess@broadcom.com> > > On 06/08/2013 2:18 PM, Mark Kettenis wrote: > >> Date: Tue, 6 Aug 2013 14:08:46 +0100 > >> From: "Andrew Burgess" <aburgess@broadcom.com> > >> > >> In some cases we report optimized out registers as "*value not available*" > >> rather than "<optimized out>", the patch below makes this more consistent > >> in the case I've spotted. > >> > >> Here's an example: > >> > >> (gdb) up > >> #1 0x0000000000400800 in first_frame () at dw2-reg-undefined.c:27 > >> 27 in dw2-reg-undefined.c > >> (gdb) info registers rax > >> rax *value not available* > >> (gdb) p/x $rax > >> $1 = <optimized out> > >> > >> After the patch the behaviour is now: > >> > >> (gdb) up > >> #1 0x0000000000400800 in first_frame () at dw2-reg-undefined.c:27 > >> 27 in dw2-reg-undefined.c > >> (gdb) info registers rax > >> rax <optimized out> > >> (gdb) p/x $rax > >> $1 = <optimized out> > >> > >> The behaviour for values that are unavailable is currently unchanged, > >> though I have a follow up patch for this too. > >> > >> OK to apply? > > > > I'd say no. There is a difference between "unavailable" and > > "optimized out". Registers will be unavailable even if you compile > > without any optimization, because the ABI specifies that their > > contents are not saved across function calls. So "optimized out" > > makes very little sense for registers. > > I disagree for 3 reasons. > > 1. This patch is about consistency, having "print <reg>" report one > thing and "info register <reg>" report another seems like a bad thing to > me. > > 2. We previously fetched the register by calling > deprecated_frame_register_read, this eventually gets a value object by > called frame_unwind_register_value, we then extract the unavailable and > optimized-out attributes from the value object and for no good reason I > can see create a new value object and mark it as unavailable. My patch > side-steps this middle ground of calling > deprecated_frame_register_read, and instead works with the value we get > back by reading the register, this is already marked optimized out. My > interpretation of your concern would be that you don't think it /should/ > be marked as optimized out, I believe however, that this is not really > an issue for this patch, if this changes later then we'd revert back to > printing unavailable rather than optimized out, my patch doesn't prevent > that, it just prints the real state of the value object. > > 3. My understanding was that values lost due to the ABI of a call site > were recorded as optimized out. For evidence I would present > dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. > > For these reasons I believe my patch should still be considered, what do > you think? I think that registers are either available or unavailble. A register being unavailble implies that a variable that is supposed to live in such a register may have been optimized out. Whether GDB's pseudo variables that respresent registers are considered unavailable or optimized out in that case is arguable. ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-06 15:41 ` Mark Kettenis @ 2013-08-06 16:02 ` Andrew Burgess 2013-08-06 18:39 ` Pedro Alves 1 sibling, 0 replies; 43+ messages in thread From: Andrew Burgess @ 2013-08-06 16:02 UTC (permalink / raw) To: Mark Kettenis; +Cc: gdb-patches On 06/08/2013 4:41 PM, Mark Kettenis wrote: >> Date: Tue, 6 Aug 2013 14:49:03 +0100 >> From: "Andrew Burgess" <aburgess@broadcom.com> >> >> On 06/08/2013 2:18 PM, Mark Kettenis wrote: >>>> Date: Tue, 6 Aug 2013 14:08:46 +0100 >>>> From: "Andrew Burgess" <aburgess@broadcom.com> >>>> >>>> In some cases we report optimized out registers as "*value not available*" >>>> rather than "<optimized out>", the patch below makes this more consistent >>>> in the case I've spotted. >>>> >>>> Here's an example: >>>> >>>> (gdb) up >>>> #1 0x0000000000400800 in first_frame () at dw2-reg-undefined.c:27 >>>> 27 in dw2-reg-undefined.c >>>> (gdb) info registers rax >>>> rax *value not available* >>>> (gdb) p/x $rax >>>> $1 = <optimized out> >>>> >>>> After the patch the behaviour is now: >>>> >>>> (gdb) up >>>> #1 0x0000000000400800 in first_frame () at dw2-reg-undefined.c:27 >>>> 27 in dw2-reg-undefined.c >>>> (gdb) info registers rax >>>> rax <optimized out> >>>> (gdb) p/x $rax >>>> $1 = <optimized out> >>>> >>>> The behaviour for values that are unavailable is currently unchanged, >>>> though I have a follow up patch for this too. >>>> >>>> OK to apply? >>> >>> I'd say no. There is a difference between "unavailable" and >>> "optimized out". Registers will be unavailable even if you compile >>> without any optimization, because the ABI specifies that their >>> contents are not saved across function calls. So "optimized out" >>> makes very little sense for registers. >> >> I disagree for 3 reasons. >> >> 1. This patch is about consistency, having "print <reg>" report one >> thing and "info register <reg>" report another seems like a bad thing to >> me. >> >> 2. We previously fetched the register by calling >> deprecated_frame_register_read, this eventually gets a value object by >> called frame_unwind_register_value, we then extract the unavailable and >> optimized-out attributes from the value object and for no good reason I >> can see create a new value object and mark it as unavailable. My patch >> side-steps this middle ground of calling >> deprecated_frame_register_read, and instead works with the value we get >> back by reading the register, this is already marked optimized out. My >> interpretation of your concern would be that you don't think it /should/ >> be marked as optimized out, I believe however, that this is not really >> an issue for this patch, if this changes later then we'd revert back to >> printing unavailable rather than optimized out, my patch doesn't prevent >> that, it just prints the real state of the value object. >> >> 3. My understanding was that values lost due to the ABI of a call site >> were recorded as optimized out. For evidence I would present >> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >> >> For these reasons I believe my patch should still be considered, what do >> you think? > > I think that registers are either available or unavailble. If I understand correctly you're talking here not about how gdb represents registers, but registers in a "real" sense. I'm not sure I agree with your sentence, I guess it depends on your exact definition of "unavailable", clearly optimized out could be a sub-set of unavailable. > A register > being unavailble implies that a variable that is supposed to live in > such a register may have been optimized out. I agree with this. > Whether GDB's pseudo > variables that respresent registers are considered unavailable or > optimized out in that case is arguable. I don't really understand what "that case" is referring too, nor what "pseudo variables" are. We can consider different cases, for example, a request for a program variable that has been stored in a register that is not preserved over an ABI call, this will create a gdb value object with a location of the specified register, and attempt to fetch the register will then mark the value as (in the example I've already cited) optimized out. Similarly, a direct request to gdb for the specified register would result in a value that is marked optimiszed out. I've only given as an example the DWARF unwinder, I guess other unwinders could handle registers lost over a call differently and mark them as unavailable, however, I'm not aware of any that do this, though I've not looked that hard, can you give an example? Also I thought, though I could be wrong on this, that the gdb value "unavailable" was currently only used for value content that had not been collected through tracing, though I believe there are a few places, such as the one I'm patching here, where the value "unavailable" state is being set incorrectly. Do you have any examples of how the gdb value "unavailable" state is intentionally used for something other than non-collected trace content? I think you're suggesting that the use of optimized out as a way to mark registers lost due to the call ABI is wrong, and though I can see how having a separate state for this, or maybe using unavailable, might be a good thing it's certainly not what this patch is about, nor do I think this patch is a step away from that, if that is indeed a goal for gdb, even after my patch, if a value is marked unavailable rather than optimized out, it will be displayed as unavailable. Thanks, Andrew ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-06 15:41 ` Mark Kettenis 2013-08-06 16:02 ` Andrew Burgess @ 2013-08-06 18:39 ` Pedro Alves 2013-08-12 13:32 ` Andrew Burgess 1 sibling, 1 reply; 43+ messages in thread From: Pedro Alves @ 2013-08-06 18:39 UTC (permalink / raw) To: Mark Kettenis; +Cc: aburgess, gdb-patches On 08/06/2013 04:41 PM, Mark Kettenis wrote: >> Date: Tue, 6 Aug 2013 14:49:03 +0100 >> From: "Andrew Burgess" <aburgess@broadcom.com> >> 3. My understanding was that values lost due to the ABI of a call site >> were recorded as optimized out. For evidence I would present >> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >> >> For these reasons I believe my patch should still be considered, what do >> you think? > > I think that registers are either available or unavailble. A register > being unavailble implies that a variable that is supposed to live in > such a register may have been optimized out. Whether GDB's pseudo > variables that respresent registers are considered unavailable or > optimized out in that case is arguable. I think improving consistency as in Andrew's patch is good. When <unavailable> values were introduced, this particular "info registers"/"*value not available*" string already existed, and it was never adjusted. The distinction between <unavailable> and <optimized out> is: - <optimized out> means that the object no longer exists in the compiled binary, because the compiler got rid of it (the debug info tells us there's no way to retrieve it). - <unavailable> means that the object was not optimized out, and actually exists in the program (and the debug info describes how to get at it), but we don't have access to the bits necessary to extract/compute the object from -- e.g., a core file section has been truncated, a tracepoint did not collect the necessary registers or memory, etc.. I favor normalizing GDB's output in this direction. -- Pedro Alves ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-06 18:39 ` Pedro Alves @ 2013-08-12 13:32 ` Andrew Burgess 2013-08-12 13:55 ` Pedro Alves 0 siblings, 1 reply; 43+ messages in thread From: Andrew Burgess @ 2013-08-12 13:32 UTC (permalink / raw) To: gdb-patches; +Cc: Pedro Alves, Mark Kettenis On 06/08/2013 7:39 PM, Pedro Alves wrote: > On 08/06/2013 04:41 PM, Mark Kettenis wrote: >>> Date: Tue, 6 Aug 2013 14:49:03 +0100 >>> From: "Andrew Burgess" <aburgess@broadcom.com> > >>> 3. My understanding was that values lost due to the ABI of a call site >>> were recorded as optimized out. For evidence I would present >>> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >>> >>> For these reasons I believe my patch should still be considered, what do >>> you think? >> >> I think that registers are either available or unavailble. A register >> being unavailble implies that a variable that is supposed to live in >> such a register may have been optimized out. Whether GDB's pseudo >> variables that respresent registers are considered unavailable or >> optimized out in that case is arguable. > > I think improving consistency as in Andrew's patch is good. Given almost a week has passed with no further feedback I plan to commit this patch tomorrow unless there's any further discussion to be had. Thanks, Andrew ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-12 13:32 ` Andrew Burgess @ 2013-08-12 13:55 ` Pedro Alves 2013-08-12 14:01 ` Andrew Burgess 2013-08-12 20:01 ` Mark Kettenis 0 siblings, 2 replies; 43+ messages in thread From: Pedro Alves @ 2013-08-12 13:55 UTC (permalink / raw) To: Andrew Burgess; +Cc: gdb-patches, Mark Kettenis On 08/12/2013 02:31 PM, Andrew Burgess wrote: > On 06/08/2013 7:39 PM, Pedro Alves wrote: >> On 08/06/2013 04:41 PM, Mark Kettenis wrote: >>>> Date: Tue, 6 Aug 2013 14:49:03 +0100 >>>> From: "Andrew Burgess" <aburgess@broadcom.com> >> >>>> 3. My understanding was that values lost due to the ABI of a call site >>>> were recorded as optimized out. For evidence I would present >>>> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >>>> >>>> For these reasons I believe my patch should still be considered, what do >>>> you think? >>> >>> I think that registers are either available or unavailble. A register >>> being unavailble implies that a variable that is supposed to live in >>> such a register may have been optimized out. Whether GDB's pseudo >>> variables that respresent registers are considered unavailable or >>> optimized out in that case is arguable. >> >> I think improving consistency as in Andrew's patch is good. > > Given almost a week has passed with no further feedback I plan to > commit this patch tomorrow unless there's any further discussion to be had. TBC, note my opinion doesn't get to overrule Mark's. Consensus works much better, and Mark does have deep knowledge of all ABI/pseudo registers/etc. gdb things. That said, Mark, if you still disagree, please counter argue, otherwise, we'll just have to assume you do agree with the rationales and clarifications. In any case, Andrew, please wait until someone gives the patch an OK. I did not look at the patch at all in any detail, and/or whether it actually follows the guidelines I presented. -- Pedro Alves ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-12 13:55 ` Pedro Alves @ 2013-08-12 14:01 ` Andrew Burgess 2013-08-12 20:01 ` Mark Kettenis 1 sibling, 0 replies; 43+ messages in thread From: Andrew Burgess @ 2013-08-12 14:01 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Mark Kettenis On 12/08/2013 2:55 PM, Pedro Alves wrote: > On 08/12/2013 02:31 PM, Andrew Burgess wrote: >> On 06/08/2013 7:39 PM, Pedro Alves wrote: >>> On 08/06/2013 04:41 PM, Mark Kettenis wrote: >>>>> Date: Tue, 6 Aug 2013 14:49:03 +0100 >>>>> From: "Andrew Burgess" <aburgess@broadcom.com> >>> >>>>> 3. My understanding was that values lost due to the ABI of a call site >>>>> were recorded as optimized out. For evidence I would present >>>>> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >>>>> >>>>> For these reasons I believe my patch should still be considered, what do >>>>> you think? >>>> >>>> I think that registers are either available or unavailble. A register >>>> being unavailble implies that a variable that is supposed to live in >>>> such a register may have been optimized out. Whether GDB's pseudo >>>> variables that respresent registers are considered unavailable or >>>> optimized out in that case is arguable. >>> >>> I think improving consistency as in Andrew's patch is good. >> >> Given almost a week has passed with no further feedback I plan to >> commit this patch tomorrow unless there's any further discussion to be had. > > TBC, note my opinion doesn't get to overrule Mark's. Consensus > works much better, and Mark does have deep knowledge of all > ABI/pseudo registers/etc. gdb things. > That said, Mark, if you still disagree, please counter argue, > otherwise, we'll just have to assume you do agree with the > rationales and clarifications. In any case, Andrew, please wait > until someone gives the patch an OK. I did not look at the patch at > all in any detail, and/or whether it actually follows the guidelines > I presented. Thanks for the reply. This is why I posted before committing, I wasn't sure quite what state this patch was in. I'm more than happy to wait. Cheers, Andrew ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-12 13:55 ` Pedro Alves 2013-08-12 14:01 ` Andrew Burgess @ 2013-08-12 20:01 ` Mark Kettenis 2013-08-13 8:27 ` Andrew Burgess 2013-08-16 18:41 ` Pedro Alves 1 sibling, 2 replies; 43+ messages in thread From: Mark Kettenis @ 2013-08-12 20:01 UTC (permalink / raw) To: palves; +Cc: aburgess, gdb-patches > Date: Mon, 12 Aug 2013 14:55:04 +0100 > From: Pedro Alves <palves@redhat.com> > > On 08/12/2013 02:31 PM, Andrew Burgess wrote: > > On 06/08/2013 7:39 PM, Pedro Alves wrote: > >> On 08/06/2013 04:41 PM, Mark Kettenis wrote: > >>>> Date: Tue, 6 Aug 2013 14:49:03 +0100 > >>>> From: "Andrew Burgess" <aburgess@broadcom.com> > >> > >>>> 3. My understanding was that values lost due to the ABI of a call site > >>>> were recorded as optimized out. For evidence I would present > >>>> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. > >>>> > >>>> For these reasons I believe my patch should still be considered, what do > >>>> you think? > >>> > >>> I think that registers are either available or unavailble. A register > >>> being unavailble implies that a variable that is supposed to live in > >>> such a register may have been optimized out. Whether GDB's pseudo > >>> variables that respresent registers are considered unavailable or > >>> optimized out in that case is arguable. > >> > >> I think improving consistency as in Andrew's patch is good. > > > > Given almost a week has passed with no further feedback I plan to > > commit this patch tomorrow unless there's any further discussion to be had. > > TBC, note my opinion doesn't get to overrule Mark's. Consensus > works much better, and Mark does have deep knowledge of all > ABI/pseudo registers/etc. gdb things. > That said, Mark, if you still disagree, please counter argue, > otherwise, we'll just have to assume you do agree with the > rationales and clarifications. Can't say I agree. It simply doesn't make sense for registers to be "optimized out". I guess there are two reasons why GDB can't display the contents of a register in a frame: 1. The register contents aren't made available by the debugging interface, i.e. ptrace(2) or the remote stub doesn't tell us. 2. The register wasn't saved before calling another function. I guess after Andrew's chnages 1) would be shown as <unavailable> and 2) would become <optimized out>. But in the latter case something like <not saved> would make more sense. That said, Pedro, you're pretty much the expert for this area of GDB. So If you think Andrew should go ahead with this, feel free to ignore me. ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-12 20:01 ` Mark Kettenis @ 2013-08-13 8:27 ` Andrew Burgess 2013-08-16 18:41 ` Pedro Alves 1 sibling, 0 replies; 43+ messages in thread From: Andrew Burgess @ 2013-08-13 8:27 UTC (permalink / raw) To: Mark Kettenis; +Cc: palves, gdb-patches On 12/08/2013 9:01 PM, Mark Kettenis wrote: >> Date: Mon, 12 Aug 2013 14:55:04 +0100 >> From: Pedro Alves <palves@redhat.com> >> >> On 08/12/2013 02:31 PM, Andrew Burgess wrote: >>> On 06/08/2013 7:39 PM, Pedro Alves wrote: >>>> On 08/06/2013 04:41 PM, Mark Kettenis wrote: >>>>>> Date: Tue, 6 Aug 2013 14:49:03 +0100 >>>>>> From: "Andrew Burgess" <aburgess@broadcom.com> >>>> >>>>>> 3. My understanding was that values lost due to the ABI of a call site >>>>>> were recorded as optimized out. For evidence I would present >>>>>> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >>>>>> >>>>>> For these reasons I believe my patch should still be considered, what do >>>>>> you think? >>>>> >>>>> I think that registers are either available or unavailble. A register >>>>> being unavailble implies that a variable that is supposed to live in >>>>> such a register may have been optimized out. Whether GDB's pseudo >>>>> variables that respresent registers are considered unavailable or >>>>> optimized out in that case is arguable. >>>> >>>> I think improving consistency as in Andrew's patch is good. >>> >>> Given almost a week has passed with no further feedback I plan to >>> commit this patch tomorrow unless there's any further discussion to be had. >> >> TBC, note my opinion doesn't get to overrule Mark's. Consensus >> works much better, and Mark does have deep knowledge of all >> ABI/pseudo registers/etc. gdb things. >> That said, Mark, if you still disagree, please counter argue, >> otherwise, we'll just have to assume you do agree with the >> rationales and clarifications. > > Can't say I agree. It simply doesn't make sense for registers to be > "optimized out". For the sake of this discussion lets say I agree with you, what I hope to show is that it doesn't actually matter if I agree or not as this patch has /nothing/ to do with solving the issue that is bothering you. > I guess there are two reasons why GDB can't display > the contents of a register in a frame: > > 1. The register contents aren't made available by the debugging > interface, i.e. ptrace(2) or the remote stub doesn't tell us. > > 2. The register wasn't saved before calling another function. Ok, so lets look at how gdb handles these cases before my patch, CASE 1: This results in a value object marked "unavailable", when printed using "p $reg" we get "<unavailable>" and when printed using "info registers reg" we get "*value not available*". CASE 2: This currently /does/ result in a value marked "optimized-out", when printed using "p $reg" we get "<optimized-out>" and when printed using "info register reg" we get "*value not available*". My patch is based on the following idea: When printing a value we should always display the same result no matter how the value is printed.[1] As I understand your point you believe CASE 2 should print (something like) "<not-saved>". OK, so, how could we achieve that? Here are a few possible options, (#0) Leave things alone. This makes me unhappy as it breaks my rule about printing the same value in different ways. Also, I assume this does not make you happy as we can't tell the difference between unavailable values and not-saved values. (#1) Change the string "*value not available*" to be "<not-saved>". This is bad because CASE 1 above would also print "<not-saved>" and I think we agree that for CASE 1 we should print "<unavailable>". (#2) Apply my patch, but for values marked optimized out print "<not-saved>". Well, this handles CASE 1 correctly[2], but now we print "<optimized-out>" when we using "p $reg" and "<not-saved>" for "info registers reg". This makes me unhappy as it breaks my rule about displaying the save value in the same way. (#3) Apply my patch, but for value marked optimized out print "<not-saved>", AND special case other places we print "<optimized-out>" to print "<not-saved>". So in theory this gets you what you want. We don't think registers should ever be "optimized-out" so we don't miss our inability to print optimized out registers, but there are two problems, first, we litter the printing code with special cases to print either "<optimized-out>" or "<not-saved>", and second, I suspect given that your presented with a value marked optimized out, deciding whether it should be printed as optimized out or not saved will be hard (and unreliable). (#4) Replace every print of "<optimized-out>" with "<not-saved>". I mention this just for completeness, I hope we both agree this is just silly, obviously DWARF can mark variables as optimized out, so we do have to support values that are optimized out, and print them as "<optimized-out>". (#5) Introduce a new value type "not-saved". This is the only way I can see that you will get what you want. Values that are in registers that are lost due to ABI would be marked as "not-saved", and printed as "<not-saved>". It turns out that I've just submitted a patch set[3] which would make supporting a new reason really easy, however this is /not/ what this patch is about. So, what is this patch about. This patch is about printing what a value /is/, if a value /is/ unavailable print "<unavailable>", if a value /is/ optimized out, print "<optimized-out>" ... in some future world if a value /is/ not-saved, then print "<not-saved>". The problem is that you want a not-saved state, and currently that doesn't exist in gdb. If once you have introduce the not-saved state then you could, if you like change the code: if (optimized_out (value)) print "<optimized-out>" to be: gdb_assert (!optimized_out (value)); and sure, that would be a reverting part of this patch, but it doesn't feel like a huge amount of work, and given that right now register values /are/ optimized out, surely we should print them correctly? Thanks, Andrew [1] Obviously here I'm talking about different ways to ask for effectively the same view of the value, so "p $reg" and "info register reg". [2] Or will once my follow-up patch is applied: http://sourceware.org/ml/gdb-patches/2013-08/msg00171.html [3] http://sourceware.org/ml/gdb-patches/2013-08/msg00300.html > > I guess after Andrew's chnages 1) would be shown as <unavailable> and > 2) would become <optimized out>. But in the latter case something > like <not saved> would make more sense. > > That said, Pedro, you're pretty much the expert for this area of GDB. > So If you think Andrew should go ahead with this, feel free to ignore > me. > > > ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-12 20:01 ` Mark Kettenis 2013-08-13 8:27 ` Andrew Burgess @ 2013-08-16 18:41 ` Pedro Alves 2013-08-16 20:28 ` Pedro Alves 2013-08-19 10:25 ` Andrew Burgess 1 sibling, 2 replies; 43+ messages in thread From: Pedro Alves @ 2013-08-16 18:41 UTC (permalink / raw) To: Mark Kettenis; +Cc: aburgess, gdb-patches On 08/12/2013 09:01 PM, Mark Kettenis wrote: >> Date: Mon, 12 Aug 2013 14:55:04 +0100 >> From: Pedro Alves <palves@redhat.com> >> >> On 08/12/2013 02:31 PM, Andrew Burgess wrote: >>> On 06/08/2013 7:39 PM, Pedro Alves wrote: >>>> On 08/06/2013 04:41 PM, Mark Kettenis wrote: >>>>>> Date: Tue, 6 Aug 2013 14:49:03 +0100 >>>>>> From: "Andrew Burgess" <aburgess@broadcom.com> >>>> >>>>>> 3. My understanding was that values lost due to the ABI of a call site >>>>>> were recorded as optimized out. For evidence I would present >>>>>> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >>>>>> >>>>>> For these reasons I believe my patch should still be considered, what do >>>>>> you think? >>>>> >>>>> I think that registers are either available or unavailble. A register >>>>> being unavailble implies that a variable that is supposed to live in >>>>> such a register may have been optimized out. Whether GDB's pseudo >>>>> variables that respresent registers are considered unavailable or >>>>> optimized out in that case is arguable. >>>> >>>> I think improving consistency as in Andrew's patch is good. >>> >>> Given almost a week has passed with no further feedback I plan to >>> commit this patch tomorrow unless there's any further discussion to be had. >> >> TBC, note my opinion doesn't get to overrule Mark's. Consensus >> works much better, and Mark does have deep knowledge of all >> ABI/pseudo registers/etc. gdb things. >> That said, Mark, if you still disagree, please counter argue, >> otherwise, we'll just have to assume you do agree with the >> rationales and clarifications. > > Can't say I agree. It simply doesn't make sense for registers to be > "optimized out". I guess there are two reasons why GDB can't display > the contents of a register in a frame: > > 1. The register contents aren't made available by the debugging > interface, i.e. ptrace(2) or the remote stub doesn't tell us. > > 2. The register wasn't saved before calling another function. > > I guess after Andrew's chnages 1) would be shown as <unavailable> and > 2) would become <optimized out>. But in the latter case something > like <not saved> would make more sense. > > That said, Pedro, you're pretty much the expert for this area of GDB. > So If you think Andrew should go ahead with this, feel free to ignore > me. This is a tough call. I do agree that "optimized out" for registers is a bit confusing. However, we already do print "<optimized out>" in other places, such as when printing expressions, and consistency is good. If we did add a distinction, I agree with Andrew that it should be done in a more systematic way. However, I'm not really sure we need much machinery. Wouldn't something like: void val_print_optimized_out (const struct value *val, struct ui_file *stream) { if (value_lval_const (val) == lval_register) fprintf_filtered (stream, _("<not saved>")); else fprintf_filtered (stream, _("<optimized out>")); } work? What could be the register value cases that would print "not saved" that we'd still want to print "optimized out" ? ... Hmm, I spent a bit playing with this, and here's what I got. At first glance, the changes in output all look reasonable to me. frame_unwind_got_optimized needed a tweak to return an lval_register value; it's returning not_lval presently. Pushed here (along with Andrew's patch) for convenience: https://github.com/palves/gdb/commits/register_not_saved git@github.com:palves/gdb.git register_not_saved Here's the (trimmed for brevity) diff of the resulting gdb.log between after Andrew's path and after my patch, of a run of gdb.dwarf2/dw2-op-out-param.exp gdb.dwarf2/dw2-reg-undefined.exp gdb.mi/mi-reg-undefined.exp, the only tests affected. (Code patch further below.) ~~~~ (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: Switch to frame 1 p/x $rax -$6 = <optimized out> +$6 = <not saved> (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: print $rax in frame 1 p/x $rbx -$7 = <optimized out> +$7 = <not saved> (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: print $rbx in frame 1 p/x $rcx -$8 = <optimized out> +$8 = <not saved> (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: print $rcx in frame 1 p/x $r8 $9 = 0x323d7b1f40 @@ -109,9 +109,9 @@ p/x $r9 $10 = 0x323d00f310 (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: print $r9 in frame 1 info registers rax rbx rcx r8 r9 -rax <optimized out> -rbx <optimized out> -rcx <optimized out> +rax <not saved> +rbx <not saved> +rcx <not saved> r8 0x323d7b1f40 215779843904 r9 0x323d00f310 215771837200 (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: Check values of rax, rbx, rcx, r8, r9 in frame 1 @@ -120,13 +120,13 @@ frame 2 33 first_frame (); (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: Switch to frame 2 p/x $rax -$11 = <optimized out> +$11 = <not saved> (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: print $rax in frame 2 p/x $rbx -$12 = <optimized out> +$12 = <not saved> (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: print $rbx in frame 2 p/x $rcx -$13 = <optimized out> +$13 = <not saved> (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: print $rcx in frame 2 p/x $r8 $14 = 0x323d7b1f40 @@ -135,13 +135,13 @@ p/x $r9 $15 = 0x323d00f310 (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: print $r9 in frame 2 info registers rax rbx rcx r8 r9 -rax <optimized out> -rbx <optimized out> -rcx <optimized out> +rax <not saved> +rbx <not saved> +rcx <not saved> r8 0x323d7b1f40 215779843904 r9 0x323d00f310 215771837200 (gdb) PASS: gdb.dwarf2/dw2-reg-undefined.exp: Check values of rax, rbx, rcx, r8, r9 in frame 2 PASS: gdb.mi/mi-reg-undefined.exp: mi runto stop_frame @@ -247,35 +247,35 @@ Expecting: ^(330-data-list-register-valu (gdb) PASS: gdb.mi/mi-reg-undefined.exp: register values, format r, frame 0 Expecting: ^(221-data-list-register-values --thread 1 --frame 1 x 0 1 2 8 9[ -]+)?(221\^done,register-values=\[{number="0",value="<optimized out>"},{number="1",value="<optimized out>"},{number="2",value="<optimized out>"},{number="8",value="0x[0-9A-Fa-f]+"},{number="9",value="0x[0-9A-Fa-f]+"}\][ +]+)?(221\^done,register-values=\[{number="0",value="<not saved>"},{number="1",value="<not saved>"},{number="2",value="<not saved>"},{number="8",value="0x[0-9A-Fa-f]+"},{number="9",value="0x[0-9A-Fa-f]+"}\][ ]+[(]gdb[)] [ ]*) 221-data-list-register-values --thread 1 --frame 1 x 0 1 2 8 9 -221^done,register-values=[{number="0",value="<optimized out>"},{number="1",value="<optimized out>"},{number="2",value="<optimized out>"},{number="8",value="0x323d7b1f40"},{number="9",value="0x323d00f310"}] +221^done,register-values=[{number="0",value="<not saved>"},{number="1",value="<not saved>"},{number="2",value="<not saved>"},{number="8",value="0x323d7b1f40"},{number="9",value="0x323d00f310"}] (gdb) PASS: gdb.mi/mi-reg-undefined.exp: register values, format x, frame 1 Expecting: ^(331-data-list-register-values --thread 1 --frame 1 r 0 1 2 8 9[ -]+)?(331\^done,register-values=\[{number="0",value="<optimized out>"},{number="1",value="<optimized out>"},{number="2",value="<optimized out>"},{number="8",value="0x[0-9A-Fa-f]+"},{number="9",value="0x[0-9A-Fa-f]+"}\][ +]+)?(331\^done,register-values=\[{number="0",value="<not saved>"},{number="1",value="<not saved>"},{number="2",value="<not saved>"},{number="8",value="0x[0-9A-Fa-f]+"},{number="9",value="0x[0-9A-Fa-f]+"}\][ ]+[(]gdb[)] [ ]*) 331-data-list-register-values --thread 1 --frame 1 r 0 1 2 8 9 -331^done,register-values=[{number="0",value="<optimized out>"},{number="1",value="<optimized out>"},{number="2",value="<optimized out>"},{number="8",value="0x000000323d7b1f40"},{number="9",value="0x000000323d00f310"}] +331^done,register-values=[{number="0",value="<not saved>"},{number="1",value="<not saved>"},{number="2",value="<not saved>"},{number="8",value="0x000000323d7b1f40"},{number="9",value="0x000000323d00f310"}] (gdb) PASS: gdb.mi/mi-reg-undefined.exp: register values, format r, frame 1 Expecting: ^(222-data-list-register-values --thread 1 --frame 2 x 0 1 2 8 9[ -]+)?(222\^done,register-values=\[{number="0",value="<optimized out>"},{number="1",value="<optimized out>"},{number="2",value="<optimized out>"},{number="8",value="0x[0-9A-Fa-f]+"},{number="9",value="0x[0-9A-Fa-f]+"}\][ +]+)?(222\^done,register-values=\[{number="0",value="<not saved>"},{number="1",value="<not saved>"},{number="2",value="<not saved>"},{number="8",value="0x[0-9A-Fa-f]+"},{number="9",value="0x[0-9A-Fa-f]+"}\][ ]+[(]gdb[)] [ ]*) 222-data-list-register-values --thread 1 --frame 2 x 0 1 2 8 9 -222^done,register-values=[{number="0",value="<optimized out>"},{number="1",value="<optimized out>"},{number="2",value="<optimized out>"},{number="8",value="0x323d7b1f40"},{number="9",value="0x323d00f310"}] +222^done,register-values=[{number="0",value="<not saved>"},{number="1",value="<not saved>"},{number="2",value="<not saved>"},{number="8",value="0x323d7b1f40"},{number="9",value="0x323d00f310"}] (gdb) PASS: gdb.mi/mi-reg-undefined.exp: register values, format x, frame 2 Expecting: ^(332-data-list-register-values --thread 1 --frame 2 r 0 1 2 8 9[ -]+)?(332\^done,register-values=\[{number="0",value="<optimized out>"},{number="1",value="<optimized out>"},{number="2",value="<optimized out>"},{number="8",value="0x[0-9A-Fa-f]+"},{number="9",value="0x[0-9A-Fa-f]+"}\][ +]+)?(332\^done,register-values=\[{number="0",value="<not saved>"},{number="1",value="<not saved>"},{number="2",value="<not saved>"},{number="8",value="0x[0-9A-Fa-f]+"},{number="9",value="0x[0-9A-Fa-f]+"}\][ ]+[(]gdb[)] [ ]*) 332-data-list-register-values --thread 1 --frame 2 r 0 1 2 8 9 -332^done,register-values=[{number="0",value="<optimized out>"},{number="1",value="<optimized out>"},{number="2",value="<optimized out>"},{number="8",value="0x000000323d7b1f40"},{number="9",value="0x000000323d00f310"}] +332^done,register-values=[{number="0",value="<not saved>"},{number="1",value="<not saved>"},{number="2",value="<not saved>"},{number="8",value="0x000000323d7b1f40"},{number="9",value="0x000000323d00f310"}] (gdb) PASS: gdb.mi/mi-reg-undefined.exp: register values, format r, frame 2 testcase ../../../src/gdb/testsuite/gdb.mi/mi-reg-undefined.exp completed in 0 seconds @@ -338,7 +338,7 @@ Breakpoint 2, 0x000000000040058f in brea (gdb) PASS: gdb.dwarf2/dw2-op-out-param.exp: continue to breakpoint: Stop in breakpt for test int_param_single_reg_loc bt #0 0x000000000040058f in breakpt () -#1 0x00000000004005a2 in int_param_single_reg_loc (operand0=<optimized out>, operand1=0xdeadbe00deadbe01, operand2=<optimized out>) +#1 0x00000000004005a2 in int_param_single_reg_loc (operand0=<not saved>, operand1=0xdeadbe00deadbe01, operand2=<not saved>) #2 0x0000000000400577 in main () (gdb) PASS: gdb.dwarf2/dw2-op-out-param.exp: Backtrace for test int_param_single_reg_loc continue @@ -348,7 +348,7 @@ Breakpoint 2, 0x000000000040058f in brea (gdb) PASS: gdb.dwarf2/dw2-op-out-param.exp: continue to breakpoint: Stop in breakpt for struct_param_single_reg_loc bt #0 0x000000000040058f in breakpt () -#1 0x00000000004005b2 in struct_param_single_reg_loc (operand0=<optimized out>, operand1=<optimized out>, operand2=<optimized out>) +#1 0x00000000004005b2 in struct_param_single_reg_loc (operand0=<not saved>, operand1=<not saved>, operand2=<not saved>) #2 0x000000000040057d in main () (gdb) KFAIL: gdb.dwarf2/dw2-op-out-param.exp: Backtrace for test struct_param_single_reg_loc (PRMS: symtab/14604) continue @@ -371,7 +371,7 @@ bt #1 0x00000000004005d2 in int_param_two_reg_pieces (operand0=0xdeadbe05, operand1=0xdeadbe0100000000, operand2=0x0) #2 0x0000000000400589 in main () (gdb) KFAIL: gdb.dwarf2/dw2-op-out-param.exp: Backtrace for test int_param_two_reg_pieces (PRMS: symtab/14605) ~~~~ ------- From 2e7a45e5752bbdd3344b540dd27fafe0faf4e627 Mon Sep 17 00:00:00 2001 From: Pedro Alves <palves@redhat.com> Date: Fri, 16 Aug 2013 11:31:13 +0100 Subject: [PATCH] WIP: print "optimized out" register values as "<not saved>" instead of "optimized out". --- gdb/cp-valprint.c | 4 ++-- gdb/frame-unwind.c | 2 +- gdb/infcmd.c | 2 +- gdb/jv-valprint.c | 4 ++-- gdb/p-valprint.c | 4 ++-- gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp | 10 +++++----- 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 | 23 ++++++++++++++++++++++- gdb/value.h | 4 ++++ 12 files changed, 53 insertions(+), 24 deletions(-) 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, _("<error reading variable: %s>"), 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/frame-unwind.c b/gdb/frame-unwind.c index ce2f6da..69c977e 100644 --- a/gdb/frame-unwind.c +++ b/gdb/frame-unwind.c @@ -164,7 +164,7 @@ frame_unwind_got_optimized (struct frame_info *frame, int regnum) struct gdbarch *gdbarch = frame_unwind_arch (frame); struct type *reg_type = register_type (gdbarch, regnum); - return allocate_optimized_out_value (reg_type); + return allocate_not_saved_value (reg_type, frame, regnum); } /* Return a value which indicates that FRAME copied REGNUM into diff --git a/gdb/infcmd.c b/gdb/infcmd.c index f6a5290..76e84c9 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; } diff --git a/gdb/jv-valprint.c b/gdb/jv-valprint.c index 3b90e54..961a8e8 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 (v, stream); else { struct value_print_options opts; diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c index 05d4c6f..6e8a408 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 (v, stream); else pascal_object_print_static_field (v, stream, recurse + 1, options); diff --git a/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp index 5e4ca01..fecb0df 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp +++ b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp @@ -46,16 +46,16 @@ gdb_test_no_output "set print frame-arguments all" # (1) int_param_single_reg_loc gdb_continue_to_breakpoint "Stop in breakpt for test int_param_single_reg_loc" -gdb_test "bt" "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_single_reg_loc \\(operand0=<optimized out>, operand1=0xdeadbe00deadbe01, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)" "Backtrace for test int_param_single_reg_loc" +gdb_test "bt" "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_single_reg_loc \\(operand0=<not saved>, operand1=0xdeadbe00deadbe01, operand2=<not saved>\\)\r\n#2 ($hex in )?main \\(\\)" "Backtrace for test int_param_single_reg_loc" # (2) struct_param_single_reg_loc gdb_continue_to_breakpoint "Stop in breakpt for struct_param_single_reg_loc" set test "Backtrace for test struct_param_single_reg_loc" gdb_test_multiple "bt" "$test" { - -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_single_reg_loc \\(operand0={a = 0xdeadbe00deadbe01, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe04deadbe05}, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { + -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_single_reg_loc \\(operand0={a = 0xdeadbe00deadbe01, b = <not saved>}, operand1={a = <not saved>, b = 0xdeadbe04deadbe05}, operand2=<not saved>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { xpass $test } - -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_single_reg_loc \\(operand0=<optimized out>, operand1=<optimized out>, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { + -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_single_reg_loc \\(operand0=<not saved>, operand1=<not saved>, operand2=<not saved>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { kfail "symtab/14604" $test } } @@ -64,7 +64,7 @@ gdb_test_multiple "bt" "$test" { gdb_continue_to_breakpoint "Stop in breakpt for struct_param_two_reg_pieces" set test "Backtrace for test struct_param_two_reg_pieces" gdb_test_multiple "bt" "$test" { - -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_two_reg_pieces \\(operand0={a = 0xdeadbe04deadbe05, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe00deadbe01}, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { + -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_two_reg_pieces \\(operand0={a = 0xdeadbe04deadbe05, b = <not saved>}, operand1={a = <not saved>, b = 0xdeadbe00deadbe01}, operand2=<not saved>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { xpass $test } -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?struct_param_two_reg_pieces \\(operand0=.*, operand1=.*, operand2=.*\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { @@ -76,7 +76,7 @@ gdb_test_multiple "bt" "$test" { gdb_continue_to_breakpoint "Stop in breakpt for int_param_two_reg_pieces" set test "Backtrace for test int_param_two_reg_pieces" gdb_test_multiple "bt" "$test" { - -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_two_reg_pieces \\(operand0=<optimized out>, operand1=<optimized out>, operand2=<optimized out>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { + -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_two_reg_pieces \\(operand0=<not saved>, operand1=<not saved>, operand2=<not saved>\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { xpass $test } -re "#0 ($hex in )?breakpt \\(\\)\r\n#1 ($hex in )?int_param_two_reg_pieces \\(operand0=.*, operand1=.*, operand2=.*\\)\r\n#2 ($hex in )?main \\(\\)\r\n$gdb_prompt $" { 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 "<optimized out>" - set pattern_rax_rbx_rcx_info "<optimized out>" + set pattern_rax_rbx_rcx_print "<not saved>" + set pattern_rax_rbx_rcx_info "<not saved>" 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 "<optimized out>" +set not_saved_pattern "<not saved>" 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 753ae34..285a7fe 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, _("<optimized out>")); + if (val != NULL && value_lval_const (val) == lval_register) + fprintf_filtered (stream, _("<not saved>")); + else + fprintf_filtered (stream, _("<optimized out>")); } void @@ -805,7 +808,7 @@ value_check_printable (struct value *val, struct ui_file *stream, if (options->summary && !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 2959098..40e2ebb 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 09ab1bb..6032267 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -747,6 +747,22 @@ allocate_optimized_out_value (struct type *type) return retval; } +/* Allocate a "not saved" value for type TYPE. */ + +struct value * +allocate_not_saved_value (struct type *type, + struct frame_info *frame, int regnum) +{ + struct value *retval = allocate_value (type); + + set_value_optimized_out (retval, 1); + VALUE_LVAL (retval) = lval_register; + VALUE_FRAME_ID (retval) = get_frame_id (frame); + VALUE_REGNUM (retval) = regnum; + + return retval; +} + /* Accessor methods. */ struct value * @@ -886,7 +902,12 @@ 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 has been optimized out")); + } } static void diff --git a/gdb/value.h b/gdb/value.h index bef193c..d4463bf 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -243,6 +243,10 @@ extern int valprint_check_validity (struct ui_file *stream, struct type *type, extern struct value *allocate_optimized_out_value (struct type *type); +extern struct value *allocate_not_saved_value (struct type *type, + struct frame_info *frame, + int regnum); + /* If VALUE is lval_computed, return its lval_funcs structure. */ extern const struct lval_funcs *value_computed_funcs (const struct value *); -- 1.7.11.7 ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-16 18:41 ` Pedro Alves @ 2013-08-16 20:28 ` Pedro Alves 2013-08-19 10:25 ` Andrew Burgess 1 sibling, 0 replies; 43+ messages in thread From: Pedro Alves @ 2013-08-16 20:28 UTC (permalink / raw) To: gdb-patches; +Cc: Mark Kettenis, aburgess On 08/16/2013 07:41 PM, Pedro Alves wrote: > +/* Allocate a "not saved" value for type TYPE. */ > + > +struct value * > +allocate_not_saved_value (struct type *type, > + struct frame_info *frame, int regnum) > +{ > + struct value *retval = allocate_value (type); > + > + set_value_optimized_out (retval, 1); > + VALUE_LVAL (retval) = lval_register; > + VALUE_FRAME_ID (retval) = get_frame_id (frame); I noticed that this should be the previous frame's id, not FRAME's. I've fixed it in the branch, and did some additional cleaning up. -- Pedro Alves ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Consistent display of "<optimized out>" 2013-08-16 18:41 ` Pedro Alves 2013-08-16 20:28 ` Pedro Alves @ 2013-08-19 10:25 ` Andrew Burgess 2013-09-05 16:29 ` [PATCH] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". (was: Re: [PATCH] Consistent display of "<optimized out>") Pedro Alves 1 sibling, 1 reply; 43+ messages in thread From: Andrew Burgess @ 2013-08-19 10:25 UTC (permalink / raw) To: gdb-patches; +Cc: Pedro Alves, Mark Kettenis On 16/08/2013 7:41 PM, Pedro Alves wrote: > On 08/12/2013 09:01 PM, Mark Kettenis wrote: >>> Date: Mon, 12 Aug 2013 14:55:04 +0100 >>> From: Pedro Alves <palves@redhat.com> >>> >>> On 08/12/2013 02:31 PM, Andrew Burgess wrote: >>>> On 06/08/2013 7:39 PM, Pedro Alves wrote: >>>>> On 08/06/2013 04:41 PM, Mark Kettenis wrote: >>>>>>> Date: Tue, 6 Aug 2013 14:49:03 +0100 >>>>>>> From: "Andrew Burgess" <aburgess@broadcom.com> >>>>> >>>>>>> 3. My understanding was that values lost due to the ABI of a call site >>>>>>> were recorded as optimized out. For evidence I would present >>>>>>> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >>>>>>> >>>>>>> For these reasons I believe my patch should still be considered, what do >>>>>>> you think? >>>>>> >>>>>> I think that registers are either available or unavailble. A register >>>>>> being unavailble implies that a variable that is supposed to live in >>>>>> such a register may have been optimized out. Whether GDB's pseudo >>>>>> variables that respresent registers are considered unavailable or >>>>>> optimized out in that case is arguable. >>>>> >>>>> I think improving consistency as in Andrew's patch is good. >>>> >>>> Given almost a week has passed with no further feedback I plan to >>>> commit this patch tomorrow unless there's any further discussion to be had. >>> >>> TBC, note my opinion doesn't get to overrule Mark's. Consensus >>> works much better, and Mark does have deep knowledge of all >>> ABI/pseudo registers/etc. gdb things. >>> That said, Mark, if you still disagree, please counter argue, >>> otherwise, we'll just have to assume you do agree with the >>> rationales and clarifications. >> >> Can't say I agree. It simply doesn't make sense for registers to be >> "optimized out". I guess there are two reasons why GDB can't display >> the contents of a register in a frame: >> >> 1. The register contents aren't made available by the debugging >> interface, i.e. ptrace(2) or the remote stub doesn't tell us. >> >> 2. The register wasn't saved before calling another function. >> >> I guess after Andrew's chnages 1) would be shown as <unavailable> and >> 2) would become <optimized out>. But in the latter case something >> like <not saved> would make more sense. >> >> That said, Pedro, you're pretty much the expert for this area of GDB. >> So If you think Andrew should go ahead with this, feel free to ignore >> me. > > This is a tough call. I do agree that "optimized out" for registers > is a bit confusing. However, we already do print "<optimized out>" in > other places, such as when printing expressions, and consistency > is good. If we did add a distinction, I agree with Andrew that it should > be done in a more systematic way. However, I'm not really sure we need > much machinery. Wouldn't something like: > > void > val_print_optimized_out (const struct value *val, struct ui_file *stream) > { > if (value_lval_const (val) == lval_register) > fprintf_filtered (stream, _("<not saved>")); > else > fprintf_filtered (stream, _("<optimized out>")); > } > > work? What could be the register value cases that would print > "not saved" that we'd still want to print "optimized out" ? The only case I can immediately think of where this would cause a problem would be for computed locations, (lval_computed). The easy answer would be (in that case) the blame the compiler - why say the location is in a register if that register is volatile - but sadly I see this way too often. However, exchanging what I see as the current larger inconsistency, for this much smaller one seems like a good deal to me, especially if it gets this patch unblocked... Thanks, Andrew ^ permalink raw reply [flat|nested] 43+ messages in thread
* [PATCH] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". (was: Re: [PATCH] Consistent display of "<optimized out>") 2013-08-19 10:25 ` Andrew Burgess @ 2013-09-05 16:29 ` Pedro Alves 2013-09-05 16:35 ` [PATCH] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>" Andrew Burgess 0 siblings, 1 reply; 43+ messages in thread From: Pedro Alves @ 2013-09-05 16:29 UTC (permalink / raw) To: Andrew Burgess; +Cc: gdb-patches, Mark Kettenis Hi guys, Getting back to this, trying to make progress. On 08/19/2013 11:24 AM, Andrew Burgess wrote: > On 16/08/2013 7:41 PM, Pedro Alves wrote: >> On 08/12/2013 09:01 PM, Mark Kettenis wrote: >>>> Date: Mon, 12 Aug 2013 14:55:04 +0100 >>>> From: Pedro Alves <palves@redhat.com> >>>> >>>> On 08/12/2013 02:31 PM, Andrew Burgess wrote: >>>>> On 06/08/2013 7:39 PM, Pedro Alves wrote: >>>>>> On 08/06/2013 04:41 PM, Mark Kettenis wrote: >>>>>>>> Date: Tue, 6 Aug 2013 14:49:03 +0100 >>>>>>>> From: "Andrew Burgess" <aburgess@broadcom.com> >>>>>> >>>>>>>> 3. My understanding was that values lost due to the ABI of a call site >>>>>>>> were recorded as optimized out. For evidence I would present >>>>>>>> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >>>>>>>> >>>>>>>> For these reasons I believe my patch should still be considered, what do >>>>>>>> you think? >>>>>>> >>>>>>> I think that registers are either available or unavailble. A register >>>>>>> being unavailble implies that a variable that is supposed to live in >>>>>>> such a register may have been optimized out. Whether GDB's pseudo >>>>>>> variables that respresent registers are considered unavailable or >>>>>>> optimized out in that case is arguable. >>>>>> >>>>>> I think improving consistency as in Andrew's patch is good. >>>>> >>>>> Given almost a week has passed with no further feedback I plan to >>>>> commit this patch tomorrow unless there's any further discussion to be had. >>>> >>>> TBC, note my opinion doesn't get to overrule Mark's. Consensus >>>> works much better, and Mark does have deep knowledge of all >>>> ABI/pseudo registers/etc. gdb things. >>>> That said, Mark, if you still disagree, please counter argue, >>>> otherwise, we'll just have to assume you do agree with the >>>> rationales and clarifications. >>> >>> Can't say I agree. It simply doesn't make sense for registers to be >>> "optimized out". I guess there are two reasons why GDB can't display >>> the contents of a register in a frame: >>> >>> 1. The register contents aren't made available by the debugging >>> interface, i.e. ptrace(2) or the remote stub doesn't tell us. >>> >>> 2. The register wasn't saved before calling another function. >>> >>> I guess after Andrew's chnages 1) would be shown as <unavailable> and >>> 2) would become <optimized out>. But in the latter case something >>> like <not saved> would make more sense. >>> >>> That said, Pedro, you're pretty much the expert for this area of GDB. >>> So If you think Andrew should go ahead with this, feel free to ignore >>> me. >> >> This is a tough call. I do agree that "optimized out" for registers >> is a bit confusing. However, we already do print "<optimized out>" in >> other places, such as when printing expressions, and consistency >> is good. If we did add a distinction, I agree with Andrew that it should >> be done in a more systematic way. However, I'm not really sure we need >> much machinery. Wouldn't something like: >> >> void >> val_print_optimized_out (const struct value *val, struct ui_file *stream) >> { >> if (value_lval_const (val) == lval_register) >> fprintf_filtered (stream, _("<not saved>")); >> else >> fprintf_filtered (stream, _("<optimized out>")); >> } >> >> work? What could be the register value cases that would print >> "not saved" that we'd still want to print "optimized out" ? > > The only case I can immediately think of where this would cause a > problem would be for computed locations, (lval_computed). The easy > answer would be (in that case) the blame the compiler - why say the > location is in a register if that register is volatile - but sadly I see > this way too often. Hmm, OK, but then lval_computed values with that change won't ever show "<not saved>", due to the lval_register check. IOW, we'd have to do something else in addition to lval_computed values to make them print something other than the current <optimized out>. However, I've come to think there's a really simple rule to follow here -- We should only ever print <not saved> for values that represent machine/pseudo registers. IOW, $pc, $rax, etc. If the debug info happens to describe a variable as being located in some optimized out register, we should still print <optimized out>. The previous version of the patch failed that: (gdb) PASS: gdb.dwarf2/dw2-op-out-param.exp: continue to breakpoint: Stop in breakpt for test int_param_single_reg_loc bt #0 0x000000000040058f in breakpt () -#1 0x00000000004005a2 in int_param_single_reg_loc (operand0=<optimized out>, operand1=0xdeadbe00deadbe01, operand2=<optimized out>) +#1 0x00000000004005a2 in int_param_single_reg_loc (operand0=<not saved>, operand1=0xdeadbe00deadbe01, operand2=<not saved>) #2 0x0000000000400577 in main () It didn't really make a lot of sense. This new version doesn't have that change anymore. That simple rule suggests that whatever the internal representation, we should be easily able to have a single central point where to tag such values. In fact, I think that already exists in value_of_register. > However, exchanging what I see as the current larger inconsistency, for > this much smaller one seems like a good deal to me, especially if it > gets this patch unblocked... Alright, what do you (all) think of of this (supposedly finished) patch on top of yours (Andrew's) then? Force-pushed here (along with Andrew's patch) for convenience: https://github.com/palves/gdb/commits/register_not_saved git@github.com:palves/gdb.git register_not_saved -------------- Subject: [PATCH] Print registers not saved in the frame as "<not saved>" instead of "<optimized out>". Currently we print not saved registers as <optimized out>. 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 = <optimized out> (gdb) info registers rax rax <optimized out> After: (gdb) p/x $rax $1 = <not saved> (gdb) info registers rax rax <not saved> However, if for some reason the debug info describes a variable as being in such a register, we still want to print <optimized out>. IOW, <not saved> 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 <optimized out>. 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-05 Pedro Alves <palves@redhat.com> * 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) <xxxxxx>: 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 <not saved> 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) <optimized_out>: 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. gdb/testsuite/ 2013-09-05 Pedro Alves <palves@redhat.com> * gdb.mi/mi-reg-undefined.exp (opt_out_pattern): Delete. (not_saved_pattern): New. Replace uses for the former with the latter. --- gdb/cp-valprint.c | 4 ++-- 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 +++++ 14 files changed, 70 insertions(+), 26 deletions(-) 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, _("<error reading variable: %s>"), 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/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 + <optimized out> instead of <not saved>. */ + 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 f6a5290..2bba49e 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 e6e98b6..503b7bf 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 "<optimized out>" - set pattern_rax_rbx_rcx_info "<optimized out>" + set pattern_rax_rbx_rcx_print "<not saved>" + set pattern_rax_rbx_rcx_info "<not saved>" 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 "<optimized out>" +set not_saved_pattern "<not saved>" 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, _("<optimized out>")); + if (val != NULL && value_lval_const (val) == lval_register) + fprintf_filtered (stream, _("<not saved>")); + else + fprintf_filtered (stream, _("<optimized out>")); } 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 42a8d2f..871b57c 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 ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-05 16:29 ` [PATCH] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". (was: Re: [PATCH] Consistent display of "<optimized out>") Pedro Alves @ 2013-09-05 16:35 ` Andrew Burgess 2013-09-16 19:05 ` Pedro Alves 0 siblings, 1 reply; 43+ messages in thread From: Andrew Burgess @ 2013-09-05 16:35 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Mark Kettenis On 05/09/2013 5:29 PM, Pedro Alves wrote: > Hi guys, > > Getting back to this, trying to make progress. > > On 08/19/2013 11:24 AM, Andrew Burgess wrote: >> On 16/08/2013 7:41 PM, Pedro Alves wrote: >>> On 08/12/2013 09:01 PM, Mark Kettenis wrote: >>>>> Date: Mon, 12 Aug 2013 14:55:04 +0100 >>>>> From: Pedro Alves <palves@redhat.com> >>>>> >>>>> On 08/12/2013 02:31 PM, Andrew Burgess wrote: >>>>>> On 06/08/2013 7:39 PM, Pedro Alves wrote: >>>>>>> On 08/06/2013 04:41 PM, Mark Kettenis wrote: >>>>>>>>> Date: Tue, 6 Aug 2013 14:49:03 +0100 >>>>>>>>> From: "Andrew Burgess" <aburgess@broadcom.com> >>>>>>> >>>>>>>>> 3. My understanding was that values lost due to the ABI of a call site >>>>>>>>> were recorded as optimized out. For evidence I would present >>>>>>>>> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >>>>>>>>> >>>>>>>>> For these reasons I believe my patch should still be considered, what do >>>>>>>>> you think? >>>>>>>> >>>>>>>> I think that registers are either available or unavailble. A register >>>>>>>> being unavailble implies that a variable that is supposed to live in >>>>>>>> such a register may have been optimized out. Whether GDB's pseudo >>>>>>>> variables that respresent registers are considered unavailable or >>>>>>>> optimized out in that case is arguable. >>>>>>> >>>>>>> I think improving consistency as in Andrew's patch is good. >>>>>> >>>>>> Given almost a week has passed with no further feedback I plan to >>>>>> commit this patch tomorrow unless there's any further discussion to be had. >>>>> >>>>> TBC, note my opinion doesn't get to overrule Mark's. Consensus >>>>> works much better, and Mark does have deep knowledge of all >>>>> ABI/pseudo registers/etc. gdb things. >>>>> That said, Mark, if you still disagree, please counter argue, >>>>> otherwise, we'll just have to assume you do agree with the >>>>> rationales and clarifications. >>>> >>>> Can't say I agree. It simply doesn't make sense for registers to be >>>> "optimized out". I guess there are two reasons why GDB can't display >>>> the contents of a register in a frame: >>>> >>>> 1. The register contents aren't made available by the debugging >>>> interface, i.e. ptrace(2) or the remote stub doesn't tell us. >>>> >>>> 2. The register wasn't saved before calling another function. >>>> >>>> I guess after Andrew's chnages 1) would be shown as <unavailable> and >>>> 2) would become <optimized out>. But in the latter case something >>>> like <not saved> would make more sense. >>>> >>>> That said, Pedro, you're pretty much the expert for this area of GDB. >>>> So If you think Andrew should go ahead with this, feel free to ignore >>>> me. >>> >>> This is a tough call. I do agree that "optimized out" for registers >>> is a bit confusing. However, we already do print "<optimized out>" in >>> other places, such as when printing expressions, and consistency >>> is good. If we did add a distinction, I agree with Andrew that it should >>> be done in a more systematic way. However, I'm not really sure we need >>> much machinery. Wouldn't something like: >>> >>> void >>> val_print_optimized_out (const struct value *val, struct ui_file *stream) >>> { >>> if (value_lval_const (val) == lval_register) >>> fprintf_filtered (stream, _("<not saved>")); >>> else >>> fprintf_filtered (stream, _("<optimized out>")); >>> } >>> >>> work? What could be the register value cases that would print >>> "not saved" that we'd still want to print "optimized out" ? >> >> The only case I can immediately think of where this would cause a >> problem would be for computed locations, (lval_computed). The easy >> answer would be (in that case) the blame the compiler - why say the >> location is in a register if that register is volatile - but sadly I see >> this way too often. > > Hmm, OK, but then lval_computed values with that change won't > ever show "<not saved>", due to the lval_register check. IOW, > we'd have to do something else in addition to lval_computed values > to make them print something other than the current <optimized out>. > > However, I've come to think there's a really simple rule to > follow here -- We should only ever print <not saved> for values > that represent machine/pseudo registers. IOW, $pc, $rax, etc. > If the debug info happens to describe a variable as being located > in some optimized out register, we should still print > <optimized out>. The previous version of the patch failed that: > > (gdb) PASS: gdb.dwarf2/dw2-op-out-param.exp: continue to breakpoint: Stop in breakpt for test int_param_single_reg_loc > bt > #0 0x000000000040058f in breakpt () > -#1 0x00000000004005a2 in int_param_single_reg_loc (operand0=<optimized out>, operand1=0xdeadbe00deadbe01, operand2=<optimized out>) > +#1 0x00000000004005a2 in int_param_single_reg_loc (operand0=<not saved>, operand1=0xdeadbe00deadbe01, operand2=<not saved>) > #2 0x0000000000400577 in main () > > It didn't really make a lot of sense. This new version doesn't have > that change anymore. > > That simple rule suggests that whatever the internal representation, > we should be easily able to have a single central point where to tag > such values. In fact, I think that already exists in value_of_register. > >> However, exchanging what I see as the current larger inconsistency, for >> this much smaller one seems like a good deal to me, especially if it >> gets this patch unblocked... > > Alright, what do you (all) think of of this (supposedly finished) patch > on top of yours (Andrew's) then? Looks good to me. Thanks for this. Andrew ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-05 16:35 ` [PATCH] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>" Andrew Burgess @ 2013-09-16 19:05 ` Pedro Alves 2013-09-18 14:04 ` Andrew Burgess 0 siblings, 1 reply; 43+ messages in thread From: Pedro Alves @ 2013-09-16 19:05 UTC (permalink / raw) To: Andrew Burgess; +Cc: gdb-patches, Mark Kettenis On 09/05/2013 05:35 PM, Andrew Burgess wrote: > On 05/09/2013 5:29 PM, Pedro Alves wrote: >> Hi guys, >> >> Getting back to this, trying to make progress. >> >> On 08/19/2013 11:24 AM, Andrew Burgess wrote: >>> On 16/08/2013 7:41 PM, Pedro Alves wrote: >>>> On 08/12/2013 09:01 PM, Mark Kettenis wrote: >>>>>> Date: Mon, 12 Aug 2013 14:55:04 +0100 >>>>>> From: Pedro Alves <palves@redhat.com> >>>>>> >>>>>> On 08/12/2013 02:31 PM, Andrew Burgess wrote: >>>>>>> On 06/08/2013 7:39 PM, Pedro Alves wrote: >>>>>>>> On 08/06/2013 04:41 PM, Mark Kettenis wrote: >>>>>>>>>> Date: Tue, 6 Aug 2013 14:49:03 +0100 >>>>>>>>>> From: "Andrew Burgess" <aburgess@broadcom.com> >>>>>>>> >>>>>>>>>> 3. My understanding was that values lost due to the ABI of a call site >>>>>>>>>> were recorded as optimized out. For evidence I would present >>>>>>>>>> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >>>>>>>>>> >>>>>>>>>> For these reasons I believe my patch should still be considered, what do >>>>>>>>>> you think? >>>>>>>>> >>>>>>>>> I think that registers are either available or unavailble. A register >>>>>>>>> being unavailble implies that a variable that is supposed to live in >>>>>>>>> such a register may have been optimized out. Whether GDB's pseudo >>>>>>>>> variables that respresent registers are considered unavailable or >>>>>>>>> optimized out in that case is arguable. >>>>>>>> >>>>>>>> I think improving consistency as in Andrew's patch is good. >>>>>>> >>>>>>> Given almost a week has passed with no further feedback I plan to >>>>>>> commit this patch tomorrow unless there's any further discussion to be had. >>>>>> >>>>>> TBC, note my opinion doesn't get to overrule Mark's. Consensus >>>>>> works much better, and Mark does have deep knowledge of all >>>>>> ABI/pseudo registers/etc. gdb things. >>>>>> That said, Mark, if you still disagree, please counter argue, >>>>>> otherwise, we'll just have to assume you do agree with the >>>>>> rationales and clarifications. >>>>> >>>>> Can't say I agree. It simply doesn't make sense for registers to be >>>>> "optimized out". I guess there are two reasons why GDB can't display >>>>> the contents of a register in a frame: >>>>> >>>>> 1. The register contents aren't made available by the debugging >>>>> interface, i.e. ptrace(2) or the remote stub doesn't tell us. >>>>> >>>>> 2. The register wasn't saved before calling another function. >>>>> >>>>> I guess after Andrew's chnages 1) would be shown as <unavailable> and >>>>> 2) would become <optimized out>. But in the latter case something >>>>> like <not saved> would make more sense. >>>>> >>>>> That said, Pedro, you're pretty much the expert for this area of GDB. >>>>> So If you think Andrew should go ahead with this, feel free to ignore >>>>> me. >>>> >>>> This is a tough call. I do agree that "optimized out" for registers >>>> is a bit confusing. However, we already do print "<optimized out>" in >>>> other places, such as when printing expressions, and consistency >>>> is good. If we did add a distinction, I agree with Andrew that it should >>>> be done in a more systematic way. However, I'm not really sure we need >>>> much machinery. Wouldn't something like: >>>> >>>> void >>>> val_print_optimized_out (const struct value *val, struct ui_file *stream) >>>> { >>>> if (value_lval_const (val) == lval_register) >>>> fprintf_filtered (stream, _("<not saved>")); >>>> else >>>> fprintf_filtered (stream, _("<optimized out>")); >>>> } >>>> >>>> work? What could be the register value cases that would print >>>> "not saved" that we'd still want to print "optimized out" ? >>> >>> The only case I can immediately think of where this would cause a >>> problem would be for computed locations, (lval_computed). The easy >>> answer would be (in that case) the blame the compiler - why say the >>> location is in a register if that register is volatile - but sadly I see >>> this way too often. >> >> Hmm, OK, but then lval_computed values with that change won't >> ever show "<not saved>", due to the lval_register check. IOW, >> we'd have to do something else in addition to lval_computed values >> to make them print something other than the current <optimized out>. >> >> However, I've come to think there's a really simple rule to >> follow here -- We should only ever print <not saved> for values >> that represent machine/pseudo registers. IOW, $pc, $rax, etc. >> If the debug info happens to describe a variable as being located >> in some optimized out register, we should still print >> <optimized out>. The previous version of the patch failed that: >> >> (gdb) PASS: gdb.dwarf2/dw2-op-out-param.exp: continue to breakpoint: Stop in breakpt for test int_param_single_reg_loc >> bt >> #0 0x000000000040058f in breakpt () >> -#1 0x00000000004005a2 in int_param_single_reg_loc (operand0=<optimized out>, operand1=0xdeadbe00deadbe01, operand2=<optimized out>) >> +#1 0x00000000004005a2 in int_param_single_reg_loc (operand0=<not saved>, operand1=0xdeadbe00deadbe01, operand2=<not saved>) >> #2 0x0000000000400577 in main () >> >> It didn't really make a lot of sense. This new version doesn't have >> that change anymore. >> >> That simple rule suggests that whatever the internal representation, >> we should be easily able to have a single central point where to tag >> such values. In fact, I think that already exists in value_of_register. >> >>> However, exchanging what I see as the current larger inconsistency, for >>> this much smaller one seems like a good deal to me, especially if it >>> gets this patch unblocked... >> >> Alright, what do you (all) think of of this (supposedly finished) patch >> on top of yours (Andrew's) then? > > > Looks good to me. Thanks for this. Thanks. Could you apply your patch then? -- Pedro Alves ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-16 19:05 ` Pedro Alves @ 2013-09-18 14:04 ` Andrew Burgess 2013-09-18 15:54 ` [PATCH+DOC] " Pedro Alves 0 siblings, 1 reply; 43+ messages in thread From: Andrew Burgess @ 2013-09-18 14:04 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Mark Kettenis On 16/09/2013 8:05 PM, Pedro Alves wrote: > On 09/05/2013 05:35 PM, Andrew Burgess wrote: >> On 05/09/2013 5:29 PM, Pedro Alves wrote: >>> Hi guys, >>> >>> Getting back to this, trying to make progress. >>> >>> On 08/19/2013 11:24 AM, Andrew Burgess wrote: >>>> On 16/08/2013 7:41 PM, Pedro Alves wrote: >>>>> On 08/12/2013 09:01 PM, Mark Kettenis wrote: >>>>>>> Date: Mon, 12 Aug 2013 14:55:04 +0100 >>>>>>> From: Pedro Alves <palves@redhat.com> >>>>>>> >>>>>>> On 08/12/2013 02:31 PM, Andrew Burgess wrote: >>>>>>>> On 06/08/2013 7:39 PM, Pedro Alves wrote: >>>>>>>>> On 08/06/2013 04:41 PM, Mark Kettenis wrote: >>>>>>>>>>> Date: Tue, 6 Aug 2013 14:49:03 +0100 >>>>>>>>>>> From: "Andrew Burgess" <aburgess@broadcom.com> >>>>>>>>> >>>>>>>>>>> 3. My understanding was that values lost due to the ABI of a call site >>>>>>>>>>> were recorded as optimized out. For evidence I would present >>>>>>>>>>> dwarf2_frame_prev_register, and how DWARF2_FRAME_REG_UNDEFINED is handled. >>>>>>>>>>> >>>>>>>>>>> For these reasons I believe my patch should still be considered, what do >>>>>>>>>>> you think? >>>>>>>>>> >>>>>>>>>> I think that registers are either available or unavailble. A register >>>>>>>>>> being unavailble implies that a variable that is supposed to live in >>>>>>>>>> such a register may have been optimized out. Whether GDB's pseudo >>>>>>>>>> variables that respresent registers are considered unavailable or >>>>>>>>>> optimized out in that case is arguable. >>>>>>>>> >>>>>>>>> I think improving consistency as in Andrew's patch is good. >>>>>>>> >>>>>>>> Given almost a week has passed with no further feedback I plan to >>>>>>>> commit this patch tomorrow unless there's any further discussion to be had. >>>>>>> >>>>>>> TBC, note my opinion doesn't get to overrule Mark's. Consensus >>>>>>> works much better, and Mark does have deep knowledge of all >>>>>>> ABI/pseudo registers/etc. gdb things. >>>>>>> That said, Mark, if you still disagree, please counter argue, >>>>>>> otherwise, we'll just have to assume you do agree with the >>>>>>> rationales and clarifications. >>>>>> >>>>>> Can't say I agree. It simply doesn't make sense for registers to be >>>>>> "optimized out". I guess there are two reasons why GDB can't display >>>>>> the contents of a register in a frame: >>>>>> >>>>>> 1. The register contents aren't made available by the debugging >>>>>> interface, i.e. ptrace(2) or the remote stub doesn't tell us. >>>>>> >>>>>> 2. The register wasn't saved before calling another function. >>>>>> >>>>>> I guess after Andrew's chnages 1) would be shown as <unavailable> and >>>>>> 2) would become <optimized out>. But in the latter case something >>>>>> like <not saved> would make more sense. >>>>>> >>>>>> That said, Pedro, you're pretty much the expert for this area of GDB. >>>>>> So If you think Andrew should go ahead with this, feel free to ignore >>>>>> me. >>>>> >>>>> This is a tough call. I do agree that "optimized out" for registers >>>>> is a bit confusing. However, we already do print "<optimized out>" in >>>>> other places, such as when printing expressions, and consistency >>>>> is good. If we did add a distinction, I agree with Andrew that it should >>>>> be done in a more systematic way. However, I'm not really sure we need >>>>> much machinery. Wouldn't something like: >>>>> >>>>> void >>>>> val_print_optimized_out (const struct value *val, struct ui_file *stream) >>>>> { >>>>> if (value_lval_const (val) == lval_register) >>>>> fprintf_filtered (stream, _("<not saved>")); >>>>> else >>>>> fprintf_filtered (stream, _("<optimized out>")); >>>>> } >>>>> >>>>> work? What could be the register value cases that would print >>>>> "not saved" that we'd still want to print "optimized out" ? >>>> >>>> The only case I can immediately think of where this would cause a >>>> problem would be for computed locations, (lval_computed). The easy >>>> answer would be (in that case) the blame the compiler - why say the >>>> location is in a register if that register is volatile - but sadly I see >>>> this way too often. >>> >>> Hmm, OK, but then lval_computed values with that change won't >>> ever show "<not saved>", due to the lval_register check. IOW, >>> we'd have to do something else in addition to lval_computed values >>> to make them print something other than the current <optimized out>. >>> >>> However, I've come to think there's a really simple rule to >>> follow here -- We should only ever print <not saved> for values >>> that represent machine/pseudo registers. IOW, $pc, $rax, etc. >>> If the debug info happens to describe a variable as being located >>> in some optimized out register, we should still print >>> <optimized out>. The previous version of the patch failed that: >>> >>> (gdb) PASS: gdb.dwarf2/dw2-op-out-param.exp: continue to breakpoint: Stop in breakpt for test int_param_single_reg_loc >>> bt >>> #0 0x000000000040058f in breakpt () >>> -#1 0x00000000004005a2 in int_param_single_reg_loc (operand0=<optimized out>, operand1=0xdeadbe00deadbe01, operand2=<optimized out>) >>> +#1 0x00000000004005a2 in int_param_single_reg_loc (operand0=<not saved>, operand1=0xdeadbe00deadbe01, operand2=<not saved>) >>> #2 0x0000000000400577 in main () >>> >>> It didn't really make a lot of sense. This new version doesn't have >>> that change anymore. >>> >>> That simple rule suggests that whatever the internal representation, >>> we should be easily able to have a single central point where to tag >>> such values. In fact, I think that already exists in value_of_register. >>> >>>> However, exchanging what I see as the current larger inconsistency, for >>>> this much smaller one seems like a good deal to me, especially if it >>>> gets this patch unblocked... >>> >>> Alright, what do you (all) think of of this (supposedly finished) patch >>> on top of yours (Andrew's) then? >> >> >> Looks good to me. Thanks for this. > > Thanks. Could you apply your patch then? > Committed. Thanks for your time. Andrew ^ permalink raw reply [flat|nested] 43+ messages in thread
* [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-18 14:04 ` Andrew Burgess @ 2013-09-18 15:54 ` Pedro Alves 2013-09-18 16:30 ` Eli Zaretskii 2013-09-18 16:30 ` Andreas Schwab 0 siblings, 2 replies; 43+ messages in thread From: Pedro Alves @ 2013-09-18 15:54 UTC (permalink / raw) To: Andrew Burgess; +Cc: gdb-patches, Mark Kettenis Eli, I've added NEWS and documentation changes to this patch. Are those OK? --------- Currently we print not saved registers as <optimized out>. 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 = <optimized out> (gdb) info registers rax rax <optimized out> After: (gdb) p/x $rax $1 = <not saved> (gdb) info registers rax rax <not saved> However, if for some reason the debug info describes a variable as being in such a register, we still want to print <optimized out>. IOW, <not saved> 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 <optimized out>. 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 <palves@redhat.com> * 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) <xxxxxx>: 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 <not saved> 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) <optimized_out>: 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 <not saved>. gdb/testsuite/ 2013-09-18 Pedro Alves <palves@redhat.com> * 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 <palves@redhat.com> * gdb.texinfo (Registers): Explain <not saved>. --- 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 "<not saved>" when printing values of registers that + have not been saved in the frame: + + (gdb) p $rax $1 = <not saved> + (gdb) info registers rax rax <not saved> + + Before, the former would print "<optimized out>", 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, _("<error reading variable: %s>"), 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{<not saved>}}. + +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 + <optimized out> instead of <not saved>. */ + 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 "<optimized out>" - set pattern_rax_rbx_rcx_info "<optimized out>" + set pattern_rax_rbx_rcx_print "<not saved>" + set pattern_rax_rbx_rcx_info "<not saved>" 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 "<optimized out>" +set not_saved_pattern "<not saved>" 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, _("<optimized out>")); + if (val != NULL && value_lval_const (val) == lval_register) + fprintf_filtered (stream, _("<not saved>")); + else + fprintf_filtered (stream, _("<optimized out>")); } 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 ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-18 15:54 ` [PATCH+DOC] " Pedro Alves @ 2013-09-18 16:30 ` Eli Zaretskii 2013-09-18 17:35 ` Pedro Alves 2013-09-18 20:47 ` Mark Kettenis 2013-09-18 16:30 ` Andreas Schwab 1 sibling, 2 replies; 43+ messages in thread From: Eli Zaretskii @ 2013-09-18 16:30 UTC (permalink / raw) To: Pedro Alves; +Cc: aburgess, gdb-patches, mark.kettenis > Date: Wed, 18 Sep 2013 16:54:27 +0100 > From: Pedro Alves <palves@redhat.com> > CC: gdb-patches@sourceware.org, Mark Kettenis <mark.kettenis@xs4all.nl> > > Eli, I've added NEWS and documentation changes to this patch. > Are those OK? Almost. > +* GDB now shows "<not saved>" when printing values of registers that > + have not been saved in the frame: > + > + (gdb) p $rax $1 = <not saved> > + (gdb) info registers rax rax <not saved> Wrong formatting of what GDB prints. > +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 ^ "the" > +outer frame). Values of registers that @value{GDBN} can tell were not > +saved in their stack frames are shown as @w{@samp{<not saved>}}. > + > +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. I don't understand the significance of the last paragraph. Also, shouldn't we mention optimizations as (the main) reason for registers being unavailable? Thanks. ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-18 16:30 ` Eli Zaretskii @ 2013-09-18 17:35 ` Pedro Alves 2013-09-18 19:35 ` Eli Zaretskii 2013-09-18 20:47 ` Mark Kettenis 1 sibling, 1 reply; 43+ messages in thread From: Pedro Alves @ 2013-09-18 17:35 UTC (permalink / raw) To: Eli Zaretskii; +Cc: aburgess, gdb-patches, mark.kettenis On 09/18/2013 05:30 PM, Eli Zaretskii wrote: >> Date: Wed, 18 Sep 2013 16:54:27 +0100 >> From: Pedro Alves <palves@redhat.com> >> CC: gdb-patches@sourceware.org, Mark Kettenis <mark.kettenis@xs4all.nl> >> >> Eli, I've added NEWS and documentation changes to this patch. >> Are those OK? > > Almost. > >> +* GDB now shows "<not saved>" when printing values of registers that >> + have not been saved in the frame: >> + >> + (gdb) p $rax $1 = <not saved> >> + (gdb) info registers rax rax <not saved> > > Wrong formatting of what GDB prints. Blah. Bad copy/paste. Thanks. > >> +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 > ^ > "the" Fixed. > >> +outer frame). Values of registers that @value{GDBN} can tell were not >> +saved in their stack frames are shown as @w{@samp{<not saved>}}. >> + >> +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. > > I don't understand the significance of the last paragraph. It's preexisting actually. I just added the "debug or unwind info" bit. But yeah, it's confusing. I _think_ I know what it's talking about. I think "makes no difference" refers to GDB assuming $reg in an outer frame is found at the same location as in the inner frame (that is, assuming the call clobbered register hasn't been clobbered yet). I've rewritten all this text now. What do you think? > Also, shouldn't we mention optimizations as (the main) reason for > registers being unavailable? I'm not actually sure how to say that. Not sure you actually always need optimization to see this in the debugger. But maybe we don't need to in this new version. :-) diff --git c/gdb/NEWS w/gdb/NEWS index af06a21..7c10cbb 100644 --- c/gdb/NEWS +++ w/gdb/NEWS @@ -15,6 +15,19 @@ * The "catch syscall" command now works on arm*-linux* targets. +* GDB now shows "<not saved>" when printing values of registers the + debug info indicates have not been saved in the frame and there's + nowhere to retrieve them from: + + (gdb) p $rax + $1 = <not saved> + + (gdb) info registers rax + rax <not saved> + + Before, the former would print "<optimized out>", and the latter + "*value not available*". + * Python scripting ** Frame filters and frame decorators have been added. diff --git c/gdb/doc/gdb.texinfo w/gdb/doc/gdb.texinfo index 60d2877..d122874 100644 --- c/gdb/doc/gdb.texinfo +++ w/gdb/doc/gdb.texinfo @@ -10031,10 +10031,21 @@ 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 the +outer frame), if the register has since been clobbered 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. 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. Values of +registers that @value{GDBN} can definitely tell from the debug/unwind +info were not saved in their stack frames and there's nowhere to +retrieve the original value from anymore are shown as +@w{@samp{<not saved>}}. @node Floating Point Hardware @section Floating Point Hardware ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-18 17:35 ` Pedro Alves @ 2013-09-18 19:35 ` Eli Zaretskii 0 siblings, 0 replies; 43+ messages in thread From: Eli Zaretskii @ 2013-09-18 19:35 UTC (permalink / raw) To: Pedro Alves; +Cc: aburgess, gdb-patches, mark.kettenis > Date: Wed, 18 Sep 2013 18:35:07 +0100 > From: Pedro Alves <palves@redhat.com> > CC: aburgess@broadcom.com, gdb-patches@sourceware.org, mark.kettenis@xs4all.nl > > > I don't understand the significance of the last paragraph. > > It's preexisting actually. I just added the "debug or unwind info" bit. > But yeah, it's confusing. I _think_ I know what it's talking about. > I think "makes no difference" refers to GDB assuming $reg in an outer > frame is found at the same location as in the inner frame (that is, > assuming the call clobbered register hasn't been clobbered yet). > > I've rewritten all this text now. What do you think? We are almost there, just a few minor comments below. > > Also, shouldn't we mention optimizations as (the main) reason for > > registers being unavailable? > > I'm not actually sure how to say that. Not sure you actually > always need optimization to see this in the debugger. But maybe > we don't need to in this new version. :-) One of the comments below addresses that. > +In some ABIs, some registers may not be preserved, or saved, across > +function calls. It's enough to mention optimizations here, as in In some ABIs, or in optimized code, some registers may not be preserved > +the outer frame, you may also be affecting the inner frame. Values of > +registers that @value{GDBN} can definitely tell from the debug/unwind > +info were not saved in their stack frames and there's nowhere to > +retrieve the original value from anymore are shown as > +@w{@samp{<not saved>}}. The last sentence is unduly hard to read, because it uses passive tense too aggressively. I would rephrase: If @value{GDBN} can definitely tell from the debug/unwind info that the value of a register was not saved in its stack frame, and there's no other place for it from which to retrieve that register's original value, @value{GDBN} will show the value of such a register as @w{@samp{<not saved>}}. OK with those changes. Thanks. ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-18 16:30 ` Eli Zaretskii 2013-09-18 17:35 ` Pedro Alves @ 2013-09-18 20:47 ` Mark Kettenis 2013-09-19 7:53 ` Eli Zaretskii 1 sibling, 1 reply; 43+ messages in thread From: Mark Kettenis @ 2013-09-18 20:47 UTC (permalink / raw) To: eliz; +Cc: palves, aburgess, gdb-patches, mark.kettenis > Date: Wed, 18 Sep 2013 19:30:07 +0300 > From: Eli Zaretskii <eliz@gnu.org> > > Also, shouldn't we mention optimizations as (the main) reason for > registers being unavailable? I don't consider optimisations as an important cause of registers not being saved. It is primarily a consequence of the fact that most ABIs reserve some registers as "scratch" registers that don't need to be saved. ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-18 20:47 ` Mark Kettenis @ 2013-09-19 7:53 ` Eli Zaretskii 2013-09-19 16:58 ` Pedro Alves 0 siblings, 1 reply; 43+ messages in thread From: Eli Zaretskii @ 2013-09-19 7:53 UTC (permalink / raw) To: Mark Kettenis; +Cc: palves, aburgess, gdb-patches > Date: Wed, 18 Sep 2013 22:47:24 +0200 (CEST) > From: Mark Kettenis <mark.kettenis@xs4all.nl> > CC: palves@redhat.com, aburgess@broadcom.com, gdb-patches@sourceware.org, > mark.kettenis@xs4all.nl > > > Date: Wed, 18 Sep 2013 19:30:07 +0300 > > From: Eli Zaretskii <eliz@gnu.org> > > > > Also, shouldn't we mention optimizations as (the main) reason for > > registers being unavailable? > > I don't consider optimisations as an important cause of registers not > being saved. The question is: does it happen in practice? If it does, I think we should mention that, because it's important to let the users know that recompiling without optimizations might remove this nuisance. ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-19 7:53 ` Eli Zaretskii @ 2013-09-19 16:58 ` Pedro Alves 2013-09-19 19:15 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Pedro Alves 2013-10-02 16:17 ` [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>" Pedro Alves 0 siblings, 2 replies; 43+ messages in thread From: Pedro Alves @ 2013-09-19 16:58 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Mark Kettenis, aburgess, gdb-patches On 09/19/2013 08:53 AM, Eli Zaretskii wrote: >> Date: Wed, 18 Sep 2013 22:47:24 +0200 (CEST) >> From: Mark Kettenis <mark.kettenis@xs4all.nl> >> CC: palves@redhat.com, aburgess@broadcom.com, gdb-patches@sourceware.org, >> mark.kettenis@xs4all.nl >> >>> Date: Wed, 18 Sep 2013 19:30:07 +0300 >>> From: Eli Zaretskii <eliz@gnu.org> >>> >>> Also, shouldn't we mention optimizations as (the main) reason for >>> registers being unavailable? >> >> I don't consider optimisations as an important cause of registers not >> being saved. > > The question is: does it happen in practice? If it does, I think we > should mention that, because it's important to let the users know that > recompiling without optimizations might remove this nuisance. I think it's really independent of optimization. Jan's comments at <https://sourceware.org/ml/gdb-patches/2012-08/msg00787.html> help understand this. Current/recent enough GCC doesn't mark variables/arguments as being in call-clobbered registers in the ranges corresponding to function calls, while older GCCs did. Newer GCCs will just not say where the variable is, so GDB will end up realizing the variable is optimized out. In fact, if I build an -O2 version of GDB, and do $ readelf --debug-dump=frames ./gdb | grep DW_CFA_undefined nothing comes out. Now, GDB itself could just assume that call-clobbered registers are always <not saved> 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). I wondered what would the "return" command do if forcing a return to a function where we current show registers as "<optimized out>/<not saved>", to see if that would through a "value optimized out" error or some such. It actually doesn't: Breakpoint 2, stop_frame () at dw2-reg-undefined.c:22 22 in dw2-reg-undefined.c (gdb) info registers rax 0x0 0 rbx 0x0 0 rcx 0x400552 4195666 rdx 0x7fffffffdb18 140737488345880 rsi 0x7fffffffdb08 140737488345864 rdi 0x1 1 rbp 0x7fffffffda00 0x7fffffffda00 rsp 0x7fffffffda00 0x7fffffffda00 r8 0x323d7b1f40 215779843904 r9 0x323d00f310 215771837200 r10 0x7fffffffd880 140737488345216 r11 0x323d421640 215776106048 r12 0x400430 4195376 r13 0x7fffffffdb00 140737488345856 r14 0x0 0 r15 0x0 0 rip 0x400540 0x400540 <stop_frame+4> eflags 0x246 [ PF ZF IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) up #1 0x0000000000400550 in first_frame () at dw2-reg-undefined.c:27 27 in dw2-reg-undefined.c (gdb) info registers rax <optimized out> rbx <optimized out> rcx <optimized out> rdx <optimized out> rsi <optimized out> rdi <optimized out> rbp 0x7fffffffda10 0x7fffffffda10 rsp <optimized out> r8 0x323d7b1f40 215779843904 r9 0x323d00f310 215771837200 r10 0x7fffffffd880 140737488345216 r11 0x323d421640 215776106048 r12 0x400430 4195376 r13 0x7fffffffdb00 140737488345856 r14 0x0 0 r15 0x0 0 rip 0x400550 0x400550 <first_frame+14> eflags 0x246 [ PF ZF IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) down #0 stop_frame () at dw2-reg-undefined.c:22 22 in dw2-reg-undefined.c (gdb) return Make stop_frame return now? (y or n) y #0 first_frame () at dw2-reg-undefined.c:28 28 in dw2-reg-undefined.c (gdb) info registers rax 0x0 0 rbx 0x0 0 rcx 0x400552 4195666 rdx 0x7fffffffdb18 140737488345880 rsi 0x7fffffffdb08 140737488345864 rdi 0x1 1 rbp 0x7fffffffda10 0x7fffffffda10 rsp 0x7fffffffda00 0x7fffffffda00 r8 0x323d7b1f40 215779843904 r9 0x323d00f310 215771837200 r10 0x7fffffffd880 140737488345216 r11 0x323d421640 215776106048 r12 0x400430 4195376 r13 0x7fffffffdb00 140737488345856 r14 0x0 0 r15 0x0 0 rip 0x400550 0x400550 <first_frame+14> eflags 0x246 [ PF ZF IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) In case that isn't clear, GDB did fetch the values of call-clobbered registers from the inner frame. I didn't check where/how that happens. -- Pedro Alves ^ permalink raw reply [flat|nested] 43+ messages in thread
* [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) 2013-09-19 16:58 ` Pedro Alves @ 2013-09-19 19:15 ` Pedro Alves 2013-09-19 19:35 ` Eli Zaretskii ` (4 more replies) 2013-10-02 16:17 ` [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>" Pedro Alves 1 sibling, 5 replies; 43+ messages in thread From: Pedro Alves @ 2013-09-19 19:15 UTC (permalink / raw) To: gdb-patches; +Cc: Eli Zaretskii, Mark Kettenis, aburgess On 09/19/2013 05:58 PM, Pedro Alves wrote: > Now, GDB itself could just assume that call-clobbered registers > are always <not saved> 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 "<optimized out>" all the same. (See <https://sourceware.org/ml/gdb-patches/2012-08/msg00787.html>.) The difference is that with binaries produced by those older GCCs, GDB will also print the registers themselves (info registers / p $reg) as "<optimized out>". 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=<optimized out>, operand1=-2401054115373400575, operand2=<optimized out>) (gdb) info registers rax 0x323d7b35b0 215779849648 rbx 0xdeadbe00deadbe01 -2401054115373400575 rcx <optimized out> rdx 0xdeadbe04deadbe05 -2401054098193531387 rsi <optimized out> rdi <optimized out> 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 <int_param_single_reg_loc+10> 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 <breakpt> 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=<optimized out>, operand1=-2401054115373400575, operand2=<optimized out>) (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 <int_param_single_reg_loc+10> 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 <int_param_single_reg_loc+10> 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 <palves@redhat.com> * 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 <palves@redhat.com> * gdb.dwarf2/dw2-reg-undefined.exp: Expect hex numbers instead of "<optimized out>" for all frames. * gdb.mi/mi-reg-undefined.exp (opt_out_pattern): Delete. (top level): Expect hex numbers instead of "<optimized out>" for all frames. gdb/doc/ 2013-09-18 Pedro Alves <palves@redhat.com> * 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 "<optimized out>" - set pattern_rax_rbx_rcx_info "<optimized out>" - 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 "<optimized out>" - 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 ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) 2013-09-19 19:15 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Pedro Alves @ 2013-09-19 19:35 ` Eli Zaretskii 2013-09-19 23:13 ` Doug Evans ` (3 subsequent siblings) 4 siblings, 0 replies; 43+ messages in thread From: Eli Zaretskii @ 2013-09-19 19:35 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, mark.kettenis, aburgess > Date: Thu, 19 Sep 2013 20:15:20 +0100 > From: Pedro Alves <palves@redhat.com> > CC: Eli Zaretskii <eliz@gnu.org>, Mark Kettenis <mark.kettenis@xs4all.nl>, > aburgess@broadcom.com > > +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 "@:" after "a.k.a." Also, caller-saved and call-clobbered should probably be in ``..'' quotes. Otherwise, OK for the documentation part. Thanks. ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) 2013-09-19 19:15 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Pedro Alves 2013-09-19 19:35 ` Eli Zaretskii @ 2013-09-19 23:13 ` Doug Evans 2013-09-19 23:22 ` Doug Evans ` (2 subsequent siblings) 4 siblings, 0 replies; 43+ messages in thread From: Doug Evans @ 2013-09-19 23:13 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Eli Zaretskii, Mark Kettenis, aburgess Pedro Alves writes: > gdb/ > 2013-09-18 Pedro Alves <palves@redhat.com> > > * 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 <palves@redhat.com> > > * gdb.dwarf2/dw2-reg-undefined.exp: Expect hex numbers instead of > "<optimized out>" for all frames. > * gdb.mi/mi-reg-undefined.exp (opt_out_pattern): Delete. > (top level): Expect hex numbers instead of "<optimized out>" for > all frames. > > gdb/doc/ > 2013-09-18 Pedro Alves <palves@redhat.com> > > * gdb.texinfo (Registers): Expand explanation of not-saved > call-clobbered registers in frames other than the innermost. "works for me" ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) 2013-09-19 19:15 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Pedro Alves 2013-09-19 19:35 ` Eli Zaretskii 2013-09-19 23:13 ` Doug Evans @ 2013-09-19 23:22 ` Doug Evans 2013-09-20 11:04 ` [PATCH] Always print call-clobbered registers in outer frames Andrew Burgess 2013-09-20 12:28 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Mark Kettenis 4 siblings, 0 replies; 43+ messages in thread From: Doug Evans @ 2013-09-19 23:22 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Eli Zaretskii, Mark Kettenis, aburgess Pedro Alves writes: > gdb/ > 2013-09-18 Pedro Alves <palves@redhat.com> > > * 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 <palves@redhat.com> > > * gdb.dwarf2/dw2-reg-undefined.exp: Expect hex numbers instead of > "<optimized out>" for all frames. > * gdb.mi/mi-reg-undefined.exp (opt_out_pattern): Delete. > (top level): Expect hex numbers instead of "<optimized out>" for > all frames. > > gdb/doc/ > 2013-09-18 Pedro Alves <palves@redhat.com> > > * gdb.texinfo (Registers): Expand explanation of not-saved > call-clobbered registers in frames other than the innermost. Sorry for the followup. This doesn't have to be part of this patch of course, but IWBN if "i reg" included a note next to register values obtained via heuristics. [such values could have a flag set] It could even be just a general warning printed by "i reg" in non-inner-most frames, but it feels like the above shouldn't be too hard. ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. 2013-09-19 19:15 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Pedro Alves ` (2 preceding siblings ...) 2013-09-19 23:22 ` Doug Evans @ 2013-09-20 11:04 ` Andrew Burgess 2013-09-24 12:07 ` Pedro Alves 2013-09-20 12:28 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Mark Kettenis 4 siblings, 1 reply; 43+ messages in thread From: Andrew Burgess @ 2013-09-20 11:04 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Eli Zaretskii, Mark Kettenis On 19/09/2013 8:15 PM, Pedro Alves wrote: > On 09/19/2013 05:58 PM, Pedro Alves wrote: > >> Now, GDB itself could just assume that call-clobbered registers >> are always <not saved> 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 "<optimized out>" all the > same. (See <https://sourceware.org/ml/gdb-patches/2012-08/msg00787.html>.) > > The difference is that with binaries produced by those older GCCs, GDB > will also print the registers themselves (info registers / p $reg) as > "<optimized out>". This is confusing. I agree with you 100% on this, however, I feel we're merging two arguments together here. The reason gdb prints <optimised out> is really because values only support 3 states: available, unavailable, and optimized-out, we use optimized-out for the DW_CFA_undefined state. What we really need is a new state, lets call it not-saved, we don't necessarily need to have extra state inside the value object to model this, we might (as in your original patch) be able to derive this state, but this is a state that a register can be in. > 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. You're right that most targets seem to follow this rule, which seems odd to me, however I think that the rs600, s390, sh, and tic6x targets don't, they set the call-clobbered registers to DW_CFA_undefined in their dwarf2_frame_set_init_reg functions, this seems much more sensible to me, assuming that call-clobbered registers have not been used seems .... odd. > > 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. I really think this is going to confuse users, we're basically saying that call-clobbered registers are assumed to never be clobbered .... we might get away with this from very shallow call-stacks, but for very deep stacks this seems very unlikely, in which case, a user switches to some outer stack and does "info registers", how does he know which registers gdb has carefully retrieved and are correct, and which are just random values fetched from some inner frame? My question then is, what makes you believe the inner, possibly call-clobbered value is right? > Which is what you'd get with a newer GCC. I think this statement is only true for platforms that don't define any call-clobbered registers in their dwarf2_frame_set_init_reg function. Like I said before, this feels like a bug for those platforms to me, probably one that has only become apparent since gcc stopped marking values as DW_CFA_undefined; I guess this has not been an issue as gcc at the same time stopped leaving variables in these registers. > 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: I agree with this, but don't think it's relevant, your talking about altering the control flow of the inferior, this is not what "info registers" means to me, I'm expecting to see the value of those registers as they were, in that frame, at the time of the call, if gdb can't figure that out then I'd much rather gdb just says so... but maybe I'm expecting the wrong thing... > > 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 I think here you should say "Most ABIs reserve some registers as ``scratch'' registers that don't need to be saved by the callee" (callee, not caller). > +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. I don't think this is correct either, we try to figure out where callee saved registers are stored, but these are not the scratch registers, if the scratch registers are needed by the caller then the caller will save them, but the callee will just go ahead and use them. Similarly the DWARF only tells us about callee saved registers. The caller saved registers are now not mentioned in the DWARF as gcc has made sure that no variables are live in these registers. > 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. I'd just like to pick up on the "harmless" here, I agree that it would be "harmless" in the sense that if we did a return in gdb it would be harmless; the register is callee clobbered, the caller either does not care what is in the register after the call, or has code to restore the value that it does care about. From a debugging point of few though, I suspect showing the wrong value might be far from harmless, and if this patch is merged we need to draw attention to the fact that the more "outer" the frame it you're looking at, the more likely call-clobbered registers are to be wrong. Thanks, Andrew ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. 2013-09-20 11:04 ` [PATCH] Always print call-clobbered registers in outer frames Andrew Burgess @ 2013-09-24 12:07 ` Pedro Alves 2013-09-24 12:56 ` Andrew Burgess 0 siblings, 1 reply; 43+ messages in thread From: Pedro Alves @ 2013-09-24 12:07 UTC (permalink / raw) To: Andrew Burgess; +Cc: gdb-patches, Eli Zaretskii, Mark Kettenis On 09/20/2013 12:03 PM, Andrew Burgess wrote: > On 19/09/2013 8:15 PM, Pedro Alves wrote: >> 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 "<optimized out>" all the >> same. (See <https://sourceware.org/ml/gdb-patches/2012-08/msg00787.html>.) >> >> The difference is that with binaries produced by those older GCCs, GDB >> will also print the registers themselves (info registers / p $reg) as >> "<optimized out>". This is confusing. > > I agree with you 100% on this, however, I feel we're merging two > arguments together here. The reason gdb prints <optimised out> is > really because values only support 3 states: available, unavailable, and > optimized-out, we use optimized-out for the DW_CFA_undefined state. > > What we really need is a new state, lets call it not-saved, we don't > necessarily need to have extra state inside the value object to model > this, we might (as in your original patch) be able to derive this state, > but this is a state that a register can be in. Luckily, I already have a patch that does that. :-) >> 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. > > You're right that most targets seem to follow this rule, which seems odd > to me, however I think that the rs600, s390, sh, and tic6x targets > don't, they set the call-clobbered registers to DW_CFA_undefined in > their dwarf2_frame_set_init_reg functions, this seems much more sensible > to me, assuming that call-clobbered registers have not been used seems > .... odd. Okay. Reading more code, and investigating the history behind it convinced me that that is indeed the direction GDB was currently heading. > >> >> 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. > > I really think this is going to confuse users, we're basically saying > that call-clobbered registers are assumed to never be clobbered .... we > might get away with this from very shallow call-stacks, but for very > deep stacks this seems very unlikely, in which case, a user switches to > some outer stack and does "info registers", how does he know which > registers gdb has carefully retrieved and are correct, and which are > just random values fetched from some inner frame? I had toyed with something like Doug suggested. See my other reply to Mark. > My question then is, what makes you believe the inner, possibly > call-clobbered value is right? Nothing, of course. It's just a choice -- either assume it's right, and somehow warn the user it may not be right through some other means; or, assume it's not right, and hide the value from the user. If GDB is wrong, the user can still fetch the value, though it'll take more steps (up+p $reg+down, etc.). It might still be a good idea to provide an easier way to "flatten" the not-saved registers as convenience for that, not sure). (skipping answering some of the other points as I believe I've answered them in my other reply to Mark). >> -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 > > I think here you should say "Most ABIs reserve some registers as > ``scratch'' registers that don't need to be saved by the callee" > (callee, not caller). Indeed. > >> +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. > > I don't think this is correct either, we try to figure out where callee > saved registers are stored, but these are not the scratch registers, if > the scratch registers are needed by the caller then the caller will save > them, but the callee will just go ahead and use them. Similarly the > DWARF only tells us about callee saved registers. The caller saved > registers are now not mentioned in the DWARF as gcc has made sure that > no variables are live in these registers. Hmm. You're right, but only if you see a sequence/connection between the sentences. They're different paragraphs -- the second sentence is mostly preexisting, and I didn't mean to imply the GDB tries to figure out where caller-saved/scratch registers are. I'll rephrase it (in this or the <not saved> patch, whatever we end up with. Thanks. > >> 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. > > I'd just like to pick up on the "harmless" here, I agree that it would > be "harmless" in the sense that if we did a return in gdb it would be > harmless; the register is callee clobbered, the caller either does not > care what is in the register after the call, or has code to restore the > value that it does care about. Right, that's what I was thinking. It'd be better to write that out explicitly. > From a debugging point of few though, I > suspect showing the wrong value might be far from harmless, No sure why. > and if this > patch is merged we need to draw attention to the fact that the more > "outer" the frame it you're looking at, the more likely call-clobbered > registers are to be wrong. Blah, what a rat hole. :-P :-) Please guys, re-confirm to me the direction you prefer seeing GDB follow, even after my reasoning further explained (I'm okay with either approach), and I'll update the corresponding patch's documentation bits with the suggestions you've sent. -- Pedro Alves ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. 2013-09-24 12:07 ` Pedro Alves @ 2013-09-24 12:56 ` Andrew Burgess 2013-09-24 13:43 ` Pedro Alves 0 siblings, 1 reply; 43+ messages in thread From: Andrew Burgess @ 2013-09-24 12:56 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Eli Zaretskii, Mark Kettenis On 24/09/2013 1:06 PM, Pedro Alves wrote: > On 09/20/2013 12:03 PM, Andrew Burgess wrote: >> On 19/09/2013 8:15 PM, Pedro Alves wrote: >>> 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 "<optimized out>" all the >>> same. (See <https://sourceware.org/ml/gdb-patches/2012-08/msg00787.html>.) >>> >>> The difference is that with binaries produced by those older GCCs, GDB >>> will also print the registers themselves (info registers / p $reg) as >>> "<optimized out>". This is confusing. >> >> I agree with you 100% on this, however, I feel we're merging two >> arguments together here. The reason gdb prints <optimised out> is >> really because values only support 3 states: available, unavailable, and >> optimized-out, we use optimized-out for the DW_CFA_undefined state. >> >> What we really need is a new state, lets call it not-saved, we don't >> necessarily need to have extra state inside the value object to model >> this, we might (as in your original patch) be able to derive this state, >> but this is a state that a register can be in. > > Luckily, I already have a patch that does that. :-) > >>> 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. >> >> You're right that most targets seem to follow this rule, which seems odd >> to me, however I think that the rs600, s390, sh, and tic6x targets >> don't, they set the call-clobbered registers to DW_CFA_undefined in >> their dwarf2_frame_set_init_reg functions, this seems much more sensible >> to me, assuming that call-clobbered registers have not been used seems >> .... odd. > > Okay. Reading more code, and investigating the history behind it > convinced me that that is indeed the direction GDB was currently > heading. > >> >>> >>> 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. >> >> I really think this is going to confuse users, we're basically saying >> that call-clobbered registers are assumed to never be clobbered .... we >> might get away with this from very shallow call-stacks, but for very >> deep stacks this seems very unlikely, in which case, a user switches to >> some outer stack and does "info registers", how does he know which >> registers gdb has carefully retrieved and are correct, and which are >> just random values fetched from some inner frame? > > I had toyed with something like Doug suggested. See my > other reply to Mark. > >> My question then is, what makes you believe the inner, possibly >> call-clobbered value is right? > > Nothing, of course. It's just a choice -- either assume it's right, > and somehow warn the user it may not be right through some other means; > or, assume it's not right, and hide the value from the user. If > GDB is wrong, the user can still fetch the value, though it'll take > more steps (up+p $reg+down, etc.). It might still be a good idea to > provide an easier way to "flatten" the not-saved registers as > convenience for that, not sure). I guess the thing I'm struggling with is why would we /ever/ assume the value in an inner frame is correct? Sure, for very shallow stacks on machines with a non-small register set there's a reasonable chance the value is correct, but in any other case I seriously don't see how taking the value from an inner frame is any better than picking a random number. > > (skipping answering some of the other points as I believe I've answered > them in my other reply to Mark). > >>> -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 >> >> I think here you should say "Most ABIs reserve some registers as >> ``scratch'' registers that don't need to be saved by the callee" >> (callee, not caller). > > Indeed. > >> >>> +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. >> >> I don't think this is correct either, we try to figure out where callee >> saved registers are stored, but these are not the scratch registers, if >> the scratch registers are needed by the caller then the caller will save >> them, but the callee will just go ahead and use them. Similarly the >> DWARF only tells us about callee saved registers. The caller saved >> registers are now not mentioned in the DWARF as gcc has made sure that >> no variables are live in these registers. > > Hmm. You're right, but only if you see a sequence/connection between > the sentences. They're different paragraphs -- the second sentence is > mostly preexisting, and I didn't mean to imply the GDB tries to figure > out where caller-saved/scratch registers are. I'll rephrase it (in > this or the <not saved> patch, whatever we end up with. Thanks. > >> >>> 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. >> >> I'd just like to pick up on the "harmless" here, I agree that it would >> be "harmless" in the sense that if we did a return in gdb it would be >> harmless; the register is callee clobbered, the caller either does not >> care what is in the register after the call, or has code to restore the >> value that it does care about. > > Right, that's what I was thinking. It'd be better to write that out > explicitly. > >> From a debugging point of few though, I >> suspect showing the wrong value might be far from harmless, > > No sure why. I think that if you print it "they" (users) will use it, assuming it's correct. Given that I don't think it's correct I think we're likely to be giving users miss-information. Are there any other examples within gdb that you can think of (I can't) where we print information that we know is very likely wrong? (Obviously I mean deliberately here rather than being mislead by invalid debug information). > >> and if this >> patch is merged we need to draw attention to the fact that the more >> "outer" the frame it you're looking at, the more likely call-clobbered >> registers are to be wrong. > > Blah, what a rat hole. :-P :-) > > Please guys, re-confirm to me the direction you prefer seeing > GDB follow, even after my reasoning further explained (I'm okay > with either approach), and I'll update the corresponding patch's > documentation bits with the suggestions you've sent. I think the original "<not-saved>" patch was great and a good improvement on where we are right now, I'd much rather see that merged than the "values-from-inner-frame" patch. Thanks for your continued effort :) Andrew ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. 2013-09-24 12:56 ` Andrew Burgess @ 2013-09-24 13:43 ` Pedro Alves 2013-09-24 15:18 ` Andrew Burgess 0 siblings, 1 reply; 43+ messages in thread From: Pedro Alves @ 2013-09-24 13:43 UTC (permalink / raw) To: Andrew Burgess; +Cc: gdb-patches, Eli Zaretskii, Mark Kettenis On 09/24/2013 01:56 PM, Andrew Burgess wrote: >>> My question then is, what makes you believe the inner, possibly >>> call-clobbered value is right? >> >> Nothing, of course. It's just a choice -- either assume it's right, >> and somehow warn the user it may not be right through some other means; >> or, assume it's not right, and hide the value from the user. If >> GDB is wrong, the user can still fetch the value, though it'll take >> more steps (up+p $reg+down, etc.). It might still be a good idea to >> provide an easier way to "flatten" the not-saved registers as >> convenience for that, not sure). > > I guess the thing I'm struggling with is why would we /ever/ assume the > value in an inner frame is correct? "correct" depends on the definition. If we defined registers in frame > 0 the way I suggested in response to Mark, then they always are. Doing otherwise means assuming we know the ABI the outer and inner frames agreed on. There are a number of ways to get that wrong, like with assembly code, or even probably with gcc attributes or some JITs, meaning GDB will hide the value from the user behind <not saved>, when it should not. Granted, not the _usual_ scenario, but I bet it's real. Yeah, can always be fixed in the unwind/debug itself. > Sure, for very shallow stacks on > machines with a non-small register set there's a reasonable chance the > value is correct, but in any other case I seriously don't see how taking > the value from an inner frame is any better than picking a random number. Again, it's a matter of definition -- "taking a value from an inner frame" just meant "if the unwind info doesn't say the register was saved, then assume that when the inner function returned, the register would still hold that value". > I think that if you print it "they" (users) will use it, assuming it's > correct. Given that I don't think it's correct I think we're likely to > be giving users miss-information. And here is where I'm wondering what sort of use do you think they'll be giving them. :-) GDB will still print <optimized out> for variables that happened to be live in such registers at the time of the call. If the functions involved are C or even higher-level language code, nothing changes, because indeed if the register is supposedly call-clobbered nothing in the caller will be expecting to find the old register value still in the register. But, when you're peeking into machine register values in the debugger you're going deeper than that. You're probably looking into mapping them to a disassembly of the machine code. In my mind, at this level, it's not strictly correct for GDB to assume any particular ABI -- best be driven by unwind info, and if the unwind info doesn't specify where the register was saved, at least give the user some useful value, rather than forcing her to go hunt for it in inner frames. (Again, I think both perspectives are reasonable. But if the always-print-registers route is harder to explain to other GDB developers, then that does hint that users wouldn't understand it either, which does favor the <not saved> route.) -- Pedro Alves ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. 2013-09-24 13:43 ` Pedro Alves @ 2013-09-24 15:18 ` Andrew Burgess 2013-09-24 19:36 ` Pedro Alves 0 siblings, 1 reply; 43+ messages in thread From: Andrew Burgess @ 2013-09-24 15:18 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Eli Zaretskii, Mark Kettenis On 24/09/2013 2:43 PM, Pedro Alves wrote: > On 09/24/2013 01:56 PM, Andrew Burgess wrote: > >>>> My question then is, what makes you believe the inner, possibly >>>> call-clobbered value is right? >>> >>> Nothing, of course. It's just a choice -- either assume it's right, >>> and somehow warn the user it may not be right through some other means; >>> or, assume it's not right, and hide the value from the user. If >>> GDB is wrong, the user can still fetch the value, though it'll take >>> more steps (up+p $reg+down, etc.). It might still be a good idea to >>> provide an easier way to "flatten" the not-saved registers as >>> convenience for that, not sure). >> >> I guess the thing I'm struggling with is why would we /ever/ assume the >> value in an inner frame is correct? > > "correct" depends on the definition. If we defined registers in > frame > 0 the way I suggested in response to Mark, then they always are. I've included the definition here for reference: "The values of registers in the outer frame, are defined as being the values the registers would have if the inner frame was to return immediately, respecting relevant ABI rules." I dislike that definition. I'd prefer: "The values of registers in the outer frame, are defined as being the value that was in that register at the time of the call to the inner frame. Sometimes this value is not available in which case the value will be displayed as <not-saved>." My real concern with your definition is that I don't believe it's correct! If you did an "immediate" return then even those register that are callee saved would not be restored. I think you need to expand your definition, otherwise it would sound like we don't do register unwinding at all. Assuming that we do perform register unwinding and you expand your definition, we would then have a split register set, one half looking backwards, one half looking forwards; we have the registers that we unwind, these display the value at the time of the call, and the set looking forward, these hold the value from an inner frame. My expectation of walking back up the stack is that I'm walking back into history, not walking into the future; I want to see the stack frame as it _was_ at the time of the call, not how it might be at the time of a return (or if we force a return, how it will be). But this is just my opinion, others might use gdb differently and have different expectations. > Doing otherwise means assuming we know the ABI the outer and inner > frames agreed on. I agree ... and disagree with this statement :) Right now on x86-64 we don't define a dwarf2_frame_set_init_reg function, nor in the prologue scanning amd64_frame_prev_register function do we ever return frame_unwind_got_optimized. gdb basically has no idea which registers are callee saved, and which are callee clobbered. I claim that right now, on x86-64 the behaviour we have is the behaviour as defined by your definition of a register in an outer frame. I'm claiming that you'll not see <optimized-out> (or what would be <not-saved>) for a register right now UNLESS you specifically craft some dwarf to mark a register as undefined. The problem is that (by my reading of the DWARF standard) the compiler should be marking callee clobbered registers as undefined (this is based on appendix D.6 Call Frame Information Example from DWARF4), however, gcc, at least the versions I have to hand, don't do this. To work around this, on some targets, we use the dwarf2_frame_set_init_reg function to teach gdb about the ABI, we now /do/ see registers as not-saved. So, back to your statement that to mark registers as not-saved requires gdb to know the ABI, you are correct that some targets do have the ABI baked in, but this is only to work around a lack of DWARF from the compiler. I guess, looking the this issue again, I'd suggest my argument is this, if the DWARF or the prologue scanner has gone to the effort of saying "this register is not saved" then we should display it as such, your patch seems (to me) to be ignoring this and printing some other value instead. If a particular target (x86-64 say) wants the behaviour you've defined then, hey, we already have that behaviour, we just don't define a default DWARF state, and don't have the prologue scanner mark any registers as not-saved. No patch required. If we do apply your (value from inner frame) patch then it feels like we're taking away the option for other targets to support a not-saved state for registers. > There are a number of ways to get that wrong, like > with assembly code, or even probably with gcc attributes or some JITs, > meaning GDB will hide the value from the user behind <not saved>, when > it should not. Granted, not the _usual_ scenario, but I bet it's real. > Yeah, can always be fixed in the unwind/debug itself. I agree that it would be nice if the DWARF code didn't need to have the ABI wired in; but that's something to take up with the gcc folk I guess. The prologue scanner code is harder, there's always going to be some aspect of ABI awareness within that code, but generally that should be the mechanism of last resort so I think we can forgive that a more than other code. > >> Sure, for very shallow stacks on >> machines with a non-small register set there's a reasonable chance the >> value is correct, but in any other case I seriously don't see how taking >> the value from an inner frame is any better than picking a random number. > > Again, it's a matter of definition -- "taking a value from an > inner frame" just meant "if the unwind info doesn't say the register was > saved, then assume that when the inner function returned, the register > would still hold that value". > >> I think that if you print it "they" (users) will use it, assuming it's >> correct. Given that I don't think it's correct I think we're likely to >> be giving users miss-information. > > And here is where I'm wondering what sort of use do you think they'll > be giving them. :-) GDB will still print <optimized out> for variables > that happened to be live in such registers at the time of the call. If the > functions involved are C or even higher-level language code, nothing > changes, because indeed if the register is supposedly call-clobbered > nothing in the caller will be expecting to find the old register value > still in the register. But, when you're peeking into machine register values > in the debugger you're going deeper than that. You're probably looking into > mapping them to a disassembly of the machine code. In my mind, at this > level, it's not strictly correct for GDB to assume any particular ABI -- best > be driven by unwind info, and if the unwind info doesn't specify where the > register was saved, at least give the user some useful value, rather than > forcing her to go hunt for it in inner frames. Given I'm expecting a view of the frame as it was, the value is, in general not going to be correct (for me), and so is not useful. I'd rather not see it. > (Again, I think both perspectives are reasonable. But if the > always-print-registers route is harder to explain to other GDB developers, > then that does hint that users wouldn't understand it either, which does > favor the <not saved> route.) ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. 2013-09-24 15:18 ` Andrew Burgess @ 2013-09-24 19:36 ` Pedro Alves 2013-09-24 23:22 ` Andrew Burgess 0 siblings, 1 reply; 43+ messages in thread From: Pedro Alves @ 2013-09-24 19:36 UTC (permalink / raw) To: Andrew Burgess; +Cc: gdb-patches, Eli Zaretskii, Mark Kettenis On 09/24/2013 04:18 PM, Andrew Burgess wrote: > On 24/09/2013 2:43 PM, Pedro Alves wrote: >> On 09/24/2013 01:56 PM, Andrew Burgess wrote: >> >>>>> My question then is, what makes you believe the inner, possibly >>>>> call-clobbered value is right? >>>> >>>> Nothing, of course. It's just a choice -- either assume it's right, >>>> and somehow warn the user it may not be right through some other means; >>>> or, assume it's not right, and hide the value from the user. If >>>> GDB is wrong, the user can still fetch the value, though it'll take >>>> more steps (up+p $reg+down, etc.). It might still be a good idea to >>>> provide an easier way to "flatten" the not-saved registers as >>>> convenience for that, not sure). >>> >>> I guess the thing I'm struggling with is why would we /ever/ assume the >>> value in an inner frame is correct? >> >> "correct" depends on the definition. If we defined registers in >> frame > 0 the way I suggested in response to Mark, then they always are. > > I've included the definition here for reference: > > "The values of registers in the outer frame, are defined as > being the values the registers would have if the inner frame > was to return immediately, respecting relevant ABI rules." > > I dislike that definition. I'd prefer: > > "The values of registers in the outer frame, are defined as > being the value that was in that register at the time of the > call to the inner frame. Sometimes this value is not available > in which case the value will be displayed as <not-saved>." > > My real concern with your definition is that I don't believe it's > correct! If you did an "immediate" return then even those register that > are callee saved would not be restored. No, no, no, it's correct. That's what the "respecting relevant ABI rules" meant -- IOW, as if the inner frame actually ran its epilogue. Note that <not-saved> definition isn't correct for at least the PC! (as the program ran through the outer frame, the PC pointed to the actual call instruction just before the call, and then it switched to point to the the call destination, well, just right after the call. But, the PC _never_ pointed to the call's return address in the outer frame. Yet that's what we present in info reg / p $pc in outer frames... IOW, we present the PC in the same way I was suggesting we present the other registers. == more consistency.) And, in some ports, that definition is not correct for the stack pointer either. > I think you need to expand your > definition, otherwise it would sound like we don't do register unwinding > at all. Assuming that we do perform register unwinding and you expand > your definition, we would then have a split register set, one half > looking backwards, one half looking forwards; we have the registers that > we unwind, these display the value at the time of the call, and the set > looking forward, these hold the value from an inner frame. Only if you choose to look at it that way. Maybe I'm not being clear enough. Another way to say it would be, perhaps, that the value of a register in the outer frame is defined as being the value that the inner function would leave in it, were it to immediately run its epilogue and return. > > My expectation of walking back up the stack is that I'm walking back > into history, not walking into the future; I want to see the stack frame > as it _was_ at the time of the call, not how it might be at the time of > a return (or if we force a return, how it will be). So what's your opinion on how we present the PC register in outer frames? Because it's not what you're suggesting. > But this is just my > opinion, others might use gdb differently and have different expectations. > >> Doing otherwise means assuming we know the ABI the outer and inner >> frames agreed on. > > I agree ... and disagree with this statement :) > > Right now on x86-64 we don't define a dwarf2_frame_set_init_reg > function, nor in the prologue scanning amd64_frame_prev_register > function do we ever return frame_unwind_got_optimized. gdb basically > has no idea which registers are callee saved, and which are callee > clobbered. Did you see the patch I sent to Mark, that does just that? > I claim that right now, on x86-64 the behaviour we have is the behaviour > as defined by your definition of a register in an outer frame. I'm > claiming that you'll not see <optimized-out> (or what would be > <not-saved>) for a register right now UNLESS you specifically craft some > dwarf to mark a register as undefined. Right. > The problem is that (by my reading of the DWARF standard) the compiler > should be marking callee clobbered registers as undefined (this is based > on appendix D.6 Call Frame Information Example from DWARF4), however, > gcc, at least the versions I have to hand, don't do this. It also says: "The default rule for all columns before interpretation of the initial instructions is the undefined rule. However, an ABI authoring body or ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a compilation system authoring body may specify an alternate default ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value for any or all columns." And see: http://gcc.gnu.org/ml/gcc/2006-12/msg00293.html And: http://gcc.gnu.org/ml/gcc/2006-12/msg00312.html AFAICS, that patch is in the tree. > To work > around this, on some targets, we use the dwarf2_frame_set_init_reg > function to teach gdb about the ABI, we now /do/ see registers as not-saved. > > So, back to your statement that to mark registers as not-saved requires > gdb to know the ABI, you are correct that some targets do have the ABI > baked in, but this is only to work around a lack of DWARF from the compiler. I think calling it "lack" or not that depends on what gcc, being the "compilation system authoring body" is considering to be the default. > I guess, looking the this issue again, I'd suggest my argument is this, > if the DWARF or the prologue scanner has gone to the effort of saying > "this register is not saved" then we should display it as such, your > patch seems (to me) to be ignoring this and printing some other value > instead. Yes. If the variable doesn't actually exist, the compiler doesn't actually emit that "this register is not saved" info at all, IIUC. The only reason the compiler emitted that was to say that the "variable lived in this register, but the register is gone". IOW, it's info meant to be used at the C/higher-level language/variable level. IIUC, there was never a time when the compiler emitted info saying "all these registers x,y,z are undefined (because they're ABI call-clobbered)" in all functions. > If a particular target (x86-64 say) wants the behaviour you've > defined then, hey, we already have that behaviour, we just don't define > a default DWARF state, and don't have the prologue scanner mark any > registers as not-saved. No patch required. If we do apply your (value > from inner frame) patch then it feels like we're taking away the option > for other targets to support a not-saved state for registers. Well, yes and no. If we followed my definition of outer frame registers, the registers value of <not-saved> wouldn't ever need to exist, by definition, but, we would instead show "[not saved]" or same such other auxiliary, out-of-band info in "info registers" output -- and that info would be extracted from GDB's own knowledge of the ABI and from the debug/unwind info. Note that the "no patch required" above isn't strictly true, as your paragraph actually argues _against_ my AMD64 patch at: <https://sourceware.org/ml/gdb-patches/2013-09/msg00848.html>, and, likewise argues that rs6000, s390, sh and tic6x are actually wrong in defaulting some registers to DWARF2_FRAME_REG_UNDEFINED. > >> There are a number of ways to get that wrong, like >> with assembly code, or even probably with gcc attributes or some JITs, >> meaning GDB will hide the value from the user behind <not saved>, when >> it should not. Granted, not the _usual_ scenario, but I bet it's real. >> Yeah, can always be fixed in the unwind/debug itself. > > I agree that it would be nice if the DWARF code didn't need to have the > ABI wired in; but that's something to take up with the gcc folk I guess. > The prologue scanner code is harder, there's always going to be some > aspect of ABI awareness within that code, but generally that should be > the mechanism of last resort so I think we can forgive that a more than > other code. Yeah. But what does "forgive" actually mean? I'm currently inclined to never make the prologue scanners assume not-saved registers are clobbered (as in, make them default to same_value, like x86 scanners do currently). >>> Sure, for very shallow stacks on >>> machines with a non-small register set there's a reasonable chance the >>> value is correct, but in any other case I seriously don't see how taking >>> the value from an inner frame is any better than picking a random number. >> >> Again, it's a matter of definition -- "taking a value from an >> inner frame" just meant "if the unwind info doesn't say the register was >> saved, then assume that when the inner function returned, the register >> would still hold that value". >> >>> I think that if you print it "they" (users) will use it, assuming it's >>> correct. Given that I don't think it's correct I think we're likely to >>> be giving users miss-information. >> >> And here is where I'm wondering what sort of use do you think they'll >> be giving them. :-) GDB will still print <optimized out> for variables >> that happened to be live in such registers at the time of the call. If the >> functions involved are C or even higher-level language code, nothing >> changes, because indeed if the register is supposedly call-clobbered >> nothing in the caller will be expecting to find the old register value >> still in the register. But, when you're peeking into machine register values >> in the debugger you're going deeper than that. You're probably looking into >> mapping them to a disassembly of the machine code. In my mind, at this >> level, it's not strictly correct for GDB to assume any particular ABI -- best >> be driven by unwind info, and if the unwind info doesn't specify where the >> register was saved, at least give the user some useful value, rather than >> forcing her to go hunt for it in inner frames. > > Given I'm expecting a view of the frame as it was, the value is, in > general not going to be correct (for me), and so is not useful. I'd > rather not see it. > >> (Again, I think both perspectives are reasonable. But if the >> always-print-registers route is harder to explain to other GDB developers, >> then that does hint that users wouldn't understand it either, which does >> favor the <not saved> route.) (I wonder if what we should have is some kind of switch or knob that allows getting _both_ behaviors from GDB...) -- Pedro Alves ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. 2013-09-24 19:36 ` Pedro Alves @ 2013-09-24 23:22 ` Andrew Burgess 2013-10-02 16:05 ` Pedro Alves 0 siblings, 1 reply; 43+ messages in thread From: Andrew Burgess @ 2013-09-24 23:22 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Eli Zaretskii, Mark Kettenis On 24/09/2013 8:36 PM, Pedro Alves wrote: > On 09/24/2013 04:18 PM, Andrew Burgess wrote: >> On 24/09/2013 2:43 PM, Pedro Alves wrote: >>> On 09/24/2013 01:56 PM, Andrew Burgess wrote: >>> >>>>>> My question then is, what makes you believe the inner, possibly >>>>>> call-clobbered value is right? >>>>> >>>>> Nothing, of course. It's just a choice -- either assume it's right, >>>>> and somehow warn the user it may not be right through some other means; >>>>> or, assume it's not right, and hide the value from the user. If >>>>> GDB is wrong, the user can still fetch the value, though it'll take >>>>> more steps (up+p $reg+down, etc.). It might still be a good idea to >>>>> provide an easier way to "flatten" the not-saved registers as >>>>> convenience for that, not sure). >>>> >>>> I guess the thing I'm struggling with is why would we /ever/ assume the >>>> value in an inner frame is correct? >>> >>> "correct" depends on the definition. If we defined registers in >>> frame > 0 the way I suggested in response to Mark, then they always are. >> >> I've included the definition here for reference: >> >> "The values of registers in the outer frame, are defined as >> being the values the registers would have if the inner frame >> was to return immediately, respecting relevant ABI rules." >> >> I dislike that definition. I'd prefer: >> >> "The values of registers in the outer frame, are defined as >> being the value that was in that register at the time of the >> call to the inner frame. Sometimes this value is not available >> in which case the value will be displayed as <not-saved>." >> >> My real concern with your definition is that I don't believe it's >> correct! If you did an "immediate" return then even those register that >> are callee saved would not be restored. > > No, no, no, it's correct. That's what the "respecting relevant > ABI rules" meant -- IOW, as if the inner frame actually ran its > epilogue. > > Note that <not-saved> definition isn't correct for at least the PC! > (as the program ran through the outer frame, the PC pointed to the actual > call instruction just before the call, and then it switched to point to > the the call destination, well, just right after the call. But, the PC _never_ > pointed to the call's return address in the outer frame. Yet that's > what we present in info reg / p $pc in outer frames... IOW, we present > the PC in the same way I was suggesting we present the other > registers. == more consistency.) OK, I accept the point you make here. But I still don't think this is the right patch to apply .... > And, in some ports, that definition is not correct for the stack > pointer either. > >> I think you need to expand your >> definition, otherwise it would sound like we don't do register unwinding >> at all. Assuming that we do perform register unwinding and you expand >> your definition, we would then have a split register set, one half >> looking backwards, one half looking forwards; we have the registers that >> we unwind, these display the value at the time of the call, and the set >> looking forward, these hold the value from an inner frame. > > Only if you choose to look at it that way. Maybe I'm not being clear > enough. Another way to say it would be, perhaps, that > the value of a register in the outer frame is defined as being > the value that the inner function would leave in it, were it to > immediately run its epilogue and return. No, I do understand what you're suggesting I just think it's the wrong thing to do... but if I've not convinced you then I guess my argument must be pretty weak, and your point about the PC is a good example of where I'm clearly wrong, still.... > >> >> My expectation of walking back up the stack is that I'm walking back >> into history, not walking into the future; I want to see the stack frame >> as it _was_ at the time of the call, not how it might be at the time of >> a return (or if we force a return, how it will be). > > So what's your opinion on how we present the PC register in outer frames? > Because it's not what you're suggesting. Honestly, I've always thought it would be nice if the unwound PC pointed at the call instruction ... I've always just assumed that was "hard" and lived with what we have. I didn't think about that when I made my previous statements otherwise I'd have pre-emptively added an exception for the PC, doing so now would seem childish :) > >> But this is just my >> opinion, others might use gdb differently and have different expectations. >> >>> Doing otherwise means assuming we know the ABI the outer and inner >>> frames agreed on. >> >> I agree ... and disagree with this statement :) >> >> Right now on x86-64 we don't define a dwarf2_frame_set_init_reg >> function, nor in the prologue scanning amd64_frame_prev_register >> function do we ever return frame_unwind_got_optimized. gdb basically >> has no idea which registers are callee saved, and which are callee >> clobbered. > > Did you see the patch I sent to Mark, that does just that? Indeed. Looked good to me, except ... see my comments below. > >> I claim that right now, on x86-64 the behaviour we have is the behaviour >> as defined by your definition of a register in an outer frame. I'm >> claiming that you'll not see <optimized-out> (or what would be >> <not-saved>) for a register right now UNLESS you specifically craft some >> dwarf to mark a register as undefined. > > Right. > >> The problem is that (by my reading of the DWARF standard) the compiler >> should be marking callee clobbered registers as undefined (this is based >> on appendix D.6 Call Frame Information Example from DWARF4), however, >> gcc, at least the versions I have to hand, don't do this. > > It also says: > > "The default rule for all columns before interpretation of the initial > instructions is the undefined rule. However, an ABI authoring body or > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > a compilation system authoring body may specify an alternate default > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > value for any or all columns." > > And see: > http://gcc.gnu.org/ml/gcc/2006-12/msg00293.html > > And: > http://gcc.gnu.org/ml/gcc/2006-12/msg00312.html > > AFAICS, that patch is in the tree. OK, so that would seem to suggest that the patch you posted for Mark is correct and should go in, at least, when debugging a gcc binary, except, see comments below.... > >> To work >> around this, on some targets, we use the dwarf2_frame_set_init_reg >> function to teach gdb about the ABI, we now /do/ see registers as not-saved. >> >> So, back to your statement that to mark registers as not-saved requires >> gdb to know the ABI, you are correct that some targets do have the ABI >> baked in, but this is only to work around a lack of DWARF from the compiler. > > I think calling it "lack" or not that depends on what gcc, being > the "compilation system authoring body" is considering to be > the default. You're right "lack" was a bad choice of words and indicated a "lack" of understanding on my part. Apologies. > >> I guess, looking the this issue again, I'd suggest my argument is this, >> if the DWARF or the prologue scanner has gone to the effort of saying >> "this register is not saved" then we should display it as such, your >> patch seems (to me) to be ignoring this and printing some other value >> instead. > > Yes. If the variable doesn't actually exist, the compiler doesn't > actually emit that "this register is not saved" info at all, IIUC. > The only reason the compiler emitted that was to say that the > "variable lived in this register, but the register is gone". IOW, > it's info meant to be used at the C/higher-level language/variable > level. IIUC, there was never a time when the compiler emitted info > saying "all these registers x,y,z are undefined (because they're > ABI call-clobbered)" in all functions. > >> If a particular target (x86-64 say) wants the behaviour you've >> defined then, hey, we already have that behaviour, we just don't define >> a default DWARF state, and don't have the prologue scanner mark any >> registers as not-saved. No patch required. If we do apply your (value >> from inner frame) patch then it feels like we're taking away the option >> for other targets to support a not-saved state for registers. > > Well, yes and no. If we followed my definition of outer frame registers, > the registers value of <not-saved> wouldn't ever need to exist, by > definition, but, we would instead show "[not saved]" > or same such other auxiliary, out-of-band info in "info registers" > output -- and that info would be extracted from GDB's own knowledge > of the ABI and from the debug/unwind info. > > Note that the "no patch required" above isn't strictly true, as your > paragraph actually argues _against_ my AMD64 patch at: > <https://sourceware.org/ml/gdb-patches/2013-09/msg00848.html>, > and, likewise argues that rs6000, s390, sh and tic6x are actually > wrong in defaulting some registers to DWARF2_FRAME_REG_UNDEFINED. I wasn't arguing the rs6000, etc are wrong, rather that different targets might prefer different behaviours, applying the inner-value patch I think takes away that choice. If what we want for x86-64 is the inner-frame behaviour then could we not just leave things as they are? The only thing we loose is the additional "not saved" out-of-band information in "info registers", but we maintain the behaviour of the dwarf undefined state for any targets that do want to make use of it. [ ASIDE: The "not-saved" information could easily be added back in by specialising the "info register" code for x86-64, a lot of other targets already specialise. ] > >> >>> There are a number of ways to get that wrong, like >>> with assembly code, or even probably with gcc attributes or some JITs, >>> meaning GDB will hide the value from the user behind <not saved>, when >>> it should not. Granted, not the _usual_ scenario, but I bet it's real. >>> Yeah, can always be fixed in the unwind/debug itself. >> >> I agree that it would be nice if the DWARF code didn't need to have the >> ABI wired in; but that's something to take up with the gcc folk I guess. >> The prologue scanner code is harder, there's always going to be some >> aspect of ABI awareness within that code, but generally that should be >> the mechanism of last resort so I think we can forgive that a more than >> other code. > > Yeah. But what does "forgive" actually mean? I'm currently inclined > to never make the prologue scanners assume not-saved registers are > clobbered (as in, make them default to same_value, like x86 scanners > do currently). By "forgive" I simply meant that the prologue scanners are one of the places where ABI specific knowledge is most likely to be written into gdb, and this is probably one of the most acceptable places. I think the behaviour of the scanners should really be what makes most sense to each target, to me marking callee clobbered registers undefined makes more sense... but if the inner-value patch is applied it would make little difference if we use same-value or undefined as they'll have the same result ... right? > >>>> Sure, for very shallow stacks on >>>> machines with a non-small register set there's a reasonable chance the >>>> value is correct, but in any other case I seriously don't see how taking >>>> the value from an inner frame is any better than picking a random number. >>> >>> Again, it's a matter of definition -- "taking a value from an >>> inner frame" just meant "if the unwind info doesn't say the register was >>> saved, then assume that when the inner function returned, the register >>> would still hold that value". >>> >>>> I think that if you print it "they" (users) will use it, assuming it's >>>> correct. Given that I don't think it's correct I think we're likely to >>>> be giving users miss-information. >>> >>> And here is where I'm wondering what sort of use do you think they'll >>> be giving them. :-) GDB will still print <optimized out> for variables >>> that happened to be live in such registers at the time of the call. If the >>> functions involved are C or even higher-level language code, nothing >>> changes, because indeed if the register is supposedly call-clobbered >>> nothing in the caller will be expecting to find the old register value >>> still in the register. But, when you're peeking into machine register values >>> in the debugger you're going deeper than that. You're probably looking into >>> mapping them to a disassembly of the machine code. In my mind, at this >>> level, it's not strictly correct for GDB to assume any particular ABI -- best >>> be driven by unwind info, and if the unwind info doesn't specify where the >>> register was saved, at least give the user some useful value, rather than >>> forcing her to go hunt for it in inner frames. >> >> Given I'm expecting a view of the frame as it was, the value is, in >> general not going to be correct (for me), and so is not useful. I'd >> rather not see it. >> >>> (Again, I think both perspectives are reasonable. But if the >>> always-print-registers route is harder to explain to other GDB developers, >>> then that does hint that users wouldn't understand it either, which does >>> favor the <not saved> route.) > > (I wonder if what we should have is some kind of switch or knob that > allows getting _both_ behaviors from GDB...) That might indeed be the only way to make us both happy :) Cheers, Andrew ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. 2013-09-24 23:22 ` Andrew Burgess @ 2013-10-02 16:05 ` Pedro Alves 2013-10-02 19:07 ` Doug Evans 0 siblings, 1 reply; 43+ messages in thread From: Pedro Alves @ 2013-10-02 16:05 UTC (permalink / raw) To: Andrew Burgess; +Cc: gdb-patches, Eli Zaretskii, Mark Kettenis OK, I've given this whole thing some time for comments from others. As I'm not hearing any support for the point of view I've presented in the follow up discussions of this patch, I'll just forget about it, and I'll go apply the original <not saved> one instead. That one doesn't really change GDB's behavior, other than making output a little clearer. We can always reconsider the other idea if we want to. -- Pedro Alves ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. 2013-10-02 16:05 ` Pedro Alves @ 2013-10-02 19:07 ` Doug Evans 0 siblings, 0 replies; 43+ messages in thread From: Doug Evans @ 2013-10-02 19:07 UTC (permalink / raw) To: Pedro Alves; +Cc: Andrew Burgess, gdb-patches, Eli Zaretskii, Mark Kettenis Pedro Alves writes: > OK, I've given this whole thing some time for comments > from others. > > As I'm not hearing any support for the point of view I've > presented in the follow up discussions of this patch, I'll > just forget about it, and I'll go apply the original <not saved> > one instead. That one doesn't really change GDB's behavior, > other than making output a little clearer. > We can always reconsider the other idea if we want to. Ok by me. ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) 2013-09-19 19:15 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Pedro Alves ` (3 preceding siblings ...) 2013-09-20 11:04 ` [PATCH] Always print call-clobbered registers in outer frames Andrew Burgess @ 2013-09-20 12:28 ` Mark Kettenis 2013-09-24 12:06 ` [PATCH] Always print call-clobbered registers in outer frames Pedro Alves 4 siblings, 1 reply; 43+ messages in thread From: Mark Kettenis @ 2013-09-20 12:28 UTC (permalink / raw) To: palves; +Cc: gdb-patches, eliz, mark.kettenis, aburgess > Date: Thu, 19 Sep 2013 20:15:20 +0100 > From: Pedro Alves <palves@redhat.com> > > On 09/19/2013 05:58 PM, Pedro Alves wrote: > > > Now, GDB itself could just assume that call-clobbered registers > > are always <not saved> 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 "<optimized out>" all the > same. (See <https://sourceware.org/ml/gdb-patches/2012-08/msg00787.html>.) > > The difference is that with binaries produced by those older GCCs, GDB > will also print the registers themselves (info registers / p $reg) as > "<optimized out>". 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=<optimized out>, operand1=-2401054115373400575, operand2=<optimized out>) > (gdb) info registers > rax 0x323d7b35b0 215779849648 > rbx 0xdeadbe00deadbe01 -2401054115373400575 > rcx <optimized out> > rdx 0xdeadbe04deadbe05 -2401054098193531387 > rsi <optimized out> > rdi <optimized out> > 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 <int_param_single_reg_loc+10> > 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 <breakpt> > 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=<optimized out>, operand1=-2401054115373400575, operand2=<optimized out>) > (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 <int_param_single_reg_loc+10> > 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 <int_param_single_reg_loc+10> > 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. I strongly disagree with this change. I think it is useful to show that rgeisters have not been saved. If you want to look at their value anyway, you can always go down (or up) the stack and chase the value of the register yourself. I also think it doesn't make sense for the varobj subsystem to reimplement bits of the unwinder subsystem. If newer GCC versions are even less explicit about saving or not saving registers than older versions, we should probably improve the _dwarf2_frame_init_reg() implementations to indicate properly which registers are caller-saved and which registers are callee-saved. ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH] Always print call-clobbered registers in outer frames. 2013-09-20 12:28 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Mark Kettenis @ 2013-09-24 12:06 ` Pedro Alves 0 siblings, 0 replies; 43+ messages in thread From: Pedro Alves @ 2013-09-24 12:06 UTC (permalink / raw) To: Mark Kettenis; +Cc: gdb-patches, eliz, aburgess On 09/20/2013 01:27 PM, Mark Kettenis wrote: > I strongly disagree with this change. Ack. My thought process was that it was not that much different from defining the value of PC in frames other than #0 to be the return address, not the value the PC had _before_ the call. If we went further and defined all register values in that direction, things would all be consistent. Something like: The values of registers in the outer frame, are defined as being the values the registers would have if the inner frame was to return immediately, respecting relevant ABI rules. IOW, call-clobbered registers would show whatever value's current in the inner frame, and callee-saved registers would show the saved values. I think _both_ definitions are reasonable, though this one seemed a little more consistent to me. > I think it is useful to show that rgeisters have not been saved. Right, but that could also be done in some other way. I toyed with something like Doug suggested. That is, make "info reg" indicate whether the register was actually saved or GDB assumed same_value. Something like: (gdb) i reg rax 0x1 1 [not saved] rbx 0x0 0 rcx 0x2 2 [not saved] rdx 0x3 3 [not saved] rsi 0x4 4 [not saved] rdi 0x5 5 [not saved] rbp 0x7fffffffda70 0x7fffffffda70 rsp 0x7fffffffda40 0x7fffffffda40 So GDB would still "flatten" the registers, and "p $rax" would still print some number, and the user could tell that the registers' values might no longer be the values the frame had when it called out the inner frame. > If you want to look at their > value anyway, you can always go down (or up) the stack and chase the > value of the register yourself. Of course. Though not very convenient. If that's the direction we're heading, and if GDB gets the saved/not-saved wrong, that may be a nuisance. It might be useful to have shorthand for that (though admittedly the use cases will probably trigger so seldom that we may never hear requests for it). > > I also think it doesn't make sense for the varobj subsystem to > reimplement bits of the unwinder subsystem. You mean value machinery, I guess. I wouldn't say reimplement. The idea was to still leave the unwinder treating not-saved as is, and only hide that at the user-facing presentation layer, so that anything that might need to rely on the unwinder machinery getting info about registers at inner frame call time, wouldn't get possibly no-longer-correct register values unless it wanted to. (IOW, we could move the value_of_register function to stack.c and call it part of the unwinder machinery as well.) > If newer GCC versions are even less explicit about saving or not > saving registers than older versions, we should probably improve the > _dwarf2_frame_init_reg() implementations to indicate properly which > registers are caller-saved and which registers are callee-saved. So... I tried that out for AMD64, on top of the <not-saved> patch. (top-gdb) i reg rax 0x5e60ff 6185215 rbx 0x0 0 rcx 0x323d435bf0 215776189424 rdx 0x7fffffffda50 140737488345680 rsi 0x0 0 rdi 0x7fffffffda50 140737488345680 rbp 0x7fffffffd9a0 0x7fffffffd9a0 rsp 0x7fffffffd860 0x7fffffffd860 r8 0x70 112 r9 0x100000 1048576 r10 0x8 8 r11 0x246 582 r12 0x45aed0 4566736 r13 0x7fffffffdb50 140737488345936 r14 0x0 0 r15 0x0 0 rip 0x5e6114 0x5e6114 <captured_main+21> eflags 0x206 [ PF IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (top-gdb) up #1 0x00000000005e3876 in catch_errors (func=0x5e60ff <captured_main>, func_args=0x7fffffffda50, errstring=0x8a6194 "", mask=RETURN_MASK_ALL) at ../../src/gdb/exceptions.c:524 524 val = func (func_args); (top-gdb) i reg rax <not saved> rbx 0x0 0 rcx <not saved> rdx <not saved> rsi <not saved> rdi <not saved> rbp 0x7fffffffda10 0x7fffffffda10 rsp 0x7fffffffd9b0 0x7fffffffd9b0 r8 <not saved> r9 <not saved> r10 <not saved> r11 <not saved> r12 0x45aed0 4566736 r13 0x7fffffffdb50 140737488345936 r14 0x0 0 r15 0x0 0 rip 0x5e3876 0x5e3876 <catch_errors+95> eflags <not saved> cs <not saved> ss <not saved> ds <not saved> es <not saved> fs <not saved> gs <not saved> The patch also teaches the heuristic unwinder about call-clobbered registers, though I wonder whether we should be assuming much about the ABI around assembly or no-debug-info functions. Hmm. Argh, this thread is getting quite confusing with the back and forth. Sorry about that. --- gdb/amd64-tdep.c | 54 +++++++++++++++++++++++++- gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp | 31 +++++++++++++-- gdb/testsuite/gdb.mi/mi-reg-undefined.exp | 43 ++++++++++++++++---- 3 files changed, 115 insertions(+), 13 deletions(-) diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index 3ab74f0..3ab6058 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -40,6 +40,7 @@ #include "exceptions.h" #include "amd64-tdep.h" #include "i387-tdep.h" +#include "dwarf2-frame.h" #include "features/i386/amd64.c" #include "features/i386/amd64-avx.c" @@ -1744,6 +1745,28 @@ amd64_alloc_frame_cache (void) return cache; } +/* Return true if the ABI specifies REGNUM as a callee-saved + register. */ + +static int +amd64_register_callee_saved (int regnum) +{ + if (regnum == AMD64_RBP_REGNUM + || regnum == AMD64_RBX_REGNUM + || (AMD64_R12_REGNUM <= regnum && regnum <= AMD64_R15_REGNUM)) + return 1; + + /* The control bits of the MXCSR register are callee-saved. */ + if (regnum == AMD64_MXCSR_REGNUM) + return 1; + + /* The x87 control word is callee-saved. */ + if (regnum == AMD64_FCTRL_REGNUM) + return 1; + + return 0; +} + /* GCC 4.4 and later, can put code in the prologue to realign the stack pointer. Check whether PC points to such code, and update CACHE accordingly. Return the first instruction after the code @@ -2423,7 +2446,10 @@ amd64_frame_prev_register (struct frame_info *this_frame, void **this_cache, return frame_unwind_got_memory (this_frame, regnum, cache->saved_regs[regnum]); - return frame_unwind_got_register (this_frame, regnum, regnum); + if (amd64_register_callee_saved (regnum)) + return frame_unwind_got_register (this_frame, regnum, regnum); + else + return frame_unwind_got_optimized (this_frame, regnum); } static const struct frame_unwind amd64_frame_unwind = @@ -2846,6 +2872,30 @@ static const int amd64_record_regmap[] = AMD64_DS_REGNUM, AMD64_ES_REGNUM, AMD64_FS_REGNUM, AMD64_GS_REGNUM }; +/* Implement the "init_reg" dwarf2_frame_ops method. */ + +static void +amd64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, + struct dwarf2_frame_state_reg *reg, + struct frame_info *this_frame) +{ + /* Mark the PC as the destination for the return address. */ + if (regnum == gdbarch_pc_regnum (gdbarch)) + reg->how = DWARF2_FRAME_REG_RA; + + /* Mark the stack pointer as the call frame address. */ + else if (regnum == gdbarch_sp_regnum (gdbarch)) + reg->how = DWARF2_FRAME_REG_CFA; + + /* The above was taken from the default init_reg in dwarf2-frame.c + while the below is AMD64 specific. */ + + else if (amd64_register_callee_saved (regnum)) + reg->how = DWARF2_FRAME_REG_SAME_VALUE; + else + reg->how = DWARF2_FRAME_REG_UNDEFINED; +} + void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { @@ -2948,6 +2998,8 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) frame_unwind_append_unwinder (gdbarch, &amd64_frame_unwind); frame_base_set_default (gdbarch, &amd64_frame_base); + dwarf2_frame_set_init_reg (gdbarch, amd64_dwarf2_frame_init_reg); + /* If we have a register mapping, enable the generic core file support. */ if (tdep->gregset_reg_offset) set_gdbarch_regset_from_core_section (gdbarch, diff --git a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp index 44bf8e9..c11b007 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp +++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp @@ -44,11 +44,24 @@ for {set f 0} {$f < 3} {incr f} { set pattern_rax_rbx_rcx_info "$hex\\s+$decimal" set pattern_r8_r9_print "$hex" set pattern_r8_r9_info "$hex\\s+$decimal" + set pattern_r12_r15_print "$hex" + set pattern_r12_r15_info "$hex\\s+$decimal" } else { + # Even though rbx is callee-saved, these are all explicitly + # marked undefined in the debug info. set pattern_rax_rbx_rcx_print "<not saved>" set pattern_rax_rbx_rcx_info "<not saved>" - set pattern_r8_r9_print "$hex" - set pattern_r8_r9_info "$hex\\s+$decimal" + + # ABI specifies these as caller-saved. GDB should be + # implicitly aware they're not saved, even if the debug info + # doesn't explicitly say so (and also doesn't say they were + # actually saved). + set pattern_r8_r9_print "<not saved>" + set pattern_r8_r9_info "<not saved>" + + # ABI specifies these as callee-saved. + set pattern_r12_r15_print "$hex" + set pattern_r12_r15_info "$hex\\s+$decimal" } # Select frame. @@ -64,8 +77,18 @@ for {set f 0} {$f < 3} {incr f} { gdb_test "p/x \$r8" "$pattern_r8_r9_print" "print \$r8 in frame ${f}" gdb_test "p/x \$r9" "$pattern_r8_r9_print" "print \$r9 in frame ${f}" + gdb_test "p/x \$r12" "$pattern_r12_r15_print" "print \$r12 in frame ${f}" + gdb_test "p/x \$r15" "$pattern_r12_r15_print" "print \$r15 in frame ${f}" # Display register values. - gdb_test "info registers rax rbx rcx r8 r9" "rax\\s+${pattern_rax_rbx_rcx_info}\\s*\r\nrbx\\s+${pattern_rax_rbx_rcx_info}\\s*\r\nrcx\\s+${pattern_rax_rbx_rcx_info}\\s*\r\nr8\\s+${pattern_r8_r9_info}\\s*\r\nr9\\s+${pattern_r8_r9_info}\\s*" \ - "Check values of rax, rbx, rcx, r8, r9 in frame ${f}" + send_gdb "info registers rax rbx rcx r8 r9 r12 r15\n" + gdb_expect_list "info registers in frame ${f}" "$gdb_prompt $" \ + [list \ + "rax\\s+$pattern_rax_rbx_rcx_info\r\n" \ + "rbx\\s+$pattern_rax_rbx_rcx_info\r\n" \ + "rcx\\s+$pattern_rax_rbx_rcx_info\r\n" \ + "r8\\s+$pattern_r8_r9_info\r\n" \ + "r9\\s+$pattern_r8_r9_info\r\n" \ + "r12\\s+$pattern_r12_r15_info\r\n" \ + "r15\\s+$pattern_r12_r15_info\r\n" ] } diff --git a/gdb/testsuite/gdb.mi/mi-reg-undefined.exp b/gdb/testsuite/gdb.mi/mi-reg-undefined.exp index cb3a716..64fa581 100644 --- a/gdb/testsuite/gdb.mi/mi-reg-undefined.exp +++ b/gdb/testsuite/gdb.mi/mi-reg-undefined.exp @@ -52,20 +52,47 @@ 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 not_saved_pattern "<not saved>" - for {set f 0} {$f < 3} {incr f} { if {${f} == 0} { - set pattern_0_1_2 ${hex} + set pattern ${hex} } else { - set pattern_0_1_2 ${not_saved_pattern} + set pattern "<not saved>" } - 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\"\}\\\]" \ + # - rax,rbx,rcx are explicitly marked undefined in the debug info, + # so GDB should display them all as not saved, even though rbx + # is callee-saved. + # + # - r8-r9 are caller-saved. GDB should be implicitly aware + # they're not saved, even if the debug info doesn't explicitly + # say so (and also doesn't say they were actually saved). + # + # - r12-r15 are callee-saved. GDB should be able to find their + # values. + + mi_gdb_test "22${f}-data-list-register-values --thread 1 --frame ${f} x 0 1 2 8 9 12 15" \ + [join [list \ + "22${f}\\^done,register-values=\\\["\ + "\{number=\"0\",value=\"${pattern}\"\}," \ + "\{number=\"1\",value=\"${pattern}\"\}," \ + "\{number=\"2\",value=\"${pattern}\"\}," \ + "\{number=\"8\",value=\"${pattern}\"\}," \ + "\{number=\"9\",value=\"${pattern}\"\}," \ + "\{number=\"12\",value=\"$hex\"\}," \ + "\{number=\"15\",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\"\}\\\]" \ + mi_gdb_test "33${f}-data-list-register-values --thread 1 --frame ${f} r 0 1 2 8 9 12 15" \ + [join [list \ + "33${f}\\^done,register-values=\\\["\ + "\{number=\"0\",value=\"${pattern}\"\}," \ + "\{number=\"1\",value=\"${pattern}\"\}," \ + "\{number=\"2\",value=\"${pattern}\"\}," \ + "\{number=\"8\",value=\"${pattern}\"\}," \ + "\{number=\"9\",value=\"${pattern}\"\}," \ + "\{number=\"12\",value=\"$hex\"\}," \ + "\{number=\"15\",value=\"$hex\"\}" \ + "\\\]" ] "" ] \ "register values, format r, frame ${f}" } -- 1.7.11.7 ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-19 16:58 ` Pedro Alves 2013-09-19 19:15 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Pedro Alves @ 2013-10-02 16:17 ` Pedro Alves 1 sibling, 0 replies; 43+ messages in thread From: Pedro Alves @ 2013-10-02 16:17 UTC (permalink / raw) To: gdb-patches; +Cc: Eli Zaretskii, Mark Kettenis, aburgess FYI, I've now applied this patch, as below: ------- Subject: Print registers not saved in the frame as "<not saved>" instead of "<optimized out>". Currently, in some scenarios, GDB prints <optimized out> when printing outer frame registers. An <optimized out> register is a confusing concept. What this really means is that the register is call-clobbered, or IOW, not saved by the callee. This patch makes GDB say that instead. Before patch: (gdb) p/x $rax $1 = <optimized out> (gdb) info registers rax rax <optimized out> After patch: (gdb) p/x $rax $1 = <not saved> (gdb) info registers rax rax <not saved> However, if for some reason the debug info describes a variable as being in such a register (**), we still want to print <optimized out> when printing the variable. IOW, <not saved> is reserved for inspecting registers at the machine level. The patch uses lval_register+optimized_out to encode the not saved registers, and makes it so that optimized out variables always end up in !lval_register values. ** See <https://sourceware.org/ml/gdb-patches/2012-08/msg00787.html>. Current/recent enough GCC doesn't mark variables/arguments as being in call-clobbered registers in the ranges corresponding to function calls, while older GCCs did. Newer GCCs will just not say where the variable is, so GDB will end up realizing the variable is optimized out. frame_unwind_got_optimized creates not_lval optimized out registers, so by default, in most cases, we'll see <optimized out>. 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-10-02 Pedro Alves <palves@redhat.com> * 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) <DWARF_VALUE_REGISTER>: 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 <not saved> 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) <optimized_out>: 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 <not saved>. gdb/testsuite/ 2013-10-02 Pedro Alves <palves@redhat.com> * gdb.dwarf2/dw2-reg-undefined.exp <pattern_rax_rbx_rcx_print, pattern_rax_rbx_rcx_info>: Set to "<not saved>". * gdb.mi/mi-reg-undefined.exp (opt_out_pattern): Delete. (not_saved_pattern): New. Replace use of the former with the latter. gdb/doc/ 2013-10-02 Pedro Alves <palves@redhat.com> * gdb.texinfo (Registers): Expand description of saved registers in frames. Explain <not saved>. --- gdb/NEWS | 14 +++++++++++ gdb/cp-valprint.c | 4 ++- gdb/doc/gdb.texinfo | 31 +++++++++++++++++++++--- 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, 111 insertions(+), 30 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index af06a21..c0fe72a 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -15,6 +15,20 @@ * The "catch syscall" command now works on arm*-linux* targets. +* GDB now consistently shows "<not saved>" when printing values of + registers the debug info indicates have not been saved in the frame + and there's nowhere to retrieve them from + (callee-saved/call-clobbered registers): + + (gdb) p $rax + $1 = <not saved> + + (gdb) info registers rax + rax <not saved> + + Before, the former would print "<optimized out>", 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, _("<error reading variable: %s>"), 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..ffee6e1 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -10031,10 +10031,33 @@ 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. +@cindex caller-saved registers +@cindex call-clobbered registers +@cindex volatile registers +@cindex <not saved> values +Usually ABIs reserve some registers as not needed to be saved by the +callee (a.k.a.: ``caller-saved'', ``call-clobbered'' or ``volatile'' +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 the inner frame saved +(``callee-saved'') registers, from the debug info, unwind info, or the +machine code generated by your compiler. If some register is not +saved, and @value{GDBN} knows the register is ``caller-saved'' (via +its own knowledge of the ABI, or because the debug/unwind info +explicitly says the register's value is undefined), @value{GDBN} +displays @w{@samp{<not saved>}} as the register's value. With targets +that @value{GDBN} has no knowledge of the register saving convention, +if a register was not saved by the callee, then its value and location +in the outer frame are assumed to be the same of the inner frame. +This is usually harmless, because if the register is call-clobbered, +the caller either does not care what is in the register after the +call, or has code to restore the value that it does care about. Note, +however, that if you change such a register in the outer frame, you +may also be affecting the inner frame. Also, the more ``outer'' the +frame is you're looking at, the more likely a call-clobbered +register's value is to be wrong, in the sense that it doesn't actually +represent the value the register had just before the call. @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 + <optimized out> instead of <not saved>. */ + 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 "<optimized out>" - set pattern_rax_rbx_rcx_info "<optimized out>" + set pattern_rax_rbx_rcx_print "<not saved>" + set pattern_rax_rbx_rcx_info "<not saved>" 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 "<optimized out>" +set not_saved_pattern "<not saved>" 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, _("<optimized out>")); + if (val != NULL && value_lval_const (val) == lval_register) + fprintf_filtered (stream, _("<not saved>")); + else + fprintf_filtered (stream, _("<optimized out>")); } 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 ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-18 15:54 ` [PATCH+DOC] " Pedro Alves 2013-09-18 16:30 ` Eli Zaretskii @ 2013-09-18 16:30 ` Andreas Schwab 2013-09-18 17:36 ` Pedro Alves 1 sibling, 1 reply; 43+ messages in thread From: Andreas Schwab @ 2013-09-18 16:30 UTC (permalink / raw) To: Pedro Alves; +Cc: Andrew Burgess, gdb-patches, Mark Kettenis Pedro Alves <palves@redhat.com> writes: > 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 "<not saved>" when printing values of registers that > + have not been saved in the frame: > + > + (gdb) p $rax $1 = <not saved> ^s/ /\n/ > + (gdb) info registers rax rax <not saved> ^s/ /\n/ Andreas. -- Andreas Schwab, schwab@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different." ^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". 2013-09-18 16:30 ` Andreas Schwab @ 2013-09-18 17:36 ` Pedro Alves 0 siblings, 0 replies; 43+ messages in thread From: Pedro Alves @ 2013-09-18 17:36 UTC (permalink / raw) To: Andreas Schwab; +Cc: Andrew Burgess, gdb-patches, Mark Kettenis On 09/18/2013 05:30 PM, Andreas Schwab wrote: > Pedro Alves <palves@redhat.com> writes: >> +* GDB now shows "<not saved>" when printing values of registers that >> + have not been saved in the frame: >> + >> + (gdb) p $rax $1 = <not saved> > ^s/ /\n/ >> + (gdb) info registers rax rax <not saved> > ^s/ /\n/ > Thanks. Fixed in the new version. -- Pedro Alves ^ permalink raw reply [flat|nested] 43+ messages in thread
end of thread, other threads:[~2013-10-02 19:07 UTC | newest] Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2013-08-06 13:09 [PATCH] Consistent display of "<optimized out>" Andrew Burgess 2013-08-06 13:18 ` Mark Kettenis 2013-08-06 13:49 ` Andrew Burgess 2013-08-06 15:41 ` Mark Kettenis 2013-08-06 16:02 ` Andrew Burgess 2013-08-06 18:39 ` Pedro Alves 2013-08-12 13:32 ` Andrew Burgess 2013-08-12 13:55 ` Pedro Alves 2013-08-12 14:01 ` Andrew Burgess 2013-08-12 20:01 ` Mark Kettenis 2013-08-13 8:27 ` Andrew Burgess 2013-08-16 18:41 ` Pedro Alves 2013-08-16 20:28 ` Pedro Alves 2013-08-19 10:25 ` Andrew Burgess 2013-09-05 16:29 ` [PATCH] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>". (was: Re: [PATCH] Consistent display of "<optimized out>") Pedro Alves 2013-09-05 16:35 ` [PATCH] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>" Andrew Burgess 2013-09-16 19:05 ` Pedro Alves 2013-09-18 14:04 ` Andrew Burgess 2013-09-18 15:54 ` [PATCH+DOC] " Pedro Alves 2013-09-18 16:30 ` Eli Zaretskii 2013-09-18 17:35 ` Pedro Alves 2013-09-18 19:35 ` Eli Zaretskii 2013-09-18 20:47 ` Mark Kettenis 2013-09-19 7:53 ` Eli Zaretskii 2013-09-19 16:58 ` Pedro Alves 2013-09-19 19:15 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Pedro Alves 2013-09-19 19:35 ` Eli Zaretskii 2013-09-19 23:13 ` Doug Evans 2013-09-19 23:22 ` Doug Evans 2013-09-20 11:04 ` [PATCH] Always print call-clobbered registers in outer frames Andrew Burgess 2013-09-24 12:07 ` Pedro Alves 2013-09-24 12:56 ` Andrew Burgess 2013-09-24 13:43 ` Pedro Alves 2013-09-24 15:18 ` Andrew Burgess 2013-09-24 19:36 ` Pedro Alves 2013-09-24 23:22 ` Andrew Burgess 2013-10-02 16:05 ` Pedro Alves 2013-10-02 19:07 ` Doug Evans 2013-09-20 12:28 ` [PATCH] Always print call-clobbered registers in outer frames. (was: Re: [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>".) Mark Kettenis 2013-09-24 12:06 ` [PATCH] Always print call-clobbered registers in outer frames Pedro Alves 2013-10-02 16:17 ` [PATCH+DOC] Print registers not saved in the frame as "<not saved>", instead of "<optimized out>" Pedro Alves 2013-09-18 16:30 ` Andreas Schwab 2013-09-18 17:36 ` Pedro Alves
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox