aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog16
-rw-r--r--gdb/corefile.c51
-rw-r--r--gdb/target.c25
-rw-r--r--gdb/target.h31
4 files changed, 105 insertions, 18 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 8caad2f..55e2337 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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>
* configure.host: Support powerpc64le-linux and powerpcle-linux hosts.
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."));
}
+/* 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