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.
This commit is contained in:
Pedro Alves
2013-08-22 10:00:05 +00:00
parent 65fd058fe6
commit 6be7b56e00
4 changed files with 105 additions and 18 deletions

View File

@ -1,3 +1,19 @@
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.
2013-08-22 Alan Modra <amodra@gmail.com> 2013-08-22 Alan Modra <amodra@gmail.com>
* configure.host: Support powerpc64le-linux and powerpcle-linux hosts. * configure.host: Support powerpc64le-linux and powerpcle-linux hosts.

View File

@ -193,17 +193,39 @@ Use the \"file\" or \"exec-file\" command."));
} }
/* 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. */ /* Report a memory error by throwing a MEMORY_ERROR error. */
void void
memory_error (int status, CORE_ADDR memaddr) memory_error (int status, CORE_ADDR memaddr)
{ {
if (status == EIO) if (status == EIO)
/* Actually, address between memaddr and memaddr + len was out of target_xfer_memory_error (TARGET_XFER_E_IO, memaddr);
bounds. */
throw_error (MEMORY_ERROR,
_("Cannot access memory at address %s"),
paddress (target_gdbarch (), memaddr));
else else
throw_error (MEMORY_ERROR, throw_error (MEMORY_ERROR,
_("Error accessing memory address %s: %s."), _("Error accessing memory address %s: %s."),
@ -216,11 +238,22 @@ memory_error (int status, CORE_ADDR memaddr)
void void
read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len)
{ {
int status; LONGEST xfered = 0;
status = target_read_memory (memaddr, myaddr, len); while (xfered < len)
if (status != 0) {
memory_error (status, memaddr); 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. */ /* Same as target_read_stack, but report an error if can't read. */

View File

@ -81,12 +81,6 @@ static LONGEST current_xfer_partial (struct target_ops *ops,
const gdb_byte *writebuf, const gdb_byte *writebuf,
ULONGEST offset, LONGEST len); 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, static struct gdbarch *default_thread_architecture (struct target_ops *ops,
ptid_t ptid); ptid_t ptid);
@ -1238,6 +1232,21 @@ target_translate_tls_address (struct objfile *objfile, CORE_ADDR offset)
return addr; 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 #undef MIN
#define MIN(A, B) (((A) <= (B)) ? (A) : (B)) #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 /* No use trying further, we know some memory starting
at MEMADDR isn't available. */ at MEMADDR isn't available. */
return -1; return TARGET_XFER_E_UNAVAILABLE;
} }
/* Don't try to read more than how much is available, in /* 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. */ /* For docs see target.h, to_xfer_partial. */
static LONGEST LONGEST
target_xfer_partial (struct target_ops *ops, target_xfer_partial (struct target_ops *ops,
enum target_object object, const char *annex, enum target_object object, const char *annex,
void *readbuf, const void *writebuf, void *readbuf, const void *writebuf,

View File

@ -199,6 +199,26 @@ enum target_object
/* Possible future objects: TARGET_OBJECT_FILE, ... */ /* 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 /* Enumeration of the kinds of traceframe searches that a target may
be able to perform. */ be able to perform. */
@ -293,6 +313,14 @@ extern char *target_read_stralloc (struct target_ops *ops,
enum target_object object, enum target_object object,
const char *annex); 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 /* Wrappers to target read/write that perform memory transfers. They
throw an error if the memory transfer fails. throw an error if the memory transfer fails.
@ -475,7 +503,8 @@ struct target_ops
data-specific information to the target. data-specific information to the target.
Return the number of bytes actually transfered, zero when no 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 supported. Return of a positive value smaller than LEN does
not indicate the end of the object, only the end of the not indicate the end of the object, only the end of the
transfer; higher level code should continue transferring if transfer; higher level code should continue transferring if