* [PATCH 0/2] Test case on entry values @ 2013-08-13 7:41 Yao Qi 2013-08-13 7:41 ` [RFC 2/2] Test entry values in trace frame Yao Qi 2013-08-13 7:41 ` [PATCH 1/2] Test case for entry values Yao Qi 0 siblings, 2 replies; 31+ messages in thread From: Yao Qi @ 2013-08-13 7:41 UTC (permalink / raw) To: gdb-patches Hi, In the review of the patch which adds '--skip-unavailable' to skip unavailable locals and arguments, Pedro pointed that "entry value" should be considered too. The code is not hard, but the test case is harder than the code. We have to make sure that 1) necessary DIEs are generated, 2) set up a case that argument is available but entry value is not. We choose the test to arguments and entry values when GDB is examining trace frames, because something can be unavailable. This situation is not tested in current testsuite, and this test can be reviewed committed independently. Patch 1/2 is to generate dwarf using Dwarf Assembler to test "entry values" are shown correctly. At this point, gdb.trace/entry-values.exp is still a dwarf test, nothing to do with trace. Patch 2/2 is to use tracepoint, to collect data, to test what happen when argument is available and entry value is not. Most of gdb.trace/etnry-values.exp is a dwarf test, and we can move them to gdb.dwarf2 and copy necessary bits in gdb.trace. I didn't do that because it will cause some duplication. *** BLURB HERE *** Yao Qi (2): Test case for entry values. Test entry values in trace frame gdb/testsuite/gdb.trace/entry-values.c | 50 ++++++ gdb/testsuite/gdb.trace/entry-values.exp | 274 ++++++++++++++++++++++++++++++ gdb/testsuite/lib/dwarf.exp | 8 + 3 files changed, 332 insertions(+), 0 deletions(-) create mode 100644 gdb/testsuite/gdb.trace/entry-values.c create mode 100644 gdb/testsuite/gdb.trace/entry-values.exp -- 1.7.7.6 ^ permalink raw reply [flat|nested] 31+ messages in thread
* [RFC 2/2] Test entry values in trace frame 2013-08-13 7:41 [PATCH 0/2] Test case on entry values Yao Qi @ 2013-08-13 7:41 ` Yao Qi 2013-08-20 17:48 ` Tom Tromey 2013-08-13 7:41 ` [PATCH 1/2] Test case for entry values Yao Qi 1 sibling, 1 reply; 31+ messages in thread From: Yao Qi @ 2013-08-13 7:41 UTC (permalink / raw) To: gdb-patches Hi, This is the test for "entry-values" when GDB is examining trace frames. In test, tracepoint action collects arguments i and j and global variable global1. Variable global2 is not collected. The GNU_call_site_parameter is faked that i's entry value is from global1, j's entry value is from global2. When GDB is examining trace frame, value of i, j and i@entry should be available, but value of j@entry is not. However, when I run this test, I find j@entry is something like, j@entry=<error reading variable: Cannot access memory at address 0x8049788> instead of unavailable. I don't emit a fail for it because I am not very sure it is expected to be "unavailable". I am fine to kfail it. I looked into a little, and looks reading entry value doesn't use value availability-aware API. It is not an easy fix to me. gdb/testsuite: 2013-08-13 Yao Qi <yao@codesourcery.com> * gdb.trace/entry-values.c (end): New (main): Call end. * gdb.trace/entry-values.exp: Load trace-support.exp. Set tracepoint and collect data. Test entry value is unavailable. --- gdb/testsuite/gdb.trace/entry-values.c | 5 +++ gdb/testsuite/gdb.trace/entry-values.exp | 49 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 0 deletions(-) diff --git a/gdb/testsuite/gdb.trace/entry-values.c b/gdb/testsuite/gdb.trace/entry-values.c index 3f98615..e287203 100644 --- a/gdb/testsuite/gdb.trace/entry-values.c +++ b/gdb/testsuite/gdb.trace/entry-values.c @@ -32,6 +32,10 @@ bar (int i) int global1 = 1; int global2 = 2; +static void +end (void) +{} + int main (void) { @@ -41,5 +45,6 @@ main (void) global2++; ret = bar (0); + end (); return ret; } diff --git a/gdb/testsuite/gdb.trace/entry-values.exp b/gdb/testsuite/gdb.trace/entry-values.exp index ba95e4f..bf946c3 100644 --- a/gdb/testsuite/gdb.trace/entry-values.exp +++ b/gdb/testsuite/gdb.trace/entry-values.exp @@ -221,3 +221,52 @@ gdb_test_sequence "bt" "bt" { "\[\r\n\]#1 .* bar \\(i=<optimized out>, i@entry=<optimized out>\\)" "\[\r\n\]#2 .* main \\(\\)" } + +# Restart GDB and trace. + +clean_restart $binfile + +load_lib "trace-support.exp" + +if ![runto_main] { + fail "Can't run to main to check for trace support" + return -1 +} + +if ![gdb_target_supports_trace] { + unsupported "target does not support trace" + return -1 +} + +gdb_test "trace foo" "Tracepoint $decimal at .*" + +if [is_amd64_regs_target] { + set spreg "\$rsp" +} elseif [is_x86_like_target] { + set spreg "\$esp" +} else { + set spreg "\$sp" +} + +# Collect arguments i and j. Collect 'global1' which is entry value +# of argument i. Don't collect 'global2' to test the entry value of +# argument j. + +gdb_trace_setactions "set action for tracepoint 1" "" \ + "collect i, j, global1, \(\*\(void \*\*\) \($spreg\)\) @ 64" "^$" + +gdb_test_no_output "tstart" + +gdb_breakpoint "end" +gdb_continue_to_breakpoint "end" + +gdb_test_no_output "tstop" + +gdb_test "tfind" "Found trace frame 0, .*" "tfind start" + +# Since 'global2' is not collected, j@entry is expected to be 'unavailable', +# however, the current output is like: +# j@entry=<error reading variable: Cannot access memory at address 0x8049788> +gdb_test "bt 1" "#0 .* foo \\(i=\[-\]?$decimal, i@entry=2, j=\[-\]?$decimal, j@entry=.*\\).*" + +gdb_test "tfind" "Target failed to find requested trace frame\..*" -- 1.7.7.6 ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC 2/2] Test entry values in trace frame 2013-08-13 7:41 ` [RFC 2/2] Test entry values in trace frame Yao Qi @ 2013-08-20 17:48 ` Tom Tromey 2013-08-21 6:06 ` Yao Qi 0 siblings, 1 reply; 31+ messages in thread From: Tom Tromey @ 2013-08-20 17:48 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> I don't emit a fail for it because I am not very sure it is expected Yao> to be "unavailable". I am fine to kfail it. Yao> I looked into a little, and looks reading entry value doesn't use Yao> value availability-aware API. It is not an easy fix to me. I think on the whole I'd rather we not check in a test that fails. I know we already have tests like that, but what I've noticed is that these tests only ever seem to be fixed as a side effect of fixing something else. Otherwise the failures are just universally ignored. I suppose the best thing to do is to file a bug about this problem. Then you can attach this patch to the bug. What do you think? Tom ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC 2/2] Test entry values in trace frame 2013-08-20 17:48 ` Tom Tromey @ 2013-08-21 6:06 ` Yao Qi 2013-08-21 14:35 ` [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly Pedro Alves 2013-08-23 0:32 ` [RFC 2/2] Test entry values in trace frame Yao Qi 0 siblings, 2 replies; 31+ messages in thread From: Yao Qi @ 2013-08-21 6:06 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On 08/21/2013 01:48 AM, Tom Tromey wrote: > I think on the whole I'd rather we not check in a test that fails. > > I know we already have tests like that, but what I've noticed is that > these tests only ever seem to be fixed as a side effect of fixing > something else. Otherwise the failures are just universally ignored. > > I suppose the best thing to do is to file a bug about this problem. > Then you can attach this patch to the bug. > > What do you think? I agree. I opened PR15871 http://sourceware.org/bugzilla/show_bug.cgi?id=15871 On the other hand, I kfail the test. -- Yao (é½å°§) gdb/testsuite: 2013-08-21 Yao Qi <yao@codesourcery.com> * gdb.trace/entry-values.c (end): New (main): Call end. * gdb.trace/entry-values.exp: Load trace-support.exp. Set tracepoint and collect data. Test entry value is unavailable. --- gdb/testsuite/gdb.trace/entry-values.c | 5 +++ gdb/testsuite/gdb.trace/entry-values.exp | 48 ++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 0 deletions(-) diff --git a/gdb/testsuite/gdb.trace/entry-values.c b/gdb/testsuite/gdb.trace/entry-values.c index 3f98615..e287203 100644 --- a/gdb/testsuite/gdb.trace/entry-values.c +++ b/gdb/testsuite/gdb.trace/entry-values.c @@ -32,6 +32,10 @@ bar (int i) int global1 = 1; int global2 = 2; +static void +end (void) +{} + int main (void) { @@ -41,5 +45,6 @@ main (void) global2++; ret = bar (0); + end (); return ret; } diff --git a/gdb/testsuite/gdb.trace/entry-values.exp b/gdb/testsuite/gdb.trace/entry-values.exp index 30db4a6..cf2cb6f 100644 --- a/gdb/testsuite/gdb.trace/entry-values.exp +++ b/gdb/testsuite/gdb.trace/entry-values.exp @@ -230,3 +230,51 @@ gdb_test_sequence "bt" "bt (2)" { "\[\r\n\]#1 .* bar \\(i=<optimized out>, i@entry=<optimized out>\\)" "\[\r\n\]#2 .* main \\(\\)" } + +# Restart GDB and trace. + +clean_restart $binfile + +load_lib "trace-support.exp" + +if ![runto_main] { + fail "Can't run to main to check for trace support" + return -1 +} + +if ![gdb_target_supports_trace] { + unsupported "target does not support trace" + return -1 +} + +gdb_test "trace foo" "Tracepoint $decimal at .*" + +if [is_amd64_regs_target] { + set spreg "\$rsp" +} elseif [is_x86_like_target] { + set spreg "\$esp" +} else { + set spreg "\$sp" +} + +# Collect arguments i and j. Collect 'global1' which is entry value +# of argument i. Don't collect 'global2' to test the entry value of +# argument j. + +gdb_trace_setactions "set action for tracepoint 1" "" \ + "collect i, j, global1, \(\*\(void \*\*\) \($spreg\)\) @ 64" "^$" + +gdb_test_no_output "tstart" + +gdb_breakpoint "end" +gdb_continue_to_breakpoint "end" + +gdb_test_no_output "tstop" + +gdb_test "tfind" "Found trace frame 0, .*" "tfind start" + +# Since 'global2' is not collected, j@entry is expected to be 'unavailable'. +setup_kfail "gdb/15871" *-*-* +gdb_test "bt 1" "#0 .* foo \\(i=\[-\]?$decimal, i@entry=2, j=\[-\]?$decimal, j@entry=<unavailable>\\).*" + +gdb_test "tfind" "Target failed to find requested trace frame\..*" -- 1.7.7.6 ^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly 2013-08-21 6:06 ` Yao Qi @ 2013-08-21 14:35 ` Pedro Alves 2013-08-21 14:47 ` Mark Kettenis 2013-08-23 0:32 ` [RFC 2/2] Test entry values in trace frame Yao Qi 1 sibling, 1 reply; 31+ messages in thread From: Pedro Alves @ 2013-08-21 14:35 UTC (permalink / raw) To: Yao Qi; +Cc: Tom Tromey, gdb-patches On 08/13/2013 08:39 AM, Yao Qi wrote: > However, when I run this test, I find j@entry is something like, > j@entry=<error reading variable: Cannot access memory at address 0x8049788> > instead of unavailable. > > I don't emit a fail for it because I am not very sure it is expected > to be "unavailable". I am fine to kfail it. > > I looked into a little, and looks reading entry value doesn't use > value availability-aware API. It is not an easy fix to me. I looked into this. Here's a patch. Let me know what you think. -------- Subject: [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly In entry-values.exp, we have a test where the entry value of 'j' is unavailable, so it is expected that printing j@entry yields "<unavailable>". However, the actual output is: (gdb) frame #0 0x0000000000400540 in foo (i=0, i@entry=2, j=2, j@entry=<error reading variable: Cannot access memory at address 0x6009e8>) The error is thrown here: #0 throw_it (reason=RETURN_ERROR, error=MEMORY_ERROR, fmt=0x8cd550 "Cannot access memory at address %s", ap=0x7fffffffc8e8) at ../../src/gdb/exceptions.c:373 #1 0x00000000005e2f9c in throw_error (error=MEMORY_ERROR, fmt=0x8cd550 "Cannot access memory at address %s") at ../../src/gdb/exceptions.c:422 #2 0x0000000000673a5f in memory_error (status=5, memaddr=6293992) at ../../src/gdb/corefile.c:204 #3 0x0000000000673aea in read_memory (memaddr=6293992, myaddr=0x7fffffffca60 "\200\316\377\377\377\177", len=4) at ../../src/gdb/corefile.c:223 #4 0x00000000006784d1 in dwarf_expr_read_mem (baton=0x7fffffffcd50, buf=0x7fffffffca60 "\200\316\377\377\377\177", addr=6293992, len=4) at ../../src/gdb/dwarf2loc.c:334 #5 0x000000000067645e in execute_stack_op (ctx=0x1409480, op_ptr=0x7fffffffce87 "\237<\005@", op_end=0x7fffffffce88 "<\005@") at ../../src/gdb/dwarf2expr.c:1045 #6 0x0000000000674e29 in dwarf_expr_eval (ctx=0x1409480, addr=0x7fffffffce80 "\003\350\t`", len=8) at ../../src/gdb/dwarf2expr.c:364 #7 0x000000000067c5b2 in dwarf2_evaluate_loc_desc_full (type=0x10876d0, frame=0xd8ecc0, data=0x7fffffffce80 "\003\350\t`", size=8, per_cu=0xf24c40, byte_offset=0) at ../../src/gdb/dwarf2loc.c:2236 #8 0x000000000067cc65 in dwarf2_evaluate_loc_desc (type=0x10876d0, frame=0xd8ecc0, data=0x7fffffffce80 "\003\350\t`", size=8, per_cu=0xf24c40) at ../../src/gdb/dwarf2loc.c:2407 #9 0x000000000067a5d4 in dwarf_entry_parameter_to_value (parameter=0x13a7960, deref_size=18446744073709551615, type=0x10876d0, caller_frame=0xd8ecc0, per_cu=0xf24c40) at ../../src/gdb/dwarf2loc.c:1160 #10 0x000000000067a962 in value_of_dwarf_reg_entry (type=0x10876d0, frame=0xd8de70, kind=CALL_SITE_PARAMETER_DWARF_REG, kind_u=...) at ../../src/gdb/dwarf2loc.c:1310 #11 0x000000000067aaca in value_of_dwarf_block_entry (type=0x10876d0, frame=0xd8de70, block=0xf1c2d4 "Q", block_len=1) at ../../src/gdb/dwarf2loc.c:1363 #12 0x000000000067e7c9 in locexpr_read_variable_at_entry (symbol=0x13a7540, frame=0xd8de70) at ../../src/gdb/dwarf2loc.c:3326 #13 0x00000000005daab6 in read_frame_arg (sym=0x13a7540, frame=0xd8de70, argp=0x7fffffffd0e0, entryargp=0x7fffffffd100) at ../../src/gdb/stack.c:362 #14 0x00000000005db384 in print_frame_args (func=0x13a7470, frame=0xd8de70, num=-1, stream=0xea3890) at ../../src/gdb/stack.c:669 #15 0x00000000005dc338 in print_frame (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC, print_args=1, sal=...) at ../../src/gdb/stack.c:1199 #16 0x00000000005db8ee in print_frame_info (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC, print_args=1) at ../../src/gdb/stack.c:851 #17 0x00000000005da2bb in print_stack_frame (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC) at ../../src/gdb/stack.c:169 #18 0x00000000005de236 in frame_command (level_exp=0x0, from_tty=1) at ../../src/gdb/stack.c:2265 dwarf2_evaluate_loc_desc_full (frame #7) knows to handle NOT_AVAILABLE_ERROR errors, but read_memory always throws a generic error. Presently, only the value machinery knows to handle unavailable memory. We need to push the awareness down to the target_xfer layer, making it return a finer grained error indication. We can only return a generic -1 nowadays, which leaves the upper layers with no clue on why the xfer failed. Use target_xfer_partial directly, rather than propagating the error through target_read_memory so as to get a better address to display in the error message. (target_read_memory & friends build on top of target_read (thus the target_xfer machinery), but turn all errors to EIO, an errno value. I think this is a mistake, and we'd better convert all these to return a target_xfer_error too, but that can be done separately. I looked around a bit over memory_error calls, and the need to handle random errno values, other than the EIOs gdb itself hardcodes, probably comes (only) from deprecated_xfer_memory, which uses errno for error indication, but I didn't look exhaustively. We should really get rid of that...) Tested on x86_64 Fedora 17, native and gdbserver. gdb/ 2013-08-21 Pedro Alves <palves@redhat.com> PR gdb/15871 * corefile.c (target_xfer_memory_error): New function. (memory_error): Defer EIO to target_memory_error. (read_memory): Use target_xfer_partial, and handle finer-grained target xfer errors. * target.c (memory_xfer_partial_1): If memory is known to be unavailable, return -TARGET_XFER_E_UNAVAILABLE instead of -1. (target_xfer_partial): Make extern. * target.h (enum target_xfer_error): New. (target_xfer_partial): Declare. (struct target_ops) <xfer_partial>: Adjust describing comment. gdb/testsuite/ 2013-08-21 Pedro Alves <palves@redhat.com> PR gdb/15871 * gdb.trace/entry-values.exp: Remove kfail. --- gdb/corefile.c | 50 ++++++++++++++++++++++++++------ gdb/target.c | 10 ++----- gdb/target.h | 33 +++++++++++++++++---- gdb/testsuite/gdb.trace/entry-values.exp | 1 - 4 files changed, 71 insertions(+), 23 deletions(-) diff --git a/gdb/corefile.c b/gdb/corefile.c index a86f4b3..23dfcb8 100644 --- a/gdb/corefile.c +++ b/gdb/corefile.c @@ -193,17 +193,38 @@ Use the \"file\" or \"exec-file\" command.")); } \f +/* Report a target xfer memory error by throwing a suitable + exception. */ + +static void +target_xfer_memory_error (enum target_xfer_error err, CORE_ADDR memaddr) +{ + switch (err) + { + case TARGET_XFER_E_IO: + /* Actually, address between memaddr and memaddr + len was out of + bounds. */ + throw_error (MEMORY_ERROR, + _("Cannot access memory at address %s"), + paddress (target_gdbarch (), memaddr)); + case TARGET_XFER_E_UNAVAILABLE: + throw_error (NOT_AVAILABLE_ERROR, + _("Memory at address %s unavailable."), + paddress (target_gdbarch (), memaddr)); + default: + internal_error (__FILE__, __LINE__, + "unhandled target memory error: %s", + plongest (err)); + } +} + /* Report a memory error by throwing a MEMORY_ERROR error. */ void memory_error (int status, CORE_ADDR memaddr) { if (status == EIO) - /* Actually, address between memaddr and memaddr + len was out of - bounds. */ - throw_error (MEMORY_ERROR, - _("Cannot access memory at address %s"), - paddress (target_gdbarch (), memaddr)); + target_xfer_memory_error (TARGET_XFER_E_IO, memaddr); else throw_error (MEMORY_ERROR, _("Error accessing memory address %s: %s."), @@ -216,11 +237,22 @@ memory_error (int status, CORE_ADDR memaddr) void read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) { - int status; + LONGEST xfered = 0; - status = target_read_memory (memaddr, myaddr, len); - if (status != 0) - memory_error (status, memaddr); + while (xfered < len) + { + LONGEST xfer = target_xfer_partial (current_target.beneath, + TARGET_OBJECT_MEMORY, NULL, + myaddr + xfered, NULL, + memaddr + xfered, len - xfered); + + if (xfer == 0) + target_xfer_memory_error (TARGET_XFER_E_IO, memaddr + xfered); + if (xfer < 0) + target_xfer_memory_error (-xfer, memaddr + xfered); + xfered += xfer; + QUIT; + } } /* Same as target_read_stack, but report an error if can't read. */ diff --git a/gdb/target.c b/gdb/target.c index 377724d..97c8ce3 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -81,12 +81,6 @@ static LONGEST current_xfer_partial (struct target_ops *ops, const gdb_byte *writebuf, ULONGEST offset, LONGEST len); -static LONGEST target_xfer_partial (struct target_ops *ops, - enum target_object object, - const char *annex, - void *readbuf, const void *writebuf, - ULONGEST offset, LONGEST len); - static struct gdbarch *default_thread_architecture (struct target_ops *ops, ptid_t ptid); @@ -1523,7 +1517,7 @@ memory_xfer_partial_1 (struct target_ops *ops, enum target_object object, /* No use trying further, we know some memory starting at MEMADDR isn't available. */ - return -1; + return -TARGET_XFER_E_UNAVAILABLE; } /* Don't try to read more than how much is available, in @@ -1700,7 +1694,7 @@ make_show_memory_breakpoints_cleanup (int show) /* For docs see target.h, to_xfer_partial. */ -static LONGEST +LONGEST target_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, void *readbuf, const void *writebuf, diff --git a/gdb/target.h b/gdb/target.h index d538e02..a3a4cfd 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -199,6 +199,20 @@ enum target_object /* Possible future objects: TARGET_OBJECT_FILE, ... */ }; +/* Possible error codes returned by target_xfer_partial, etc. */ + +enum target_xfer_error +{ + /* Generic I/O error. Note that it's important this is '1', as we + still have target_xfer-related code returning hardcoded "-1" on + error. */ + TARGET_XFER_E_IO = 1, + + /* Transfer failed because the piece of the object requested is + unavailable. */ + TARGET_XFER_E_UNAVAILABLE +}; + /* Enumeration of the kinds of traceframe searches that a target may be able to perform. */ @@ -293,6 +307,14 @@ extern char *target_read_stralloc (struct target_ops *ops, enum target_object object, const char *annex); +/* See target_ops->to_xfer_partial. */ + +extern LONGEST target_xfer_partial (struct target_ops *ops, + enum target_object object, + const char *annex, + void *readbuf, const void *writebuf, + ULONGEST offset, LONGEST len); + /* Wrappers to target read/write that perform memory transfers. They throw an error if the memory transfer fails. @@ -475,11 +497,12 @@ struct target_ops data-specific information to the target. Return the number of bytes actually transfered, zero when no - further transfer is possible, and -1 when the transfer is not - supported. Return of a positive value smaller than LEN does - not indicate the end of the object, only the end of the - transfer; higher level code should continue transferring if - desired. This is handled in target.c. + further transfer is possible, and a negative error code + (-TARGET_XFER_ERROR) when the transfer is not supported. + Return of a positive value smaller than LEN does not indicate + the end of the object, only the end of the transfer; higher + level code should continue transferring if desired. This is + handled in target.c. The interface does not support a "retry" mechanism. Instead it assumes that at least one byte will be transfered on each diff --git a/gdb/testsuite/gdb.trace/entry-values.exp b/gdb/testsuite/gdb.trace/entry-values.exp index bfa4f5c..20d06ce 100644 --- a/gdb/testsuite/gdb.trace/entry-values.exp +++ b/gdb/testsuite/gdb.trace/entry-values.exp @@ -265,7 +265,6 @@ gdb_test_no_output "tstop" gdb_test "tfind" "Found trace frame 0, .*" "tfind start" # Since 'global2' is not collected, j@entry is expected to be 'unavailable'. -setup_kfail "gdb/15871" *-*-* gdb_test "bt 1" "#0 .* foo \\(i=\[-\]?$decimal, i@entry=2, j=\[-\]?$decimal, j@entry=<unavailable>\\).*" gdb_test "tfind" "Target failed to find requested trace frame\..*" -- 1.7.11.7 ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly 2013-08-21 14:35 ` [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly Pedro Alves @ 2013-08-21 14:47 ` Mark Kettenis 2013-08-21 15:32 ` Pedro Alves 0 siblings, 1 reply; 31+ messages in thread From: Mark Kettenis @ 2013-08-21 14:47 UTC (permalink / raw) To: palves; +Cc: yao, tromey, gdb-patches > Date: Wed, 21 Aug 2013 15:35:40 +0100 > From: Pedro Alves <palves@redhat.com> > > On 08/13/2013 08:39 AM, Yao Qi wrote: > > However, when I run this test, I find j@entry is something like, > > j@entry=<error reading variable: Cannot access memory at address 0x8049788> > > instead of unavailable. > > > > I don't emit a fail for it because I am not very sure it is expected > > to be "unavailable". I am fine to kfail it. > > > > I looked into a little, and looks reading entry value doesn't use > > value availability-aware API. It is not an easy fix to me. > > I looked into this. Here's a patch. Let me know what you think. I think you should simply define the return codes as negative numbers. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly 2013-08-21 14:47 ` Mark Kettenis @ 2013-08-21 15:32 ` Pedro Alves 2013-08-21 15:43 ` Mark Kettenis 2013-08-22 1:25 ` Yao Qi 0 siblings, 2 replies; 31+ messages in thread From: Pedro Alves @ 2013-08-21 15:32 UTC (permalink / raw) To: Mark Kettenis; +Cc: yao, tromey, gdb-patches On 08/21/2013 03:47 PM, Mark Kettenis wrote: >> Date: Wed, 21 Aug 2013 15:35:40 +0100 >> From: Pedro Alves <palves@redhat.com> >> >> On 08/13/2013 08:39 AM, Yao Qi wrote: >>> However, when I run this test, I find j@entry is something like, >>> j@entry=<error reading variable: Cannot access memory at address 0x8049788> >>> instead of unavailable. >>> >>> I don't emit a fail for it because I am not very sure it is expected >>> to be "unavailable". I am fine to kfail it. >>> >>> I looked into a little, and looks reading entry value doesn't use >>> value availability-aware API. It is not an easy fix to me. >> >> I looked into this. Here's a patch. Let me know what you think. > > I think you should simply define the return codes as negative numbers. I think that's really a matter of taste. But maybe my taste is broken... It's quite common to return "-errno" as error indication. The Linux kernel uses that convention for example. Here's the updated patch. ---------- Subject: [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly In entry-values.exp, we have a test where the entry value of 'j' is unavailable, so it is expected that printing j@entry yields "<unavailable>". However, the actual output is: (gdb) frame #0 0x0000000000400540 in foo (i=0, i@entry=2, j=2, j@entry=<error reading variable: Cannot access memory at address 0x6009e8>) The error is thrown here: #0 throw_it (reason=RETURN_ERROR, error=MEMORY_ERROR, fmt=0x8cd550 "Cannot access memory at address %s", ap=0x7fffffffc8e8) at ../../src/gdb/exceptions.c:373 #1 0x00000000005e2f9c in throw_error (error=MEMORY_ERROR, fmt=0x8cd550 "Cannot access memory at address %s") at ../../src/gdb/exceptions.c:422 #2 0x0000000000673a5f in memory_error (status=5, memaddr=6293992) at ../../src/gdb/corefile.c:204 #3 0x0000000000673aea in read_memory (memaddr=6293992, myaddr=0x7fffffffca60 "\200\316\377\377\377\177", len=4) at ../../src/gdb/corefile.c:223 #4 0x00000000006784d1 in dwarf_expr_read_mem (baton=0x7fffffffcd50, buf=0x7fffffffca60 "\200\316\377\377\377\177", addr=6293992, len=4) at ../../src/gdb/dwarf2loc.c:334 #5 0x000000000067645e in execute_stack_op (ctx=0x1409480, op_ptr=0x7fffffffce87 "\237<\005@", op_end=0x7fffffffce88 "<\005@") at ../../src/gdb/dwarf2expr.c:1045 #6 0x0000000000674e29 in dwarf_expr_eval (ctx=0x1409480, addr=0x7fffffffce80 "\003\350\t`", len=8) at ../../src/gdb/dwarf2expr.c:364 #7 0x000000000067c5b2 in dwarf2_evaluate_loc_desc_full (type=0x10876d0, frame=0xd8ecc0, data=0x7fffffffce80 "\003\350\t`", size=8, per_cu=0xf24c40, byte_offset=0) at ../../src/gdb/dwarf2loc.c:2236 #8 0x000000000067cc65 in dwarf2_evaluate_loc_desc (type=0x10876d0, frame=0xd8ecc0, data=0x7fffffffce80 "\003\350\t`", size=8, per_cu=0xf24c40) at ../../src/gdb/dwarf2loc.c:2407 #9 0x000000000067a5d4 in dwarf_entry_parameter_to_value (parameter=0x13a7960, deref_size=18446744073709551615, type=0x10876d0, caller_frame=0xd8ecc0, per_cu=0xf24c40) at ../../src/gdb/dwarf2loc.c:1160 #10 0x000000000067a962 in value_of_dwarf_reg_entry (type=0x10876d0, frame=0xd8de70, kind=CALL_SITE_PARAMETER_DWARF_REG, kind_u=...) at ../../src/gdb/dwarf2loc.c:1310 #11 0x000000000067aaca in value_of_dwarf_block_entry (type=0x10876d0, frame=0xd8de70, block=0xf1c2d4 "Q", block_len=1) at ../../src/gdb/dwarf2loc.c:1363 #12 0x000000000067e7c9 in locexpr_read_variable_at_entry (symbol=0x13a7540, frame=0xd8de70) at ../../src/gdb/dwarf2loc.c:3326 #13 0x00000000005daab6 in read_frame_arg (sym=0x13a7540, frame=0xd8de70, argp=0x7fffffffd0e0, entryargp=0x7fffffffd100) at ../../src/gdb/stack.c:362 #14 0x00000000005db384 in print_frame_args (func=0x13a7470, frame=0xd8de70, num=-1, stream=0xea3890) at ../../src/gdb/stack.c:669 #15 0x00000000005dc338 in print_frame (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC, print_args=1, sal=...) at ../../src/gdb/stack.c:1199 #16 0x00000000005db8ee in print_frame_info (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC, print_args=1) at ../../src/gdb/stack.c:851 #17 0x00000000005da2bb in print_stack_frame (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC) at ../../src/gdb/stack.c:169 #18 0x00000000005de236 in frame_command (level_exp=0x0, from_tty=1) at ../../src/gdb/stack.c:2265 dwarf2_evaluate_loc_desc_full (frame #7) knows to handle NOT_AVAILABLE_ERROR errors, but read_memory always throws a generic error. Presently, only the value machinery knows to handle unavailable memory. We need to push the awareness down to the target_xfer layer, making it return a finer grained error indication. We can only return a generic -1 nowadays, which leaves the upper layers with no clue on why the xfer failed. Use target_xfer_partial directly, rather than propagating the error through target_read_memory so as to get a better address to display in the error message. (target_read_memory & friends build on top of target_read (thus the target_xfer machinery), but turn all errors to EIO, an errno value. I think this is a mistake, and we'd better convert all these to return a target_xfer_error too, but that can be done separately. I looked around a bit over memory_error calls, and the need to handle random errno values, other than the EIOs gdb itself hardcodes, probably comes (only) from deprecated_xfer_memory, which uses errno for error indication, but I didn't look exhaustively. We should really get rid of that...) Tested on x86_64 Fedora 17, native and gdbserver. gdb/ 2013-08-21 Pedro Alves <palves@redhat.com> PR gdb/15871 * corefile.c (target_xfer_memory_error): New function. (memory_error): Defer EIO to target_memory_error. (read_memory): Use target_xfer_partial, and handle finer-grained target xfer errors. * target.c (memory_xfer_partial_1): If memory is known to be unavailable, return TARGET_XFER_E_UNAVAILABLE instead of -1. (target_xfer_partial): Make extern. * target.h (enum target_xfer_error): New. (target_xfer_partial): Declare. (struct target_ops) <xfer_partial>: Adjust describing comment. gdb/testsuite/ 2013-08-21 Pedro Alves <palves@redhat.com> PR gdb/15871 * gdb.trace/entry-values.exp: Remove kfail. --- gdb/corefile.c | 50 ++++++++++++++++++++++++++------ gdb/target.c | 10 ++----- gdb/target.h | 25 +++++++++++++++- gdb/testsuite/gdb.trace/entry-values.exp | 1 - 4 files changed, 67 insertions(+), 19 deletions(-) diff --git a/gdb/corefile.c b/gdb/corefile.c index a86f4b3..c86c172 100644 --- a/gdb/corefile.c +++ b/gdb/corefile.c @@ -193,17 +193,38 @@ Use the \"file\" or \"exec-file\" command.")); } \f +/* Report a target xfer memory error by throwing a suitable + exception. */ + +static void +target_xfer_memory_error (enum target_xfer_error err, CORE_ADDR memaddr) +{ + switch (err) + { + case TARGET_XFER_E_IO: + /* Actually, address between memaddr and memaddr + len was out of + bounds. */ + throw_error (MEMORY_ERROR, + _("Cannot access memory at address %s"), + paddress (target_gdbarch (), memaddr)); + case TARGET_XFER_E_UNAVAILABLE: + throw_error (NOT_AVAILABLE_ERROR, + _("Memory at address %s unavailable."), + paddress (target_gdbarch (), memaddr)); + default: + internal_error (__FILE__, __LINE__, + "unhandled target xfer memory error: %s", + plongest (err)); + } +} + /* Report a memory error by throwing a MEMORY_ERROR error. */ void memory_error (int status, CORE_ADDR memaddr) { if (status == EIO) - /* Actually, address between memaddr and memaddr + len was out of - bounds. */ - throw_error (MEMORY_ERROR, - _("Cannot access memory at address %s"), - paddress (target_gdbarch (), memaddr)); + target_xfer_memory_error (TARGET_XFER_E_IO, memaddr); else throw_error (MEMORY_ERROR, _("Error accessing memory address %s: %s."), @@ -216,11 +237,22 @@ memory_error (int status, CORE_ADDR memaddr) void read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) { - int status; + LONGEST xfered = 0; - status = target_read_memory (memaddr, myaddr, len); - if (status != 0) - memory_error (status, memaddr); + while (xfered < len) + { + LONGEST xfer = target_xfer_partial (current_target.beneath, + TARGET_OBJECT_MEMORY, NULL, + myaddr + xfered, NULL, + memaddr + xfered, len - xfered); + + if (xfer == 0) + target_xfer_memory_error (TARGET_XFER_E_IO, memaddr + xfered); + if (xfer < 0) + target_xfer_memory_error (xfer, memaddr + xfered); + xfered += xfer; + QUIT; + } } /* Same as target_read_stack, but report an error if can't read. */ diff --git a/gdb/target.c b/gdb/target.c index 377724d..f17e53e 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -81,12 +81,6 @@ static LONGEST current_xfer_partial (struct target_ops *ops, const gdb_byte *writebuf, ULONGEST offset, LONGEST len); -static LONGEST target_xfer_partial (struct target_ops *ops, - enum target_object object, - const char *annex, - void *readbuf, const void *writebuf, - ULONGEST offset, LONGEST len); - static struct gdbarch *default_thread_architecture (struct target_ops *ops, ptid_t ptid); @@ -1523,7 +1517,7 @@ memory_xfer_partial_1 (struct target_ops *ops, enum target_object object, /* No use trying further, we know some memory starting at MEMADDR isn't available. */ - return -1; + return TARGET_XFER_E_UNAVAILABLE; } /* Don't try to read more than how much is available, in @@ -1700,7 +1694,7 @@ make_show_memory_breakpoints_cleanup (int show) /* For docs see target.h, to_xfer_partial. */ -static LONGEST +LONGEST target_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, void *readbuf, const void *writebuf, diff --git a/gdb/target.h b/gdb/target.h index d538e02..64a8b0f 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -199,6 +199,20 @@ enum target_object /* Possible future objects: TARGET_OBJECT_FILE, ... */ }; +/* Possible error codes returned by target_xfer_partial, etc. */ + +enum target_xfer_error +{ + /* Generic I/O error. Note that it's important that this is '-1', + as we still have target_xfer-related code returning hardcoded + '-1' on error. */ + TARGET_XFER_E_IO = -1, + + /* Transfer failed because the piece of the object requested is + unavailable. */ + TARGET_XFER_E_UNAVAILABLE = -2 +}; + /* Enumeration of the kinds of traceframe searches that a target may be able to perform. */ @@ -293,6 +307,14 @@ extern char *target_read_stralloc (struct target_ops *ops, enum target_object object, const char *annex); +/* See target_ops->to_xfer_partial. */ + +extern LONGEST target_xfer_partial (struct target_ops *ops, + enum target_object object, + const char *annex, + void *readbuf, const void *writebuf, + ULONGEST offset, LONGEST len); + /* Wrappers to target read/write that perform memory transfers. They throw an error if the memory transfer fails. @@ -475,7 +497,8 @@ struct target_ops data-specific information to the target. Return the number of bytes actually transfered, zero when no - further transfer is possible, and -1 when the transfer is not + further transfer is possible, and a negative error code (really + an 'enum target_xfer_error' value) when the transfer is not supported. Return of a positive value smaller than LEN does not indicate the end of the object, only the end of the transfer; higher level code should continue transferring if diff --git a/gdb/testsuite/gdb.trace/entry-values.exp b/gdb/testsuite/gdb.trace/entry-values.exp index bfa4f5c..20d06ce 100644 --- a/gdb/testsuite/gdb.trace/entry-values.exp +++ b/gdb/testsuite/gdb.trace/entry-values.exp @@ -265,7 +265,6 @@ gdb_test_no_output "tstop" gdb_test "tfind" "Found trace frame 0, .*" "tfind start" # Since 'global2' is not collected, j@entry is expected to be 'unavailable'. -setup_kfail "gdb/15871" *-*-* gdb_test "bt 1" "#0 .* foo \\(i=\[-\]?$decimal, i@entry=2, j=\[-\]?$decimal, j@entry=<unavailable>\\).*" gdb_test "tfind" "Target failed to find requested trace frame\..*" -- 1.7.11.7 ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly 2013-08-21 15:32 ` Pedro Alves @ 2013-08-21 15:43 ` Mark Kettenis 2013-08-22 1:25 ` Yao Qi 1 sibling, 0 replies; 31+ messages in thread From: Mark Kettenis @ 2013-08-21 15:43 UTC (permalink / raw) To: palves; +Cc: yao, tromey, gdb-patches > Date: Wed, 21 Aug 2013 16:32:21 +0100 > From: Pedro Alves <palves@redhat.com> > > On 08/21/2013 03:47 PM, Mark Kettenis wrote: > >> Date: Wed, 21 Aug 2013 15:35:40 +0100 > >> From: Pedro Alves <palves@redhat.com> > >> > >> On 08/13/2013 08:39 AM, Yao Qi wrote: > >>> However, when I run this test, I find j@entry is something like, > >>> j@entry=<error reading variable: Cannot access memory at address 0x8049788> > >>> instead of unavailable. > >>> > >>> I don't emit a fail for it because I am not very sure it is expected > >>> to be "unavailable". I am fine to kfail it. > >>> > >>> I looked into a little, and looks reading entry value doesn't use > >>> value availability-aware API. It is not an easy fix to me. > >> > >> I looked into this. Here's a patch. Let me know what you think. > > > > I think you should simply define the return codes as negative numbers. > > I think that's really a matter of taste. But maybe my taste is > broken... It's quite common to return "-errno" as error indication. > The Linux kernel uses that convention for example. Yeah. I was tempted to add that you've been exposed to too much Linux kernel programming ;). Anyway, I'd argue it's more than a matter of taste. Even in the little bit of code you used the enum values both with and without a minus sign. That's confusing. Thanks for fixing this. Diff looks reasonable to me. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly 2013-08-21 15:32 ` Pedro Alves 2013-08-21 15:43 ` Mark Kettenis @ 2013-08-22 1:25 ` Yao Qi 2013-08-22 10:04 ` [COMMIT] " Pedro Alves 1 sibling, 1 reply; 31+ messages in thread From: Yao Qi @ 2013-08-22 1:25 UTC (permalink / raw) To: Pedro Alves; +Cc: Mark Kettenis, tromey, gdb-patches On 08/21/2013 11:32 PM, Pedro Alves wrote: > I looked > around a bit over memory_error calls, and the need to handle random > errno values, other than the EIOs gdb itself hardcodes, probably comes > (only) from deprecated_xfer_memory, which uses errno for error Is it in function default_xfer_partial? > indication, but I didn't look exhaustively. We should really get rid > of that...) > What do you mean by "that"? using errno for error indication? > +/* Report a target xfer memory error by throwing a suitable > + exception. */ > + > +static void > +target_xfer_memory_error (enum target_xfer_error err, CORE_ADDR memaddr) > +{ > + switch (err) > + { > + case TARGET_XFER_E_IO: > + /* Actually, address between memaddr and memaddr + len was out of > + bounds. */ This line of comment doesn't make much sense in the context of this function. This patch looks good to me. Please commit it without the change to gdb.trace/entry-values.exp, and I'll update my patch to remove kfail. A suggestion here, IWBN to print the string of 'enum target_xfer_error' in the debugging message at the end of target_xfer_partial. We are print numbers currently. -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 31+ messages in thread
* [COMMIT] Re: [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly 2013-08-22 1:25 ` Yao Qi @ 2013-08-22 10:04 ` Pedro Alves 2013-08-23 1:08 ` Yao Qi 0 siblings, 1 reply; 31+ messages in thread From: Pedro Alves @ 2013-08-22 10:04 UTC (permalink / raw) To: Yao Qi; +Cc: Mark Kettenis, tromey, gdb-patches On 08/22/2013 02:24 AM, Yao Qi wrote: > On 08/21/2013 11:32 PM, Pedro Alves wrote: >> I looked >> around a bit over memory_error calls, and the need to handle random >> errno values, other than the EIOs gdb itself hardcodes, probably comes >> (only) from deprecated_xfer_memory, which uses errno for error > > Is it in function default_xfer_partial? Yeah, it's used there, and it seems the actual errno value is just ignored nowadays. Only zero vs non-zero is checked. > >> indication, but I didn't look exhaustively. We should really get rid >> of that...) >> > > What do you mean by "that"? using errno for error indication? I meant deprecated_xfer_memory, which does: 0 means that we can't handle this. If errno has been set, it is the error which prevented us from doing it (FIXME: What about bfd_error?). and using errno values as error indication in target.h methods. E.g., target_read_memory: /* Read LEN bytes of target memory at address MEMADDR, placing the results in GDB's memory at MYADDR. Returns either 0 for success or an errno value if any error occurs. using errno values limits what we can return here. There's no errno for <unavailable>, for example. So, it'd be better if we returned target_xfer_error instead. If we needed to indicate an errno or a bfd error in addition, new TARGET_XFER_E_ERRNO or TARGET_XFER_E_BFD values could be added to target_xfer_error (and the caller would then have to consult errno or bfd_error in addition then). > >> +/* Report a target xfer memory error by throwing a suitable >> + exception. */ >> + >> +static void >> +target_xfer_memory_error (enum target_xfer_error err, CORE_ADDR memaddr) >> +{ >> + switch (err) >> + { >> + case TARGET_XFER_E_IO: >> + /* Actually, address between memaddr and memaddr + len was out of >> + bounds. */ > > This line of comment doesn't make much sense in the context of this > function. I think it makes some sense if you consider the context that the caller always has a length handy. But yeah. This is a preexisting issue though (see memory_error, this new function can be looked at as a refactor). Maybe what we should do is actually pass in the length, and show the range to the user instead of just the first address. Sometimes that info is useful, as it may not be the first address in the requested range that actually is inaccessible. > > This patch looks good to me. Please commit it without the change to > gdb.trace/entry-values.exp, and I'll update my patch to remove kfail. OK, done, as below. > A suggestion here, IWBN to print the string of 'enum target_xfer_error' > in the debugging message at the end of target_xfer_partial. We are > print numbers currently. Done. We now get: internal-error: unhandled target_xfer_error: <unknown> (-3) internal-error: unhandled target_xfer_error: TARGET_XFER_E_UNAVAILABLE (-2) internal-error: unhandled target_xfer_error: TARGET_XFER_E_IO (-1) internal-error: unhandled target_xfer_error: <unknown> (0) internal-error: unhandled target_xfer_error: <unknown> (1) ------- Subject: [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly In entry-values.exp, we have a test where the entry value of 'j' is unavailable, so it is expected that printing j@entry yields "<unavailable>". However, the actual output is: (gdb) frame #0 0x0000000000400540 in foo (i=0, i@entry=2, j=2, j@entry=<error reading variable: Cannot access memory at address 0x6009e8>) The error is thrown here: #0 throw_it (reason=RETURN_ERROR, error=MEMORY_ERROR, fmt=0x8cd550 "Cannot access memory at address %s", ap=0x7fffffffc8e8) at ../../src/gdb/exceptions.c:373 #1 0x00000000005e2f9c in throw_error (error=MEMORY_ERROR, fmt=0x8cd550 "Cannot access memory at address %s") at ../../src/gdb/exceptions.c:422 #2 0x0000000000673a5f in memory_error (status=5, memaddr=6293992) at ../../src/gdb/corefile.c:204 #3 0x0000000000673aea in read_memory (memaddr=6293992, myaddr=0x7fffffffca60 "\200\316\377\377\377\177", len=4) at ../../src/gdb/corefile.c:223 #4 0x00000000006784d1 in dwarf_expr_read_mem (baton=0x7fffffffcd50, buf=0x7fffffffca60 "\200\316\377\377\377\177", addr=6293992, len=4) at ../../src/gdb/dwarf2loc.c:334 #5 0x000000000067645e in execute_stack_op (ctx=0x1409480, op_ptr=0x7fffffffce87 "\237<\005@", op_end=0x7fffffffce88 "<\005@") at ../../src/gdb/dwarf2expr.c:1045 #6 0x0000000000674e29 in dwarf_expr_eval (ctx=0x1409480, addr=0x7fffffffce80 "\003\350\t`", len=8) at ../../src/gdb/dwarf2expr.c:364 #7 0x000000000067c5b2 in dwarf2_evaluate_loc_desc_full (type=0x10876d0, frame=0xd8ecc0, data=0x7fffffffce80 "\003\350\t`", size=8, per_cu=0xf24c40, byte_offset=0) at ../../src/gdb/dwarf2loc.c:2236 #8 0x000000000067cc65 in dwarf2_evaluate_loc_desc (type=0x10876d0, frame=0xd8ecc0, data=0x7fffffffce80 "\003\350\t`", size=8, per_cu=0xf24c40) at ../../src/gdb/dwarf2loc.c:2407 #9 0x000000000067a5d4 in dwarf_entry_parameter_to_value (parameter=0x13a7960, deref_size=18446744073709551615, type=0x10876d0, caller_frame=0xd8ecc0, per_cu=0xf24c40) at ../../src/gdb/dwarf2loc.c:1160 #10 0x000000000067a962 in value_of_dwarf_reg_entry (type=0x10876d0, frame=0xd8de70, kind=CALL_SITE_PARAMETER_DWARF_REG, kind_u=...) at ../../src/gdb/dwarf2loc.c:1310 #11 0x000000000067aaca in value_of_dwarf_block_entry (type=0x10876d0, frame=0xd8de70, block=0xf1c2d4 "Q", block_len=1) at ../../src/gdb/dwarf2loc.c:1363 #12 0x000000000067e7c9 in locexpr_read_variable_at_entry (symbol=0x13a7540, frame=0xd8de70) at ../../src/gdb/dwarf2loc.c:3326 #13 0x00000000005daab6 in read_frame_arg (sym=0x13a7540, frame=0xd8de70, argp=0x7fffffffd0e0, entryargp=0x7fffffffd100) at ../../src/gdb/stack.c:362 #14 0x00000000005db384 in print_frame_args (func=0x13a7470, frame=0xd8de70, num=-1, stream=0xea3890) at ../../src/gdb/stack.c:669 #15 0x00000000005dc338 in print_frame (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC, print_args=1, sal=...) at ../../src/gdb/stack.c:1199 #16 0x00000000005db8ee in print_frame_info (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC, print_args=1) at ../../src/gdb/stack.c:851 #17 0x00000000005da2bb in print_stack_frame (frame=0xd8de70, print_level=1, print_what=SRC_AND_LOC) at ../../src/gdb/stack.c:169 #18 0x00000000005de236 in frame_command (level_exp=0x0, from_tty=1) at ../../src/gdb/stack.c:2265 dwarf2_evaluate_loc_desc_full (frame #7) knows to handle NOT_AVAILABLE_ERROR errors, but read_memory always throws a generic error. Presently, only the value machinery knows to handle unavailable memory. We need to push the awareness down to the target_xfer layer, making it return a finer grained error indication. We can only return a generic -1 nowadays, which leaves the upper layers with no clue on why the xfer failed. Use target_xfer_partial directly, rather than propagating the error through target_read_memory so as to get a better address to display in the error message. (target_read_memory & friends build on top of target_read (thus the target_xfer machinery), but turn all errors to EIO, an errno value. I think this is a mistake, and we'd better convert all these to return a target_xfer_error too, but that can be done separately. I looked around a bit over memory_error calls, and the need to handle random errno values, other than the EIOs gdb itself hardcodes, probably comes (only) from deprecated_xfer_memory, which uses errno for error indication, but I didn't look exhaustively. We should really get rid of deprecated_xfer_memory and of passing down errno values as error indication in target_read & friends methods). Tested on x86_64 Fedora 17, native and gdbserver. Fixes the test in the PR, which will be added to the testsuite later. gdb/ 2013-08-22 Pedro Alves <palves@redhat.com> PR gdb/15871 * corefile.c (target_xfer_memory_error): New function. (memory_error): Defer EIO to target_memory_error. (read_memory): Use target_xfer_partial, and handle finer-grained target xfer errors. * target.c (target_xfer_error_to_string): New function. (memory_xfer_partial_1): If memory is known to be unavailable, return TARGET_XFER_E_UNAVAILABLE instead of -1. (target_xfer_partial): Make extern. * target.h (enum target_xfer_error): New enum. (target_xfer_error_to_string): Declare function. (target_xfer_partial): Declare function. (struct target_ops) <xfer_partial>: Adjust describing comment. --- gdb/corefile.c | 51 ++++++++++++++++++++++++++++++++++++++++++--------- gdb/target.c | 25 +++++++++++++++++-------- gdb/target.h | 31 ++++++++++++++++++++++++++++++- 3 files changed, 89 insertions(+), 18 deletions(-) diff --git a/gdb/corefile.c b/gdb/corefile.c index a86f4b3..cb7f14e 100644 --- a/gdb/corefile.c +++ b/gdb/corefile.c @@ -193,17 +193,39 @@ Use the \"file\" or \"exec-file\" command.")); } \f +/* Report a target xfer memory error by throwing a suitable + exception. */ + +static void +target_xfer_memory_error (enum target_xfer_error err, CORE_ADDR memaddr) +{ + switch (err) + { + case TARGET_XFER_E_IO: + /* Actually, address between memaddr and memaddr + len was out of + bounds. */ + throw_error (MEMORY_ERROR, + _("Cannot access memory at address %s"), + paddress (target_gdbarch (), memaddr)); + case TARGET_XFER_E_UNAVAILABLE: + throw_error (NOT_AVAILABLE_ERROR, + _("Memory at address %s unavailable."), + paddress (target_gdbarch (), memaddr)); + default: + internal_error (__FILE__, __LINE__, + "unhandled target_xfer_error: %s (%s)", + target_xfer_error_to_string (err), + plongest (err)); + } +} + /* Report a memory error by throwing a MEMORY_ERROR error. */ void memory_error (int status, CORE_ADDR memaddr) { if (status == EIO) - /* Actually, address between memaddr and memaddr + len was out of - bounds. */ - throw_error (MEMORY_ERROR, - _("Cannot access memory at address %s"), - paddress (target_gdbarch (), memaddr)); + target_xfer_memory_error (TARGET_XFER_E_IO, memaddr); else throw_error (MEMORY_ERROR, _("Error accessing memory address %s: %s."), @@ -216,11 +238,22 @@ memory_error (int status, CORE_ADDR memaddr) void read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) { - int status; + LONGEST xfered = 0; - status = target_read_memory (memaddr, myaddr, len); - if (status != 0) - memory_error (status, memaddr); + while (xfered < len) + { + LONGEST xfer = target_xfer_partial (current_target.beneath, + TARGET_OBJECT_MEMORY, NULL, + myaddr + xfered, NULL, + memaddr + xfered, len - xfered); + + if (xfer == 0) + target_xfer_memory_error (TARGET_XFER_E_IO, memaddr + xfered); + if (xfer < 0) + target_xfer_memory_error (xfer, memaddr + xfered); + xfered += xfer; + QUIT; + } } /* Same as target_read_stack, but report an error if can't read. */ diff --git a/gdb/target.c b/gdb/target.c index 377724d..f18661b 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -81,12 +81,6 @@ static LONGEST current_xfer_partial (struct target_ops *ops, const gdb_byte *writebuf, ULONGEST offset, LONGEST len); -static LONGEST target_xfer_partial (struct target_ops *ops, - enum target_object object, - const char *annex, - void *readbuf, const void *writebuf, - ULONGEST offset, LONGEST len); - static struct gdbarch *default_thread_architecture (struct target_ops *ops, ptid_t ptid); @@ -1238,6 +1232,21 @@ target_translate_tls_address (struct objfile *objfile, CORE_ADDR offset) return addr; } +const char * +target_xfer_error_to_string (enum target_xfer_error err) +{ +#define CASE(X) case X: return #X + switch (err) + { + CASE(TARGET_XFER_E_IO); + CASE(TARGET_XFER_E_UNAVAILABLE); + default: + return "<unknown>"; + } +#undef CASE +}; + + #undef MIN #define MIN(A, B) (((A) <= (B)) ? (A) : (B)) @@ -1523,7 +1532,7 @@ memory_xfer_partial_1 (struct target_ops *ops, enum target_object object, /* No use trying further, we know some memory starting at MEMADDR isn't available. */ - return -1; + return TARGET_XFER_E_UNAVAILABLE; } /* Don't try to read more than how much is available, in @@ -1700,7 +1709,7 @@ make_show_memory_breakpoints_cleanup (int show) /* For docs see target.h, to_xfer_partial. */ -static LONGEST +LONGEST target_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, void *readbuf, const void *writebuf, diff --git a/gdb/target.h b/gdb/target.h index d538e02..6959503 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -199,6 +199,26 @@ enum target_object /* Possible future objects: TARGET_OBJECT_FILE, ... */ }; +/* Possible error codes returned by target_xfer_partial, etc. */ + +enum target_xfer_error +{ + /* Generic I/O error. Note that it's important that this is '-1', + as we still have target_xfer-related code returning hardcoded + '-1' on error. */ + TARGET_XFER_E_IO = -1, + + /* Transfer failed because the piece of the object requested is + unavailable. */ + TARGET_XFER_E_UNAVAILABLE = -2, + + /* Keep list in sync with target_xfer_error_to_string. */ +}; + +/* Return the string form of ERR. */ + +extern const char *target_xfer_error_to_string (enum target_xfer_error err); + /* Enumeration of the kinds of traceframe searches that a target may be able to perform. */ @@ -293,6 +313,14 @@ extern char *target_read_stralloc (struct target_ops *ops, enum target_object object, const char *annex); +/* See target_ops->to_xfer_partial. */ + +extern LONGEST target_xfer_partial (struct target_ops *ops, + enum target_object object, + const char *annex, + void *readbuf, const void *writebuf, + ULONGEST offset, LONGEST len); + /* Wrappers to target read/write that perform memory transfers. They throw an error if the memory transfer fails. @@ -475,7 +503,8 @@ struct target_ops data-specific information to the target. Return the number of bytes actually transfered, zero when no - further transfer is possible, and -1 when the transfer is not + further transfer is possible, and a negative error code (really + an 'enum target_xfer_error' value) when the transfer is not supported. Return of a positive value smaller than LEN does not indicate the end of the object, only the end of the transfer; higher level code should continue transferring if -- 1.7.11.7 ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [COMMIT] Re: [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly 2013-08-22 10:04 ` [COMMIT] " Pedro Alves @ 2013-08-23 1:08 ` Yao Qi 2013-08-23 16:50 ` Pedro Alves 0 siblings, 1 reply; 31+ messages in thread From: Yao Qi @ 2013-08-23 1:08 UTC (permalink / raw) To: Pedro Alves; +Cc: Mark Kettenis, tromey, gdb-patches On 08/22/2013 06:04 PM, Pedro Alves wrote: > I meant deprecated_xfer_memory, which does: > > 0 means that we can't handle this. If errno has been set, it is the > error which prevented us from doing it (FIXME: What about bfd_error?). > > and using errno values as error indication in target.h methods. E.g., > target_read_memory: > > /* Read LEN bytes of target memory at address MEMADDR, placing the results in > GDB's memory at MYADDR. Returns either 0 for success or an errno value > if any error occurs. > > using errno values limits what we can return here. There's no > errno for <unavailable>, for example. So, it'd be better if > we returned target_xfer_error instead. If we needed to indicate > an errno or a bfd error in addition, new TARGET_XFER_E_ERRNO or > TARGET_XFER_E_BFD values could be added to target_xfer_error > (and the caller would then have to consult errno or bfd_error > in addition then). > OK, it is clear to me. I'd like to write this down in section "Internals" in http://sourceware.org/gdb/wiki/ProjectIdeas , let me know what do you think. Use target_xfer_error instead of errno. Some xfer_memory functions (such as target_read_memory and deprecated_xfer_memory) are using errno to indicate any error occurs. This limites what we can return here, because we can't return some GDB-specific errors, such as <unavailable>. If we need to indicate an errno, bfd error for example, a new TARGET_XFER_E_BFD can be added to target_xfer_error. See http://sourceware.org/ml/gdb-patches/2013-08/msg00589.html for more info. >> > >>> >>+/* Report a target xfer memory error by throwing a suitable >>> >>+ exception. */ >>> >>+ >>> >>+static void >>> >>+target_xfer_memory_error (enum target_xfer_error err, CORE_ADDR memaddr) >>> >>+{ >>> >>+ switch (err) >>> >>+ { >>> >>+ case TARGET_XFER_E_IO: >>> >>+ /* Actually, address between memaddr and memaddr + len was out of >>> >>+ bounds. */ >> > >> >This line of comment doesn't make much sense in the context of this >> >function. > I think it makes some sense if you consider the context that the caller > always has a length handy. But yeah. This is a preexisting issue > though (see memory_error, this new function can be looked at as > a refactor). Maybe what we should do is actually pass in the > length, and show the range to the user instead of just the first > address. Sometimes that info is useful, as it may not be the first > address in the requested range that actually is inaccessible. > Yeah, printing the range is useful some times. -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [COMMIT] Re: [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly 2013-08-23 1:08 ` Yao Qi @ 2013-08-23 16:50 ` Pedro Alves 0 siblings, 0 replies; 31+ messages in thread From: Pedro Alves @ 2013-08-23 16:50 UTC (permalink / raw) To: Yao Qi; +Cc: Mark Kettenis, tromey, gdb-patches On 08/23/2013 02:07 AM, Yao Qi wrote: > I'd like to write this down in section "Internals" in > http://sourceware.org/gdb/wiki/ProjectIdeas , let me know what do you think. > > Use target_xfer_error instead of errno. Some xfer_memory functions > (such as target_read_memory and deprecated_xfer_memory) are > using errno to indicate any error occurs. This limites what we can > return here, because we can't return some GDB-specific errors, such as > <unavailable>. If we need to indicate an errno, bfd error for example, > a new TARGET_XFER_E_BFD can be added to target_xfer_error. See > http://sourceware.org/ml/gdb-patches/2013-08/msg00589.html for more info. Thanks, but rather than end up with an incomplete transition, I went ahead and did the legwork: http://sourceware.org/ml/gdb-patches/2013-08/msg00687.html deprecated_xfer_memory should just be eliminated. I've now cleaned up remote.c: http://sourceware.org/ml/gdb-patches/2013-08/msg00668.html A few more to go still ... $ grep "deprecated_xfer_memory.*=" *.c | grep -v target.c darwin-nat.c: darwin_ops->deprecated_xfer_memory = darwin_xfer_memory; gnu-nat.c: t->deprecated_xfer_memory = gnu_xfer_memory; go32-nat.c: go32_ops.deprecated_xfer_memory = go32_xfer_memory; monitor.c: monitor_ops.deprecated_xfer_memory = monitor_xfer_memory; nto-procfs.c: procfs_ops.deprecated_xfer_memory = procfs_xfer_memory; procfs.c: t->deprecated_xfer_memory = procfs_xfer_memory; remote-m32r-sdi.c: m32r_ops.deprecated_xfer_memory = m32r_xfer_memory; remote-mips.c: mips_ops.deprecated_xfer_memory = mips_xfer_memory; remote-sim.c: gdbsim_ops.deprecated_xfer_memory = gdbsim_xfer_inferior_memory; windows-nat.c: windows_ops.deprecated_xfer_memory = windows_xfer_memory; -- Pedro Alves ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC 2/2] Test entry values in trace frame 2013-08-21 6:06 ` Yao Qi 2013-08-21 14:35 ` [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly Pedro Alves @ 2013-08-23 0:32 ` Yao Qi 2013-08-23 17:04 ` Pedro Alves 1 sibling, 1 reply; 31+ messages in thread From: Yao Qi @ 2013-08-23 0:32 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On 08/21/2013 02:05 PM, Yao Qi wrote: > I agree. I opened PR15871http://sourceware.org/bugzilla/show_bug.cgi?id=15871 > > On the other hand, I kfail the test. Pedro fixed this bug. I update the patch to get rid of the kfail. -- Yao (é½å°§) gdb/testsuite: 2013-08-23 Yao Qi <yao@codesourcery.com> * gdb.trace/entry-values.c (end): New (main): Call end. * gdb.trace/entry-values.exp: Load trace-support.exp. Set tracepoint and collect data. Test entry value is unavailable. --- gdb/testsuite/gdb.trace/entry-values.c | 5 +++ gdb/testsuite/gdb.trace/entry-values.exp | 47 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 0 deletions(-) diff --git a/gdb/testsuite/gdb.trace/entry-values.c b/gdb/testsuite/gdb.trace/entry-values.c index 3f98615..e287203 100644 --- a/gdb/testsuite/gdb.trace/entry-values.c +++ b/gdb/testsuite/gdb.trace/entry-values.c @@ -32,6 +32,10 @@ bar (int i) int global1 = 1; int global2 = 2; +static void +end (void) +{} + int main (void) { @@ -41,5 +45,6 @@ main (void) global2++; ret = bar (0); + end (); return ret; } diff --git a/gdb/testsuite/gdb.trace/entry-values.exp b/gdb/testsuite/gdb.trace/entry-values.exp index 0fb060a..bb62e5d 100644 --- a/gdb/testsuite/gdb.trace/entry-values.exp +++ b/gdb/testsuite/gdb.trace/entry-values.exp @@ -230,3 +230,50 @@ gdb_test_sequence "bt" "bt (2)" { "\[\r\n\]#1 .* bar \\(i=<optimized out>, i@entry=<optimized out>\\)" "\[\r\n\]#2 .* main \\(\\)" } + +# Restart GDB and trace. + +clean_restart $binfile + +load_lib "trace-support.exp" + +if ![runto_main] { + fail "Can't run to main to check for trace support" + return -1 +} + +if ![gdb_target_supports_trace] { + unsupported "target does not support trace" + return -1 +} + +gdb_test "trace foo" "Tracepoint $decimal at .*" + +if [is_amd64_regs_target] { + set spreg "\$rsp" +} elseif [is_x86_like_target] { + set spreg "\$esp" +} else { + set spreg "\$sp" +} + +# Collect arguments i and j. Collect 'global1' which is entry value +# of argument i. Don't collect 'global2' to test the entry value of +# argument j. + +gdb_trace_setactions "set action for tracepoint 1" "" \ + "collect i, j, global1, \(\*\(void \*\*\) \($spreg\)\) @ 64" "^$" + +gdb_test_no_output "tstart" + +gdb_breakpoint "end" +gdb_continue_to_breakpoint "end" + +gdb_test_no_output "tstop" + +gdb_test "tfind" "Found trace frame 0, .*" "tfind start" + +# Since 'global2' is not collected, j@entry is expected to be 'unavailable'. +gdb_test "bt 1" "#0 .* foo \\(i=\[-\]?$decimal, i@entry=2, j=\[-\]?$decimal, j@entry=<unavailable>\\).*" + +gdb_test "tfind" "Target failed to find requested trace frame\..*" -- 1.7.7.6 ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC 2/2] Test entry values in trace frame 2013-08-23 0:32 ` [RFC 2/2] Test entry values in trace frame Yao Qi @ 2013-08-23 17:04 ` Pedro Alves 2013-08-23 19:16 ` Tom Tromey 0 siblings, 1 reply; 31+ messages in thread From: Pedro Alves @ 2013-08-23 17:04 UTC (permalink / raw) To: Yao Qi; +Cc: Tom Tromey, gdb-patches On 08/23/2013 01:31 AM, Yao Qi wrote: > On 08/21/2013 02:05 PM, Yao Qi wrote: >> I agree. I opened PR15871http://sourceware.org/bugzilla/show_bug.cgi?id=15871 >> >> On the other hand, I kfail the test. > > Pedro fixed this bug. I update the patch to get rid of the kfail. FAOD, this patch is fine with me, if fine with Tom. -- Pedro Alves ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC 2/2] Test entry values in trace frame 2013-08-23 17:04 ` Pedro Alves @ 2013-08-23 19:16 ` Tom Tromey 2013-08-24 1:56 ` Yao Qi 0 siblings, 1 reply; 31+ messages in thread From: Tom Tromey @ 2013-08-23 19:16 UTC (permalink / raw) To: Pedro Alves; +Cc: Yao Qi, gdb-patches >>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes: Pedro> On 08/23/2013 01:31 AM, Yao Qi wrote: >> On 08/21/2013 02:05 PM, Yao Qi wrote: >>> I agree. I opened >>> PR15871http://sourceware.org/bugzilla/show_bug.cgi?id=15871 >>> >>> On the other hand, I kfail the test. >> >> Pedro fixed this bug. I update the patch to get rid of the kfail. Pedro> FAOD, this patch is fine with me, if fine with Tom. It's ok with me, thanks. Tom ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [RFC 2/2] Test entry values in trace frame 2013-08-23 19:16 ` Tom Tromey @ 2013-08-24 1:56 ` Yao Qi 0 siblings, 0 replies; 31+ messages in thread From: Yao Qi @ 2013-08-24 1:56 UTC (permalink / raw) To: Tom Tromey; +Cc: Pedro Alves, gdb-patches On 08/24/2013 03:16 AM, Tom Tromey wrote: > Pedro> FAOD, this patch is fine with me, if fine with Tom. > > It's ok with me, thanks. Thanks for the review. Patch is committed. -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH 1/2] Test case for entry values. 2013-08-13 7:41 [PATCH 0/2] Test case on entry values Yao Qi 2013-08-13 7:41 ` [RFC 2/2] Test entry values in trace frame Yao Qi @ 2013-08-13 7:41 ` Yao Qi 2013-08-20 17:39 ` Tom Tromey 2013-08-30 14:52 ` Vidya Praveen 1 sibling, 2 replies; 31+ messages in thread From: Yao Qi @ 2013-08-13 7:41 UTC (permalink / raw) To: gdb-patches Hi, This is a test case for "entry-values" in an arch-independent way. The first part of entry-values.exp is to calculate the length of functions and the offset of instruction call in function bar. Then, this test uses Dwarf Assembler to emit some DIEs for "entry-values". 2013-08-13 Yao Qi <yao@codesourcery.com> * lib/dwarf.exp (_location): Handle DW_OP_deref_size. * gdb.trace/entry-values.c: New. * gdb.trace/entry-values.exp: New. --- gdb/testsuite/gdb.trace/entry-values.c | 45 ++++++ gdb/testsuite/gdb.trace/entry-values.exp | 223 ++++++++++++++++++++++++++++++ gdb/testsuite/lib/dwarf.exp | 8 + 3 files changed, 276 insertions(+), 0 deletions(-) create mode 100644 gdb/testsuite/gdb.trace/entry-values.c create mode 100644 gdb/testsuite/gdb.trace/entry-values.exp diff --git a/gdb/testsuite/gdb.trace/entry-values.c b/gdb/testsuite/gdb.trace/entry-values.c new file mode 100644 index 0000000..3f98615 --- /dev/null +++ b/gdb/testsuite/gdb.trace/entry-values.c @@ -0,0 +1,45 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012-2013 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +int +foo (int i, int j) +{ + return 0; +} + +int +bar (int i) +{ + int j = 2; + + return foo (i, j); +} + +int global1 = 1; +int global2 = 2; + +int +main (void) +{ + int ret = 0; + + global1++; + global2++; + ret = bar (0); + + return ret; +} diff --git a/gdb/testsuite/gdb.trace/entry-values.exp b/gdb/testsuite/gdb.trace/entry-values.exp new file mode 100644 index 0000000..ba95e4f --- /dev/null +++ b/gdb/testsuite/gdb.trace/entry-values.exp @@ -0,0 +1,223 @@ +# Copyright 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +standard_testfile .c entry-values-dw.S + +if {[gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \ + object {nodebug}] != ""} { + return -1 +} + +# Start GDB and load object file, compute the function length and +# the offset of branch instruction in function. They are needed +# in the Dwarf Assembler below. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile}1.o + +set foo_length "" + +# Calculate the offset of the last instruction from the beginning. +set test "disassemble foo" +gdb_test_multiple $test $test { + -re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" { + set foo_length $expect_out(1,string) + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + } +} + +# Calculate the size of the last instruction. Single instruction +# shouldn't be longer than 10 bytes. + +set test "disassemble foo+$foo_length,+10" +gdb_test_multiple $test $test { + -re ".*($hex) <foo\\+$foo_length>:\[^\r\n\]+\r\n\[ \]+($hex) .*\.\r\n$gdb_prompt $" { + set start $expect_out(1,string) + set end $expect_out(2,string) + + set foo_length [expr $foo_length + $end - $start] + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + } +} + +set bar_length "" +set bar_call_foo "" + +# Calculate the offset of the last instruction from the beginning. +set test "disassemble bar" +gdb_test_multiple $test $test { + -re ".*$hex <\\+$decimal>:\[ \t\]+call\[^\r\n\]+\r\n\[ \]+$hex <\\+($decimal)>:" { + set bar_call_foo $expect_out(1,string) + exp_continue + } + -re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" { + set bar_length $expect_out(1,string) + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + } +} + +if [string equal $bar_call_foo ""] { + fail "Find the call or branch instruction offset in bar" + # The following test makes no sense if the offset is unknown. We need + # to update the pattern above to match call or branch instruction for + # the target architecture. + return -1 +} + +# Calculate the size of the last instruction. + +set test "disassemble bar+$bar_length,+10" +gdb_test_multiple $test $test { + -re ".*($hex) <bar\\+$bar_length>:\[^\r\n\]+\r\n\[ \]+($hex) .*\.\r\n$gdb_prompt $" { + set start $expect_out(1,string) + set end $expect_out(2,string) + + set bar_length [expr $bar_length + $end - $start] + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + } +} + +gdb_exit + +# Make some DWARF for the test. +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + declare_labels int_label foo_label + global foo_length bar_length bar_call_foo + + cu {addr_size 4} { + compile_unit {{language @DW_LANG_C}} { + int_label: base_type { + {name int} + {encoding @DW_ATE_signed} + {byte_size 4 DW_FORM_sdata} + } + + foo_label: subprogram { + {name foo} + {decl_file 1} + {low_pc foo addr} + {high_pc "foo + $foo_length" addr} + } { + formal_parameter { + {type :$int_label} + {name i} + {location {DW_OP_reg0} SPECIAL_expr} + } + formal_parameter { + {type :$int_label} + {name j} + {location {DW_OP_reg1} SPECIAL_expr} + } + } + + subprogram { + {name bar} + {decl_file 1} + {low_pc bar addr} + {high_pc "bar + $bar_length" addr} + {GNU_all_call_sites 1} + } { + formal_parameter { + {type :$int_label} + {name i} + } + + GNU_call_site { + {low_pc "bar + $bar_call_foo" addr} + {abstract_origin :$foo_label} + } { + # Faked entry values are reference to variables 'global1' + # and 'global2' and faked locations are register 0 and + # register 1. + GNU_call_site_parameter { + {location {DW_OP_reg0} SPECIAL_expr} + {GNU_call_site_value { + addr global1 + deref_size 4 + } SPECIAL_expr} + } + GNU_call_site_parameter { + {location {DW_OP_reg1} SPECIAL_expr} + {GNU_call_site_value { + addr global2 + deref_size 4 + } SPECIAL_expr} + } + } + } + } + } +} + +if {[gdb_compile $asm_file ${binfile}2.o object {nodebug}] != ""} { + return -1 +} + +if {[gdb_compile [list ${binfile}1.o ${binfile}2.o] \ + "${binfile}" executable {}] != ""} { + return -1 +} + +clean_restart ${testfile} + +if ![runto_main] { + fail "Can't run to main" + return -1 +} + +gdb_breakpoint "foo" + +gdb_continue_to_breakpoint "foo" + +gdb_test_no_output "set print entry-values both" + +gdb_test_sequence "bt" "bt" { + "\[\r\n\]#0 .* foo \\(i=[-]?[0-9]+, i@entry=2, j=[-]?[0-9]+, j@entry=3\\)" + "\[\r\n\]#1 .* bar \\(i=<optimized out>, i@entry=<optimized out>\\)" + "\[\r\n\]#2 .* main \\(\\)" +} + +# Update global variables 'global1' and 'global2' and test that the +# entry values are updated too. + +gdb_test_no_output "set var global1=10" +gdb_test_no_output "set var global2=11" + +gdb_test_sequence "bt" "bt" { + "\[\r\n\]#0 .* foo \\(i=[-]?[0-9]+, i@entry=10, j=[-]?[0-9]+, j@entry=11\\)" + "\[\r\n\]#1 .* bar \\(i=<optimized out>, i@entry=<optimized out>\\)" + "\[\r\n\]#2 .* main \\(\\)" +} diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index 5b19bb8..99f4b06 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -667,6 +667,14 @@ namespace eval Dwarf { _op .sleb128 [lindex $line 2] } + DW_OP_deref_size { + if {[llength $line] != 2} { + error "usage: DW_OP_deref_size SIZE" + } + + _op .byte [lindex $line 1] + } + default { if {[llength $line] > 1} { error "Unimplemented: operands in location for $opcode" -- 1.7.7.6 ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-13 7:41 ` [PATCH 1/2] Test case for entry values Yao Qi @ 2013-08-20 17:39 ` Tom Tromey 2013-08-21 5:55 ` Yao Qi 2013-08-30 14:52 ` Vidya Praveen 1 sibling, 1 reply; 31+ messages in thread From: Tom Tromey @ 2013-08-20 17:39 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> This is a test case for "entry-values" in an arch-independent way. The Yao> first part of entry-values.exp is to calculate the length of functions Yao> and the offset of instruction call in function bar. Then, this test Yao> uses Dwarf Assembler to emit some DIEs for "entry-values". Thanks Yao. This is cool. Yao> +# Start GDB and load object file, compute the function length and Yao> +# the offset of branch instruction in function. They are needed Yao> +# in the Dwarf Assembler below. Nice technique! I'll have to use that. Yao> +# Calculate the offset of the last instruction from the beginning. Yao> +set test "disassemble foo" Yao> +gdb_test_multiple $test $test { Yao> + -re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" { Yao> + set foo_length $expect_out(1,string) Yao> + pass $test Yao> + } Yao> + -re ".*$gdb_prompt $" { Yao> + fail $test Yao> + } Yao> +} If this test fails then later on foo_length won't be set. This will yield a Tcl error in the test suite. It's probably better to just bail out here. I think this applies elsewhere too. Yao> + cu {addr_size 4} { Will it still work on x86-64? Tom ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-20 17:39 ` Tom Tromey @ 2013-08-21 5:55 ` Yao Qi 2013-08-21 15:02 ` Tom Tromey 0 siblings, 1 reply; 31+ messages in thread From: Yao Qi @ 2013-08-21 5:55 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On 08/21/2013 01:39 AM, Tom Tromey wrote: > Yao> +# Calculate the offset of the last instruction from the beginning. > Yao> +set test "disassemble foo" > Yao> +gdb_test_multiple $test $test { > Yao> + -re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" { > Yao> + set foo_length $expect_out(1,string) > Yao> + pass $test > Yao> + } > Yao> + -re ".*$gdb_prompt $" { > Yao> + fail $test > Yao> + } > Yao> +} > > If this test fails then later on foo_length won't be set. > This will yield a Tcl error in the test suite. > It's probably better to just bail out here. > > I think this applies elsewhere too. > Fixed. > Yao> + cu {addr_size 4} { > > Will it still work on x86-64? Yes, it works. I didn't use "addr_size 4" at the beginning, but get the following error. gdb/testsuite/gdb.trace/entry-values-dw.S:19: Error: cannot represent relocation type BFD_RELOC_64 gdb/testsuite/gdb.trace/entry-values-dw.S:20: Error: cannot represent relocation type BFD_RELOC_64 I also tried the following stuff, but it seems I can't pass $cu_addr_size correctly to cu. if [is_lp64_target] { set cu_addr_size 8 } else { set cu_addr_size 4 } ... cu {addr_size $cu_addr_size} { Here is the updated patch in which "cu {addr_size 4}" is still used. -- Yao (é½å°§) 2013-08-21 Yao Qi <yao@codesourcery.com> * lib/dwarf.exp (_location): Handle DW_OP_deref_size. * gdb.trace/entry-values.c: New. * gdb.trace/entry-values.exp: New. --- gdb/testsuite/gdb.trace/entry-values.c | 45 ++++++ gdb/testsuite/gdb.trace/entry-values.exp | 232 ++++++++++++++++++++++++++++++ gdb/testsuite/lib/dwarf.exp | 8 + 3 files changed, 285 insertions(+), 0 deletions(-) create mode 100644 gdb/testsuite/gdb.trace/entry-values.c create mode 100644 gdb/testsuite/gdb.trace/entry-values.exp diff --git a/gdb/testsuite/gdb.trace/entry-values.c b/gdb/testsuite/gdb.trace/entry-values.c new file mode 100644 index 0000000..3f98615 --- /dev/null +++ b/gdb/testsuite/gdb.trace/entry-values.c @@ -0,0 +1,45 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012-2013 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +int +foo (int i, int j) +{ + return 0; +} + +int +bar (int i) +{ + int j = 2; + + return foo (i, j); +} + +int global1 = 1; +int global2 = 2; + +int +main (void) +{ + int ret = 0; + + global1++; + global2++; + ret = bar (0); + + return ret; +} diff --git a/gdb/testsuite/gdb.trace/entry-values.exp b/gdb/testsuite/gdb.trace/entry-values.exp new file mode 100644 index 0000000..30db4a6 --- /dev/null +++ b/gdb/testsuite/gdb.trace/entry-values.exp @@ -0,0 +1,232 @@ +# Copyright 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +standard_testfile .c entry-values-dw.S + +if {[gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \ + object {nodebug}] != ""} { + return -1 +} + +# Start GDB and load object file, compute the function length and +# the offset of branch instruction in function. They are needed +# in the Dwarf Assembler below. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile}1.o + +set foo_length "" + +# Calculate the offset of the last instruction from the beginning. +set test "disassemble foo" +gdb_test_multiple $test $test { + -re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" { + set foo_length $expect_out(1,string) + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + # Bail out here, because we can't do the following tests if + # $foo_length is unknown. + return -1 + } +} + +# Calculate the size of the last instruction. Single instruction +# shouldn't be longer than 10 bytes. + +set test "disassemble foo+$foo_length,+10" +gdb_test_multiple $test $test { + -re ".*($hex) <foo\\+$foo_length>:\[^\r\n\]+\r\n\[ \]+($hex) .*\.\r\n$gdb_prompt $" { + set start $expect_out(1,string) + set end $expect_out(2,string) + + set foo_length [expr $foo_length + $end - $start] + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + # Bail out here, because we can't do the following tests if + # $foo_length is unknown. + return -1 + } +} + +set bar_length "" +set bar_call_foo "" + +# Calculate the offset of the last instruction from the beginning. +set test "disassemble bar" +gdb_test_multiple $test $test { + -re ".*$hex <\\+$decimal>:\[ \t\]+call\[^\r\n\]+\r\n\[ \]+$hex <\\+($decimal)>:" { + set bar_call_foo $expect_out(1,string) + exp_continue + } + -re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" { + set bar_length $expect_out(1,string) + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + } +} + +if { [string equal $bar_call_foo ""] || [string equal $bar_length ""] } { + fail "Find the call or branch instruction offset in bar" + # The following test makes no sense if the offset is unknown. We need + # to update the pattern above to match call or branch instruction for + # the target architecture. + return -1 +} + +# Calculate the size of the last instruction. + +set test "disassemble bar+$bar_length,+10" +gdb_test_multiple $test $test { + -re ".*($hex) <bar\\+$bar_length>:\[^\r\n\]+\r\n\[ \]+($hex) .*\.\r\n$gdb_prompt $" { + set start $expect_out(1,string) + set end $expect_out(2,string) + + set bar_length [expr $bar_length + $end - $start] + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + # Bail out here, because we can't do the following tests if + # $bar_length is unknown. + return -1 + } +} + +gdb_exit + +# Make some DWARF for the test. +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + declare_labels int_label foo_label + global foo_length bar_length bar_call_foo + + cu {addr_size 4} { + compile_unit {{language @DW_LANG_C}} { + int_label: base_type { + {name int} + {encoding @DW_ATE_signed} + {byte_size 4 DW_FORM_sdata} + } + + foo_label: subprogram { + {name foo} + {decl_file 1} + {low_pc foo addr} + {high_pc "foo + $foo_length" addr} + } { + formal_parameter { + {type :$int_label} + {name i} + {location {DW_OP_reg0} SPECIAL_expr} + } + formal_parameter { + {type :$int_label} + {name j} + {location {DW_OP_reg1} SPECIAL_expr} + } + } + + subprogram { + {name bar} + {decl_file 1} + {low_pc bar addr} + {high_pc "bar + $bar_length" addr} + {GNU_all_call_sites 1} + } { + formal_parameter { + {type :$int_label} + {name i} + } + + GNU_call_site { + {low_pc "bar + $bar_call_foo" addr} + {abstract_origin :$foo_label} + } { + # Faked entry values are reference to variables 'global1' + # and 'global2' and faked locations are register 0 and + # register 1. + GNU_call_site_parameter { + {location {DW_OP_reg0} SPECIAL_expr} + {GNU_call_site_value { + addr global1 + deref_size 4 + } SPECIAL_expr} + } + GNU_call_site_parameter { + {location {DW_OP_reg1} SPECIAL_expr} + {GNU_call_site_value { + addr global2 + deref_size 4 + } SPECIAL_expr} + } + } + } + } + } +} + +if {[gdb_compile $asm_file ${binfile}2.o object {nodebug}] != ""} { + return -1 +} + +if {[gdb_compile [list ${binfile}1.o ${binfile}2.o] \ + "${binfile}" executable {}] != ""} { + return -1 +} + +clean_restart ${testfile} + +if ![runto_main] { + fail "Can't run to main" + return -1 +} + +gdb_breakpoint "foo" + +gdb_continue_to_breakpoint "foo" + +gdb_test_no_output "set print entry-values both" + +gdb_test_sequence "bt" "bt (1)" { + "\[\r\n\]#0 .* foo \\(i=[-]?[0-9]+, i@entry=2, j=[-]?[0-9]+, j@entry=3\\)" + "\[\r\n\]#1 .* bar \\(i=<optimized out>, i@entry=<optimized out>\\)" + "\[\r\n\]#2 .* main \\(\\)" +} + +# Update global variables 'global1' and 'global2' and test that the +# entry values are updated too. + +gdb_test_no_output "set var global1=10" +gdb_test_no_output "set var global2=11" + +gdb_test_sequence "bt" "bt (2)" { + "\[\r\n\]#0 .* foo \\(i=[-]?[0-9]+, i@entry=10, j=[-]?[0-9]+, j@entry=11\\)" + "\[\r\n\]#1 .* bar \\(i=<optimized out>, i@entry=<optimized out>\\)" + "\[\r\n\]#2 .* main \\(\\)" +} diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index 5b19bb8..99f4b06 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -667,6 +667,14 @@ namespace eval Dwarf { _op .sleb128 [lindex $line 2] } + DW_OP_deref_size { + if {[llength $line] != 2} { + error "usage: DW_OP_deref_size SIZE" + } + + _op .byte [lindex $line 1] + } + default { if {[llength $line] > 1} { error "Unimplemented: operands in location for $opcode" -- 1.7.7.6 ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-21 5:55 ` Yao Qi @ 2013-08-21 15:02 ` Tom Tromey 2013-08-22 0:12 ` Yao Qi 0 siblings, 1 reply; 31+ messages in thread From: Tom Tromey @ 2013-08-21 15:02 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Tom> Will it still work on x86-64? Yao> Yes, it works. Yao> I didn't use "addr_size 4" at the beginning, but get the following Yao> error. Yao> gdb/testsuite/gdb.trace/entry-values-dw.S:19: Error: cannot represent relocation type BFD_RELOC_64 Yao> gdb/testsuite/gdb.trace/entry-values-dw.S:20: Error: cannot represent relocation type BFD_RELOC_64 Jan pointed out that the new "dwz.exp" has this failure. It seems to me that using 32 bit addresses in the DWARF can yield the wrong results for the test. What if the high bits matter? Yao> I also tried the following stuff, but it seems I can't pass Yao> $cu_addr_size correctly to cu. Yao> if [is_lp64_target] { Yao> set cu_addr_size 8 Yao> } else { Yao> set cu_addr_size 4 Yao> } Yao> ... Yao> cu {addr_size $cu_addr_size} { You need to use [list ...] instead. However, what do you think of the appended? It adds a "default" setting for addr_size. This seems to be what we usually want. Tom diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index 5b19bb8..1d3eb03 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -684,8 +684,8 @@ namespace eval Dwarf { # default = 0 (32-bit) # version n - DWARF version number to emit # default = 4 - # addr_size n - the size of addresses, 32 or 64 - # default = 64 + # addr_size n - the size of addresses, 32, 64, or default + # default = default # fission 0|1 - boolean indicating if generating Fission debug info # default = 0 # BODY is Tcl code that emits the DIEs which make up the body of @@ -702,7 +702,7 @@ namespace eval Dwarf { # Establish the defaults. set is_64 0 set _cu_version 4 - set _cu_addr_size 8 + set _cu_addr_size default set fission 0 set section ".debug_info" set _abbrev_section ".debug_abbrev" @@ -716,6 +716,13 @@ namespace eval Dwarf { default { error "unknown option $name" } } } + if {$_cu_addr_size == "default"} { + if {[is_64_target]} { + set _cu_addr_size 8 + } else { + set _cu_addr_size 4 + } + } set _cu_offset_size [expr { $is_64 ? 8 : 4 }] if { $fission } { set section ".debug_info.dwo" @@ -767,8 +774,8 @@ namespace eval Dwarf { # default = 0 (32-bit) # version n - DWARF version number to emit # default = 4 - # addr_size n - the size of addresses, 32 or 64 - # default = 64 + # addr_size n - the size of addresses, 32, 64, or default + # default = default # fission 0|1 - boolean indicating if generating Fission debug info # default = 0 # SIGNATURE is the 64-bit signature of the type. @@ -788,7 +795,7 @@ namespace eval Dwarf { # Establish the defaults. set is_64 0 set _cu_version 4 - set _cu_addr_size 8 + set _cu_addr_size default set fission 0 set section ".debug_types" set _abbrev_section ".debug_abbrev" @@ -802,6 +809,13 @@ namespace eval Dwarf { default { error "unknown option $name" } } } + if {$_cu_addr_size == "default"} { + if {[is_64_target]} { + set _cu_addr_size 8 + } else { + set _cu_addr_size 4 + } + } set _cu_offset_size [expr { $is_64 ? 8 : 4 }] if { $fission } { set section ".debug_types.dwo" diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 1a1fac2..ab41da0 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -1854,6 +1854,34 @@ gdb_caching_proc is_lp64_target { return 1 } +# Return 1 if target has 64 bit addresses. +# This cannot be decided simply from looking at the target string, +# as it might depend on externally passed compiler options like -m64. +gdb_caching_proc is_64_target { + set me "is_64_target" + + set src [standard_temp_file is64[pid].c] + set obj [standard_temp_file is64[pid].o] + + set f [open $src "w"] + puts $f "int function(void) { return 3; }" + puts $f "int dummy\[sizeof (&function) == 8 ? 1 : -1\];" + close $f + + verbose "$me: compiling testfile $src" 2 + set lines [gdb_compile $src $obj object {quiet}] + file delete $src + file delete $obj + + if ![string match "" $lines] then { + verbose "$me: testfile compilation failed, returning 0" 2 + return 0 + } + + verbose "$me: returning 1" 2 + return 1 +} + # Return 1 if target has x86_64 registers - either amd64 or x32. # x32 target identifies as x86_64-*-linux*, therefore it cannot be determined # just from the target string. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-21 15:02 ` Tom Tromey @ 2013-08-22 0:12 ` Yao Qi 2013-08-22 14:05 ` Tom Tromey 0 siblings, 1 reply; 31+ messages in thread From: Yao Qi @ 2013-08-22 0:12 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On 08/21/2013 11:02 PM, Tom Tromey wrote: > However, what do you think of the appended? > It adds a "default" setting for addr_size. This seems to be what we > usually want. Tom, It looks right to me. Please commit, then I can update my patch on top of it. -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-22 0:12 ` Yao Qi @ 2013-08-22 14:05 ` Tom Tromey 2013-08-23 0:27 ` Yao Qi 0 siblings, 1 reply; 31+ messages in thread From: Tom Tromey @ 2013-08-22 14:05 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> On 08/21/2013 11:02 PM, Tom Tromey wrote: >> However, what do you think of the appended? >> It adds a "default" setting for addr_size. This seems to be what we >> usually want. Yao> It looks right to me. Please commit, then I can update my patch on top Yao> of it. It's in now. Tom ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-22 14:05 ` Tom Tromey @ 2013-08-23 0:27 ` Yao Qi 2013-08-23 19:23 ` Tom Tromey 0 siblings, 1 reply; 31+ messages in thread From: Yao Qi @ 2013-08-23 0:27 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On 08/22/2013 10:04 PM, Tom Tromey wrote: >>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: > > Yao> On 08/21/2013 11:02 PM, Tom Tromey wrote: >>> However, what do you think of the appended? >>> It adds a "default" setting for addr_size. This seems to be what we >>> usually want. > > Yao> It looks right to me. Please commit, then I can update my patch on top > Yao> of it. > > It's in now. > Here is the updated patch, without setting "addr_size" in cu. Tested on x86 and x86_64 respectively. -- Yao (é½å°§) 2013-08-23 Yao Qi <yao@codesourcery.com> * lib/dwarf.exp (_location): Handle DW_OP_deref_size. * gdb.trace/entry-values.c: New. * gdb.trace/entry-values.exp: New. --- gdb/testsuite/gdb.trace/entry-values.c | 45 ++++++ gdb/testsuite/gdb.trace/entry-values.exp | 232 ++++++++++++++++++++++++++++++ gdb/testsuite/lib/dwarf.exp | 8 + 3 files changed, 285 insertions(+), 0 deletions(-) create mode 100644 gdb/testsuite/gdb.trace/entry-values.c create mode 100644 gdb/testsuite/gdb.trace/entry-values.exp diff --git a/gdb/testsuite/gdb.trace/entry-values.c b/gdb/testsuite/gdb.trace/entry-values.c new file mode 100644 index 0000000..3f98615 --- /dev/null +++ b/gdb/testsuite/gdb.trace/entry-values.c @@ -0,0 +1,45 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012-2013 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +int +foo (int i, int j) +{ + return 0; +} + +int +bar (int i) +{ + int j = 2; + + return foo (i, j); +} + +int global1 = 1; +int global2 = 2; + +int +main (void) +{ + int ret = 0; + + global1++; + global2++; + ret = bar (0); + + return ret; +} diff --git a/gdb/testsuite/gdb.trace/entry-values.exp b/gdb/testsuite/gdb.trace/entry-values.exp new file mode 100644 index 0000000..0fb060a --- /dev/null +++ b/gdb/testsuite/gdb.trace/entry-values.exp @@ -0,0 +1,232 @@ +# Copyright 2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +standard_testfile .c entry-values-dw.S + +if {[gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \ + object {nodebug}] != ""} { + return -1 +} + +# Start GDB and load object file, compute the function length and +# the offset of branch instruction in function. They are needed +# in the Dwarf Assembler below. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile}1.o + +set foo_length "" + +# Calculate the offset of the last instruction from the beginning. +set test "disassemble foo" +gdb_test_multiple $test $test { + -re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" { + set foo_length $expect_out(1,string) + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + # Bail out here, because we can't do the following tests if + # $foo_length is unknown. + return -1 + } +} + +# Calculate the size of the last instruction. Single instruction +# shouldn't be longer than 10 bytes. + +set test "disassemble foo+$foo_length,+10" +gdb_test_multiple $test $test { + -re ".*($hex) <foo\\+$foo_length>:\[^\r\n\]+\r\n\[ \]+($hex) .*\.\r\n$gdb_prompt $" { + set start $expect_out(1,string) + set end $expect_out(2,string) + + set foo_length [expr $foo_length + $end - $start] + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + # Bail out here, because we can't do the following tests if + # $foo_length is unknown. + return -1 + } +} + +set bar_length "" +set bar_call_foo "" + +# Calculate the offset of the last instruction from the beginning. +set test "disassemble bar" +gdb_test_multiple $test $test { + -re ".*$hex <\\+$decimal>:\[ \t\]+call\[^\r\n\]+\r\n\[ \]+$hex <\\+($decimal)>:" { + set bar_call_foo $expect_out(1,string) + exp_continue + } + -re ".*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" { + set bar_length $expect_out(1,string) + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + } +} + +if { [string equal $bar_call_foo ""] || [string equal $bar_length ""] } { + fail "Find the call or branch instruction offset in bar" + # The following test makes no sense if the offset is unknown. We need + # to update the pattern above to match call or branch instruction for + # the target architecture. + return -1 +} + +# Calculate the size of the last instruction. + +set test "disassemble bar+$bar_length,+10" +gdb_test_multiple $test $test { + -re ".*($hex) <bar\\+$bar_length>:\[^\r\n\]+\r\n\[ \]+($hex) .*\.\r\n$gdb_prompt $" { + set start $expect_out(1,string) + set end $expect_out(2,string) + + set bar_length [expr $bar_length + $end - $start] + pass $test + } + -re ".*$gdb_prompt $" { + fail $test + # Bail out here, because we can't do the following tests if + # $bar_length is unknown. + return -1 + } +} + +gdb_exit + +# Make some DWARF for the test. +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + declare_labels int_label foo_label + global foo_length bar_length bar_call_foo + + cu {} { + compile_unit {{language @DW_LANG_C}} { + int_label: base_type { + {name int} + {encoding @DW_ATE_signed} + {byte_size 4 DW_FORM_sdata} + } + + foo_label: subprogram { + {name foo} + {decl_file 1} + {low_pc foo addr} + {high_pc "foo + $foo_length" addr} + } { + formal_parameter { + {type :$int_label} + {name i} + {location {DW_OP_reg0} SPECIAL_expr} + } + formal_parameter { + {type :$int_label} + {name j} + {location {DW_OP_reg1} SPECIAL_expr} + } + } + + subprogram { + {name bar} + {decl_file 1} + {low_pc bar addr} + {high_pc "bar + $bar_length" addr} + {GNU_all_call_sites 1} + } { + formal_parameter { + {type :$int_label} + {name i} + } + + GNU_call_site { + {low_pc "bar + $bar_call_foo" addr} + {abstract_origin :$foo_label} + } { + # Faked entry values are reference to variables 'global1' + # and 'global2' and faked locations are register 0 and + # register 1. + GNU_call_site_parameter { + {location {DW_OP_reg0} SPECIAL_expr} + {GNU_call_site_value { + addr global1 + deref_size 4 + } SPECIAL_expr} + } + GNU_call_site_parameter { + {location {DW_OP_reg1} SPECIAL_expr} + {GNU_call_site_value { + addr global2 + deref_size 4 + } SPECIAL_expr} + } + } + } + } + } +} + +if {[gdb_compile $asm_file ${binfile}2.o object {nodebug}] != ""} { + return -1 +} + +if {[gdb_compile [list ${binfile}1.o ${binfile}2.o] \ + "${binfile}" executable {}] != ""} { + return -1 +} + +clean_restart ${testfile} + +if ![runto_main] { + fail "Can't run to main" + return -1 +} + +gdb_breakpoint "foo" + +gdb_continue_to_breakpoint "foo" + +gdb_test_no_output "set print entry-values both" + +gdb_test_sequence "bt" "bt (1)" { + "\[\r\n\]#0 .* foo \\(i=[-]?[0-9]+, i@entry=2, j=[-]?[0-9]+, j@entry=3\\)" + "\[\r\n\]#1 .* bar \\(i=<optimized out>, i@entry=<optimized out>\\)" + "\[\r\n\]#2 .* main \\(\\)" +} + +# Update global variables 'global1' and 'global2' and test that the +# entry values are updated too. + +gdb_test_no_output "set var global1=10" +gdb_test_no_output "set var global2=11" + +gdb_test_sequence "bt" "bt (2)" { + "\[\r\n\]#0 .* foo \\(i=[-]?[0-9]+, i@entry=10, j=[-]?[0-9]+, j@entry=11\\)" + "\[\r\n\]#1 .* bar \\(i=<optimized out>, i@entry=<optimized out>\\)" + "\[\r\n\]#2 .* main \\(\\)" +} diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index 1d3eb03..3977384 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -667,6 +667,14 @@ namespace eval Dwarf { _op .sleb128 [lindex $line 2] } + DW_OP_deref_size { + if {[llength $line] != 2} { + error "usage: DW_OP_deref_size SIZE" + } + + _op .byte [lindex $line 1] + } + default { if {[llength $line] > 1} { error "Unimplemented: operands in location for $opcode" -- 1.7.7.6 ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-23 0:27 ` Yao Qi @ 2013-08-23 19:23 ` Tom Tromey 2013-08-24 1:56 ` Yao Qi 0 siblings, 1 reply; 31+ messages in thread From: Tom Tromey @ 2013-08-23 19:23 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches >>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes: Yao> Here is the updated patch, without setting "addr_size" in cu. Yao> Tested on x86 and x86_64 respectively. Yao> 2013-08-23 Yao Qi <yao@codesourcery.com> Yao> * lib/dwarf.exp (_location): Handle DW_OP_deref_size. Yao> * gdb.trace/entry-values.c: New. Yao> * gdb.trace/entry-values.exp: New. Ok. Thanks! Tom ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-23 19:23 ` Tom Tromey @ 2013-08-24 1:56 ` Yao Qi 0 siblings, 0 replies; 31+ messages in thread From: Yao Qi @ 2013-08-24 1:56 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches On 08/24/2013 03:23 AM, Tom Tromey wrote: > Yao> 2013-08-23 Yao Qi<yao@codesourcery.com> > > Yao> * lib/dwarf.exp (_location): Handle DW_OP_deref_size. > Yao> * gdb.trace/entry-values.c: New. > Yao> * gdb.trace/entry-values.exp: New. > > Ok. Thanks! Patch is committed. -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-13 7:41 ` [PATCH 1/2] Test case for entry values Yao Qi 2013-08-20 17:39 ` Tom Tromey @ 2013-08-30 14:52 ` Vidya Praveen 2013-08-30 15:29 ` Vidya Praveen 1 sibling, 1 reply; 31+ messages in thread From: Vidya Praveen @ 2013-08-30 14:52 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches Hi Yao Qi, On 08/13/13 08:39, Yao Qi wrote: [...] > +set bar_length "" > +set bar_call_foo "" > + > +# Calculate the offset of the last instruction from the beginning. > +set test "disassemble bar" > +gdb_test_multiple $test $test { > + -re ".*$hex <\\+$decimal>:\[ \t\]+call\[^\r\n\]+\r\n\[ \]+$hex <\\+($decimal)>:" { If I understand it right, this expects a 'call' instruction. Isn't this target specific? Regards VP ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-30 14:52 ` Vidya Praveen @ 2013-08-30 15:29 ` Vidya Praveen 2013-08-31 0:22 ` Yao Qi 0 siblings, 1 reply; 31+ messages in thread From: Vidya Praveen @ 2013-08-30 15:29 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches On Fri, Aug 30, 2013 at 03:52:38PM +0100, Vidya Praveen wrote: > Hi Yao Qi, > > On 08/13/13 08:39, Yao Qi wrote: > [...] > > +set bar_length "" > > +set bar_call_foo "" > > + > > +# Calculate the offset of the last instruction from the beginning. > > +set test "disassemble bar" > > +gdb_test_multiple $test $test { > > + -re ".*$hex <\\+$decimal>:\[ \t\]+call\[^\r\n\]+\r\n\[ \]+$hex <\\+($decimal)>:" { > > If I understand it right, this expects a 'call' instruction. Isn't this target > specific? Sorry I missed this comment: +if [string equal $bar_call_foo ""] { + fail "Find the call or branch instruction offset in bar" + # The following test makes no sense if the offset is unknown. We need + # to update the pattern above to match call or branch instruction for + # the target architecture. + return -1 +} This test fails for ARM targets as they generate 'bl'. Regards VP ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-30 15:29 ` Vidya Praveen @ 2013-08-31 0:22 ` Yao Qi 2013-09-10 15:30 ` Vidya Praveen 0 siblings, 1 reply; 31+ messages in thread From: Yao Qi @ 2013-08-31 0:22 UTC (permalink / raw) To: Vidya Praveen; +Cc: gdb-patches On 08/30/2013 11:29 PM, Vidya Praveen wrote: > +if [string equal $bar_call_foo ""] { > + fail "Find the call or branch instruction offset in bar" > + # The following test makes no sense if the offset is unknown. We need > + # to update the pattern above to match call or branch instruction for > + # the target architecture. > + return -1 > +} > > This test fails for ARM targets as they generate 'bl'. As the comment said, the pattern can be updated to match instruction 'bl'. I don't know branch instructions of all architectures, but people familiar with one arch probably can add its branch instruction into the pattern without much effort. -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-08-31 0:22 ` Yao Qi @ 2013-09-10 15:30 ` Vidya Praveen 2013-09-10 23:44 ` Yao Qi 0 siblings, 1 reply; 31+ messages in thread From: Vidya Praveen @ 2013-09-10 15:30 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches On Sat, Aug 31, 2013 at 01:21:38AM +0100, Yao Qi wrote: > On 08/30/2013 11:29 PM, Vidya Praveen wrote: > > +if [string equal $bar_call_foo ""] { > > + fail "Find the call or branch instruction offset in bar" > > + # The following test makes no sense if the offset is unknown. We need > > + # to update the pattern above to match call or branch instruction for > > + # the target architecture. > > + return -1 > > +} > > > > This test fails for ARM targets as they generate 'bl'. > > As the comment said, the pattern can be updated to match instruction > 'bl'. I don't know branch instructions of all architectures, but > people familiar with one arch probably can add its branch instruction > into the pattern without much effort. OK. But isn't it better to have the condition (!gdb_target_supports_trace) that checks if the target supports tracing, in the beginning of the test rather than much later? I can modify to use an appropriate regular expression based on the architecture. But I am trying to see the point when the test eventually ends as UNSUPPORTED. Regards VP > > -- > Yao (??????) > ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-09-10 15:30 ` Vidya Praveen @ 2013-09-10 23:44 ` Yao Qi 2013-09-11 13:27 ` Vidya Praveen 0 siblings, 1 reply; 31+ messages in thread From: Yao Qi @ 2013-09-10 23:44 UTC (permalink / raw) To: Vidya Praveen; +Cc: gdb-patches On 09/10/2013 11:30 PM, Vidya Praveen wrote: > OK. But isn't it better to have the condition (!gdb_target_supports_trace) > that checks if the target supports tracing, in the beginning of the test > rather than much later? This part of test is about testing entry values, and the bottom part (added by patch 2/2) is about testing unavailable entry values when examining trace frames. This part is not related to tracing, so we can't use gdb_target_supports_trace to check. See my description in "PATCH 0/2" > Patch 1/2 is to generate dwarf using Dwarf Assembler to test "entry values" > are shown correctly. At this point, gdb.trace/entry-values.exp is still > a dwarf test, nothing to do with trace. Patch 2/2 is to use tracepoint, > to collect data, to test what happen when argument is available and entry > value is not. https://sourceware.org/ml/gdb-patches/2013-08/msg00327.html -- Yao (é½å°§) ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/2] Test case for entry values. 2013-09-10 23:44 ` Yao Qi @ 2013-09-11 13:27 ` Vidya Praveen 0 siblings, 0 replies; 31+ messages in thread From: Vidya Praveen @ 2013-09-11 13:27 UTC (permalink / raw) To: Yao Qi; +Cc: gdb-patches On Wed, Sep 11, 2013 at 12:43:24AM +0100, Yao Qi wrote: > On 09/10/2013 11:30 PM, Vidya Praveen wrote: > > OK. But isn't it better to have the condition (!gdb_target_supports_trace) > > that checks if the target supports tracing, in the beginning of the test > > rather than much later? > > This part of test is about testing entry values, and the bottom part > (added by patch 2/2) is about testing unavailable entry values when > examining trace frames. This part is not related to tracing, so we > can't use gdb_target_supports_trace to check. > > See my description in "PATCH 0/2" > > > Patch 1/2 is to generate dwarf using Dwarf Assembler to test "entry values" > > are shown correctly. At this point, gdb.trace/entry-values.exp is still > > a dwarf test, nothing to do with trace. Patch 2/2 is to use tracepoint, > > to collect data, to test what happen when argument is available and entry > > value is not. > > https://sourceware.org/ml/gdb-patches/2013-08/msg00327.html However, it scans for the 'call' instruction regardless of the target. Though your comment explains it, the test is still target specific. It should check for the target before scanning for 'call' and not assume the $sp for all targets except for those you already check. Regards VP ^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2013-09-11 13:27 UTC | newest] Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2013-08-13 7:41 [PATCH 0/2] Test case on entry values Yao Qi 2013-08-13 7:41 ` [RFC 2/2] Test entry values in trace frame Yao Qi 2013-08-20 17:48 ` Tom Tromey 2013-08-21 6:06 ` Yao Qi 2013-08-21 14:35 ` [PATCH] PR gdb/15871: Unavailable entry value is not shown correctly Pedro Alves 2013-08-21 14:47 ` Mark Kettenis 2013-08-21 15:32 ` Pedro Alves 2013-08-21 15:43 ` Mark Kettenis 2013-08-22 1:25 ` Yao Qi 2013-08-22 10:04 ` [COMMIT] " Pedro Alves 2013-08-23 1:08 ` Yao Qi 2013-08-23 16:50 ` Pedro Alves 2013-08-23 0:32 ` [RFC 2/2] Test entry values in trace frame Yao Qi 2013-08-23 17:04 ` Pedro Alves 2013-08-23 19:16 ` Tom Tromey 2013-08-24 1:56 ` Yao Qi 2013-08-13 7:41 ` [PATCH 1/2] Test case for entry values Yao Qi 2013-08-20 17:39 ` Tom Tromey 2013-08-21 5:55 ` Yao Qi 2013-08-21 15:02 ` Tom Tromey 2013-08-22 0:12 ` Yao Qi 2013-08-22 14:05 ` Tom Tromey 2013-08-23 0:27 ` Yao Qi 2013-08-23 19:23 ` Tom Tromey 2013-08-24 1:56 ` Yao Qi 2013-08-30 14:52 ` Vidya Praveen 2013-08-30 15:29 ` Vidya Praveen 2013-08-31 0:22 ` Yao Qi 2013-09-10 15:30 ` Vidya Praveen 2013-09-10 23:44 ` Yao Qi 2013-09-11 13:27 ` Vidya Praveen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox