From 0fdb4f184b39af02d76e21cd25af561b464f15a6 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Fri, 18 Mar 2011 18:41:36 +0000 Subject: [PATCH] gdb/ * findvar.c (value_of_register): Mark the value as unavailable, if the register is unavailable. * frame.h (frame_register_unwind): New `unavailablep' parameter. (frame_register): New `unavailablep' parameter. (frame_register_read): Update comment. * frame.c (frame_register_unwind): New `unavailablep' parameter. Set it if the register is unavailable. If the register is unavailable, clear the output buffer. (frame_register): New `unavailablep' parameter. Pass it down. (frame_unwind_register): Adjust. (put_frame_register): Adjust. (frame_register_read): Adjust. Also return false if the register is not available. (frame_register_unwind_location): Adjust. * sentinel-frame.c (sentinel_frame_prev_register): If the register is unavailable, mark the value accordingly. * stack.c (frame_info): Handle unavailable registers. gdb/testsuite/ * gdb.trace/unavailable.exp (fpreg, spreg, pcreg): Define. (test_register, test_register_unavailable): New procedures. (gdb_unavailable_registers_test): New procedure. (gdb_trace_collection_test): Call it. --- gdb/ChangeLog | 20 ++++++ gdb/findvar.c | 15 +++- gdb/frame.c | 44 ++++++++---- gdb/frame.h | 20 +++--- gdb/sentinel-frame.c | 5 +- gdb/stack.c | 17 ++--- gdb/testsuite/ChangeLog | 7 ++ gdb/testsuite/gdb.trace/unavailable.exp | 96 +++++++++++++++++++++++++ 8 files changed, 189 insertions(+), 35 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3fab4bc7e70..097337ea3dc 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,23 @@ +2011-03-18 Pedro Alves + + * findvar.c (value_of_register): Mark the value as unavailable, if + the register is unavailable. + * frame.h (frame_register_unwind): New `unavailablep' parameter. + (frame_register): New `unavailablep' parameter. + (frame_register_read): Update comment. + * frame.c (frame_register_unwind): New `unavailablep' parameter. + Set it if the register is unavailable. If the register is + unavailable, clear the output buffer. + (frame_register): New `unavailablep' parameter. Pass it down. + (frame_unwind_register): Adjust. + (put_frame_register): Adjust. + (frame_register_read): Adjust. Also return false if the register + is not available. + (frame_register_unwind_location): Adjust. + * sentinel-frame.c (sentinel_frame_prev_register): If the register + is unavailable, mark the value accordingly. + * stack.c (frame_info): Handle unavailable registers. + 2011-03-18 Pedro Alves * mi/mi-main.c (register_changed_p): Handle REG_UNAVAILABLE, and diff --git a/gdb/findvar.c b/gdb/findvar.c index 6463342e6ec..809a99e8a72 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -265,6 +265,7 @@ value_of_register (int regnum, struct frame_info *frame) struct gdbarch *gdbarch = get_frame_arch (frame); CORE_ADDR addr; int optim; + int unavail; struct value *reg_val; int realnum; gdb_byte raw_buffer[MAX_REGISTER_SIZE]; @@ -276,16 +277,24 @@ value_of_register (int regnum, struct frame_info *frame) + gdbarch_num_pseudo_regs (gdbarch)) return value_of_user_reg (regnum, frame); - frame_register (frame, regnum, &optim, &lval, &addr, &realnum, raw_buffer); + frame_register (frame, regnum, &optim, &unavail, + &lval, &addr, &realnum, raw_buffer); reg_val = allocate_value (register_type (gdbarch, regnum)); - memcpy (value_contents_raw (reg_val), raw_buffer, - register_size (gdbarch, regnum)); + if (!optim && !unavail) + memcpy (value_contents_raw (reg_val), raw_buffer, + register_size (gdbarch, regnum)); + else + memset (value_contents_raw (reg_val), 0, + register_size (gdbarch, regnum)); + VALUE_LVAL (reg_val) = lval; set_value_address (reg_val, addr); VALUE_REGNUM (reg_val) = regnum; set_value_optimized_out (reg_val, optim); + if (unavail) + mark_value_bytes_unavailable (reg_val, 0, register_size (gdbarch, regnum)); VALUE_FRAME_ID (reg_val) = get_frame_id (frame); return reg_val; } diff --git a/gdb/frame.c b/gdb/frame.c index 3bc211ebbb9..42380eb550e 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -757,8 +757,9 @@ frame_pop (struct frame_info *this_frame) void frame_register_unwind (struct frame_info *frame, int regnum, - int *optimizedp, enum lval_type *lvalp, - CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp) + int *optimizedp, int *unavailablep, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, gdb_byte *bufferp) { struct value *value; @@ -775,13 +776,19 @@ frame_register_unwind (struct frame_info *frame, int regnum, gdb_assert (value != NULL); *optimizedp = value_optimized_out (value); + *unavailablep = !value_entirely_available (value); *lvalp = VALUE_LVAL (value); *addrp = value_address (value); *realnump = VALUE_REGNUM (value); - if (bufferp && !*optimizedp) - memcpy (bufferp, value_contents_all (value), - TYPE_LENGTH (value_type (value))); + if (bufferp) + { + if (!*optimizedp && !*unavailablep) + memcpy (bufferp, value_contents_all (value), + TYPE_LENGTH (value_type (value))); + else + memset (bufferp, 0, TYPE_LENGTH (value_type (value))); + } /* Dispose of the new value. This prevents watchpoints from trying to watch the saved frame pointer. */ @@ -791,7 +798,7 @@ frame_register_unwind (struct frame_info *frame, int regnum, void frame_register (struct frame_info *frame, int regnum, - int *optimizedp, enum lval_type *lvalp, + int *optimizedp, int *unavailablep, enum lval_type *lvalp, CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp) { /* Require all but BUFFERP to be valid. A NULL BUFFERP indicates @@ -805,20 +812,21 @@ frame_register (struct frame_info *frame, int regnum, /* Obtain the register value by unwinding the register from the next (more inner frame). */ gdb_assert (frame != NULL && frame->next != NULL); - frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp, - realnump, bufferp); + frame_register_unwind (frame->next, regnum, optimizedp, unavailablep, + lvalp, addrp, realnump, bufferp); } void frame_unwind_register (struct frame_info *frame, int regnum, gdb_byte *buf) { int optimized; + int unavailable; CORE_ADDR addr; int realnum; enum lval_type lval; - frame_register_unwind (frame, regnum, &optimized, &lval, &addr, - &realnum, buf); + frame_register_unwind (frame, regnum, &optimized, &unavailable, + &lval, &addr, &realnum, buf); } void @@ -940,10 +948,12 @@ put_frame_register (struct frame_info *frame, int regnum, struct gdbarch *gdbarch = get_frame_arch (frame); int realnum; int optim; + int unavail; enum lval_type lval; CORE_ADDR addr; - frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL); + frame_register (frame, regnum, &optim, &unavail, + &lval, &addr, &realnum, NULL); if (optim) error (_("Attempt to assign to a value that was optimized out.")); switch (lval) @@ -978,13 +988,15 @@ frame_register_read (struct frame_info *frame, int regnum, gdb_byte *myaddr) { int optimized; + int unavailable; enum lval_type lval; CORE_ADDR addr; int realnum; - frame_register (frame, regnum, &optimized, &lval, &addr, &realnum, myaddr); + frame_register (frame, regnum, &optimized, &unavailable, + &lval, &addr, &realnum, myaddr); - return !optimized; + return !optimized && !unavailable; } int @@ -1425,8 +1437,10 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum, while (this_frame != NULL) { - frame_register_unwind (this_frame, regnum, optimizedp, lvalp, - addrp, realnump, NULL); + int unavailable; + + frame_register_unwind (this_frame, regnum, optimizedp, &unavailable, + lvalp, addrp, realnump, NULL); if (*optimizedp) break; diff --git a/gdb/frame.h b/gdb/frame.h index 252b75e0539..605528cff26 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -471,7 +471,8 @@ const char *frame_stop_reason_string (enum unwind_stop_reason); fetch/compute the value. Instead just return the location of the value. */ extern void frame_register_unwind (struct frame_info *frame, int regnum, - int *optimizedp, enum lval_type *lvalp, + int *optimizedp, int *unavailablep, + enum lval_type *lvalp, CORE_ADDR *addrp, int *realnump, gdb_byte *valuep); @@ -507,7 +508,8 @@ extern ULONGEST get_frame_register_unsigned (struct frame_info *frame, VALUEP is NULL, the registers value is not fetched/computed. */ extern void frame_register (struct frame_info *frame, int regnum, - int *optimizedp, enum lval_type *lvalp, + int *optimizedp, int *unavailablep, + enum lval_type *lvalp, CORE_ADDR *addrp, int *realnump, gdb_byte *valuep); @@ -654,12 +656,14 @@ extern int deprecated_pc_in_call_dummy (struct gdbarch *gdbarch, CORE_ADDR pc); /* FIXME: cagney/2003-02-02: Should be deprecated or replaced with a function called get_frame_register_p(). This slightly weird (and older) variant of get_frame_register() returns zero (indicating the - register is unavailable) if either: the register isn't cached; or - the register has been optimized out. Problem is, neither check is - exactly correct. A register can't be optimized out (it may not - have been saved as part of a function call); The fact that a - register isn't in the register cache doesn't mean that the register - isn't available (it could have been fetched from memory). */ + register value is unavailable/invalid) if either: the register + isn't cached; or the register has been optimized out; or the + register contents are unavailable (because they haven't been + collected in a traceframe). Problem is, neither check is exactly + correct. A register can't be optimized out (it may not have been + saved as part of a function call); The fact that a register isn't + in the register cache doesn't mean that the register isn't + available (it could have been fetched from memory). */ extern int frame_register_read (struct frame_info *frame, int regnum, gdb_byte *buf); diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c index f68ea1c02ef..e6000cc136c 100644 --- a/gdb/sentinel-frame.c +++ b/gdb/sentinel-frame.c @@ -61,7 +61,10 @@ sentinel_frame_prev_register (struct frame_info *this_frame, /* Use the regcache_cooked_read() method so that it, on the fly, constructs either a raw or pseudo register from the raw register cache. */ - regcache_cooked_read (cache->regcache, regnum, value_contents_raw (value)); + if (regcache_cooked_read (cache->regcache, + regnum, + value_contents_raw (value)) == REG_UNAVAILABLE) + mark_value_bytes_unavailable (value, 0, register_size (gdbarch, regnum)); return value; } diff --git a/gdb/stack.c b/gdb/stack.c index 6e59cd0a055..79c3a433dc3 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -1186,6 +1186,7 @@ frame_info (char *addr_exp, int from_tty) { enum lval_type lval; int optimized; + int unavailable; CORE_ADDR addr; int realnum; int count; @@ -1202,9 +1203,9 @@ frame_info (char *addr_exp, int from_tty) /* Find out the location of the saved stack pointer with out actually evaluating it. */ frame_register_unwind (fi, gdbarch_sp_regnum (gdbarch), - &optimized, &lval, &addr, + &optimized, &unavailable, &lval, &addr, &realnum, NULL); - if (!optimized && lval == not_lval) + if (!optimized && !unavailable && lval == not_lval) { enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int sp_size = register_size (gdbarch, gdbarch_sp_regnum (gdbarch)); @@ -1212,7 +1213,7 @@ frame_info (char *addr_exp, int from_tty) CORE_ADDR sp; frame_register_unwind (fi, gdbarch_sp_regnum (gdbarch), - &optimized, &lval, &addr, + &optimized, &unavailable, &lval, &addr, &realnum, value); /* NOTE: cagney/2003-05-22: This is assuming that the stack pointer was packed as an unsigned integer. That @@ -1223,14 +1224,14 @@ frame_info (char *addr_exp, int from_tty) printf_filtered ("\n"); need_nl = 0; } - else if (!optimized && lval == lval_memory) + else if (!optimized && !unavailable && lval == lval_memory) { printf_filtered (" Previous frame's sp at "); fputs_filtered (paddress (gdbarch, addr), gdb_stdout); printf_filtered ("\n"); need_nl = 0; } - else if (!optimized && lval == lval_register) + else if (!optimized && !unavailable && lval == lval_register) { printf_filtered (" Previous frame's sp in %s\n", gdbarch_register_name (gdbarch, realnum)); @@ -1248,11 +1249,11 @@ frame_info (char *addr_exp, int from_tty) { /* Find out the location of the saved register without fetching the corresponding value. */ - frame_register_unwind (fi, i, &optimized, &lval, &addr, &realnum, - NULL); + frame_register_unwind (fi, i, &optimized, &unavailable, + &lval, &addr, &realnum, NULL); /* For moment, only display registers that were saved on the stack. */ - if (!optimized && lval == lval_memory) + if (!optimized && !unavailable && lval == lval_memory) { if (count == 0) puts_filtered (" Saved registers:\n "); diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index a1f1382d85f..77bad9fb738 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2011-03-18 Pedro Alves + + * gdb.trace/unavailable.exp (fpreg, spreg, pcreg): Define. + (test_register, test_register_unavailable): New procedures. + (gdb_unavailable_registers_test): New procedure. + (gdb_trace_collection_test): Call it. + 2011-03-18 Phil Muldoon PR python/12149 diff --git a/gdb/testsuite/gdb.trace/unavailable.exp b/gdb/testsuite/gdb.trace/unavailable.exp index ab8fe97b132..f526ac30fc7 100644 --- a/gdb/testsuite/gdb.trace/unavailable.exp +++ b/gdb/testsuite/gdb.trace/unavailable.exp @@ -30,10 +30,48 @@ if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \ set ws "\[\r\n\t \]+" set cr "\[\r\n\]+" +if [istarget "x86_64-*"] then { + set fpreg "rbp" + set spreg "rsp" + set pcreg "rip" +} elseif [istarget "i?86-*"] then { + set fpreg "ebp" + set spreg "esp" + set pcreg "eip" +} else { + set fpreg "fp" + set spreg "sp" + set pcreg "pc" +} + # # Utility procs # +proc test_register { reg } { + global gdb_prompt + global hex + global cr + + gdb_test_multiple "print /x $reg" "collected $reg" { + -re "\\$\[0-9\]+ = \[x0\]+$cr$gdb_prompt $" { + fail "collected $reg (zero)" + } + -re "\\$\[0-9\]+ = $hex$cr$gdb_prompt $" { + pass "collected $reg" + } + -re "\[Ee\]rror.*$gdb_prompt $" { + fail "collected $reg (error)" + } + } +} + +proc test_register_unavailable { reg } { + gdb_test "print /x $reg" \ + "" \ + "correctly report $reg as unavailable" +} + proc prepare_for_trace_test {} { global executable @@ -69,6 +107,63 @@ proc run_trace_experiment { test_func } { # Test procs # +proc gdb_unavailable_registers_test { } { + global gdb_prompt + global spreg + global pcreg + global pf_prefix + + set old_pf_prefix $pf_prefix + set pf_prefix "$pf_prefix unavailable registers:" + + prepare_for_trace_test + + # We'll simply re-use the globals_test_function for this test + gdb_test "trace globals_test_func" \ + "Tracepoint \[0-9\]+ at .*" \ + "set tracepoint" + + # Collect nothing. + + # Begin the test. + run_trace_experiment globals_test_func + + # On some archs, the $sp/$pc are a real raw registers. On others, + # like x86, they're user registers. Test both variants. + test_register_unavailable "\$$spreg" + test_register_unavailable "\$sp" + + # Test reading uncollected pseudo-registers. The set of which + # depends on target. + if [istarget "x86_64-*"] then { + # Check the raw register first. + test_register_unavailable "\$rax" + test_register_unavailable "\$eax" + test_register_unavailable "\$ax" + } elseif [istarget "i?86-*"] then { + # Check the raw register first. + test_register_unavailable "\$eax" + test_register_unavailable "\$ax" + } + + # GDBserver always provides the PC value of regular tracepoint + # hits, since it's the same as the tracepoint's address. + test_register "\$$pcreg" + test_register "\$pc" + + gdb_test "info registers" \ + "\\*value not available\\*.*\\*value not available\\*" \ + "info registers, multiple registers not available" + + gdb_test "info registers \$$spreg" \ + "\\*value not available\\*" \ + "info registers \$$spreg reports not available" + + gdb_test "tfind none" "#0 end .*" "cease trace debugging" + + set pf_prefix $old_pf_prefix +} + proc gdb_collect_globals_test { } { global ws global cr @@ -321,6 +416,7 @@ proc gdb_collect_globals_test { } { proc gdb_trace_collection_test {} { gdb_collect_globals_test + gdb_unavailable_registers_test } clean_restart $executable -- 2.30.2