mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 20:14:06 +08:00
Easier and more stubborn MI memory read commands.
* mi/mi-cmds.c (mi_cmds): Register data-read-memory-bytes and data-write-memory-bytes. * mi/mi-cmds.h (mi_cmd_data_read_memory_bytes) (mi_cmd_data_write_memory_bytes): New. * mi/mi-main.c (mi_cmd_data_read_memory): Use regular target_read. (mi_cmd_data_read_memory_bytes, mi_cmd_data_write_memory_bytes): New. (mi_cmd_list_features): Add "data-read-memory-bytes" feature. * target.c (target_read_until_error): Remove. (read_whatever_is_readable, free_memory_read_result_vector) (read_memory_robust): New. * target.h (target_read_until_error): Remove. (struct memory_read_result, free_memory_read_result_vector) (read_memory_robust): New.
This commit is contained in:
parent
f608cd77e7
commit
8dedea0203
@ -1,3 +1,22 @@
|
||||
2010-08-13 Vladimir Prus <vladimir@codesourcery.com>
|
||||
|
||||
Easier and more stubborn MI memory read commands.
|
||||
|
||||
* mi/mi-cmds.c (mi_cmds): Register data-read-memory-bytes
|
||||
and data-write-memory-bytes.
|
||||
* mi/mi-cmds.h (mi_cmd_data_read_memory_bytes)
|
||||
(mi_cmd_data_write_memory_bytes): New.
|
||||
* mi/mi-main.c (mi_cmd_data_read_memory): Use regular target_read.
|
||||
(mi_cmd_data_read_memory_bytes, mi_cmd_data_write_memory_bytes):
|
||||
New.
|
||||
(mi_cmd_list_features): Add "data-read-memory-bytes" feature.
|
||||
* target.c (target_read_until_error): Remove.
|
||||
(read_whatever_is_readable, free_memory_read_result_vector)
|
||||
(read_memory_robust): New.
|
||||
* target.h (target_read_until_error): Remove.
|
||||
(struct memory_read_result, free_memory_read_result_vector)
|
||||
(read_memory_robust): New.
|
||||
|
||||
2010-08-13 Hui Zhu <teawater@gmail.com>
|
||||
|
||||
* dwarf2read.c (load_partial_comp_unit): Initialize free_cu_cleanup.
|
||||
|
@ -1,3 +1,8 @@
|
||||
2010-08-13 Vladimir Prus <vladimir@codesourcery.com>
|
||||
|
||||
* gdb.texinfo (GDB/MI Data Manipulation): Document
|
||||
-data-read-memory-raw and -data-write-memory-raw.
|
||||
|
||||
2010-08-11 Tom Tromey <tromey@redhat.com>
|
||||
Phil Muldoon <pmuldoon@redhat.com>
|
||||
|
||||
|
@ -27375,6 +27375,8 @@ don't appear in the actual output):
|
||||
@subheading The @code{-data-read-memory} Command
|
||||
@findex -data-read-memory
|
||||
|
||||
This command is deprecated, use @code{-data-read-memory-bytes} instead.
|
||||
|
||||
@subsubheading Synopsis
|
||||
|
||||
@smallexample
|
||||
@ -27486,6 +27488,128 @@ next-page="0x000013c0",prev-page="0x00001380",memory=[
|
||||
(gdb)
|
||||
@end smallexample
|
||||
|
||||
@subheading The @code{-data-read-memory-bytes} Command
|
||||
@findex -data-read-memory-bytes
|
||||
|
||||
@subsubheading Synopsis
|
||||
|
||||
@smallexample
|
||||
-data-read-memory-bytes [ -o @var{byte-offset} ]
|
||||
@var{address} @var{count}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
where:
|
||||
|
||||
@table @samp
|
||||
@item @var{address}
|
||||
An expression specifying the address of the first memory word to be
|
||||
read. Complex expressions containing embedded white space should be
|
||||
quoted using the C convention.
|
||||
|
||||
@item @var{count}
|
||||
The number of bytes to read. This should be an integer literal.
|
||||
|
||||
@item @var{byte-offset}
|
||||
The offsets in bytes relative to @var{address} at which to start
|
||||
reading. This should be an integer literal. This option is provided
|
||||
so that a frontend is not required to first evaluate address and then
|
||||
perform address arithmetics itself.
|
||||
|
||||
@end table
|
||||
|
||||
This command attempts to read all accessible memory regions in the
|
||||
specified range. First, all regions marked as unreadable in the memory
|
||||
map (if one is defined) will be skipped. @xref{Memory Region
|
||||
Attributes}. Second, @value{GDBN} will attempt to read the remaining
|
||||
regions. For each one, if reading full region results in an errors,
|
||||
@value{GDBN} will try to read a subset of the region.
|
||||
|
||||
In general, every single byte in the region may be readable or not,
|
||||
and the only way to read every readable byte is to try a read at
|
||||
every address, which is not practical. Therefore, @value{GDBN} will
|
||||
attempt to read all accessible bytes at either beginning or the end
|
||||
of the region, using a binary division scheme. This heuristic works
|
||||
well for reading accross a memory map boundary. Note that if a region
|
||||
has a readable range that is neither at the beginning or the end,
|
||||
@value{GDBN} will not read it.
|
||||
|
||||
The result record (@pxref{GDB/MI Result Records}) that is output of
|
||||
the command includes a field named @samp{memory} whose content is a
|
||||
list of tuples. Each tuple represent a successfully read memory block
|
||||
and has the following fields:
|
||||
|
||||
@table @code
|
||||
@item begin
|
||||
The start address of the memory block, as hexadecimal literal.
|
||||
|
||||
@item end
|
||||
The end address of the memory block, as hexadecimal literal.
|
||||
|
||||
@item offset
|
||||
The offset of the memory block, as hexadecimal literal, relative to
|
||||
the start address passed to @code{-data-read-memory-bytes}.
|
||||
|
||||
@item contents
|
||||
The contents of the memory block, in hex.
|
||||
|
||||
@end table
|
||||
|
||||
|
||||
|
||||
@subsubheading @value{GDBN} Command
|
||||
|
||||
The corresponding @value{GDBN} command is @samp{x}.
|
||||
|
||||
@subsubheading Example
|
||||
|
||||
@smallexample
|
||||
(gdb)
|
||||
-data-read-memory-bytes &a 10
|
||||
^done,memory=[@{begin="0xbffff154",offset="0x00000000",
|
||||
end="0xbffff15e",
|
||||
contents="01000000020000000300"@}]
|
||||
(gdb)
|
||||
@end smallexample
|
||||
|
||||
|
||||
@subheading The @code{-data-write-memory-bytes} Command
|
||||
@findex -data-write-memory-bytes
|
||||
|
||||
@subsubheading Synopsis
|
||||
|
||||
@smallexample
|
||||
-data-write-memory-bytes @var{address} @var{contents}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
where:
|
||||
|
||||
@table @samp
|
||||
@item @var{address}
|
||||
An expression specifying the address of the first memory word to be
|
||||
read. Complex expressions containing embedded white space should be
|
||||
quoted using the C convention.
|
||||
|
||||
@item @var{contents}
|
||||
The hex-encoded bytes to write.
|
||||
|
||||
@end table
|
||||
|
||||
@subsubheading @value{GDBN} Command
|
||||
|
||||
There's no corresponding @value{GDBN} command.
|
||||
|
||||
@subsubheading Example
|
||||
|
||||
@smallexample
|
||||
(gdb)
|
||||
-data-write-memory-bytes &a "aabbccdd"
|
||||
^done
|
||||
(gdb)
|
||||
@end smallexample
|
||||
|
||||
|
||||
@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
@node GDB/MI Tracepoint Commands
|
||||
@section @sc{gdb/mi} Tracepoint Commands
|
||||
@ -28824,6 +28948,9 @@ pretty-printing commands, and possible presence of the
|
||||
@samp{display_hint} field in the output of @code{-var-list-children}
|
||||
@item thread-info
|
||||
Indicates presence of the @code{-thread-info} command.
|
||||
@item data-read-memory-bytes
|
||||
Indicates presense of the @code{-data-read-memory-bytes} and the
|
||||
@code{-data-write-memory-bytes} commands.
|
||||
|
||||
@end table
|
||||
|
||||
|
@ -51,7 +51,9 @@ struct mi_cmd mi_cmds[] =
|
||||
{ "data-list-register-names", { NULL, 0 }, mi_cmd_data_list_register_names},
|
||||
{ "data-list-register-values", { NULL, 0 }, mi_cmd_data_list_register_values},
|
||||
{ "data-read-memory", { NULL, 0 }, mi_cmd_data_read_memory},
|
||||
{ "data-read-memory-bytes", { NULL, 0 }, mi_cmd_data_read_memory_bytes},
|
||||
{ "data-write-memory", { NULL, 0 }, mi_cmd_data_write_memory},
|
||||
{ "data-write-memory-bytes", {NULL, 0}, mi_cmd_data_write_memory_bytes},
|
||||
{ "data-write-register-values", { NULL, 0 }, mi_cmd_data_write_register_values},
|
||||
{ "enable-timings", { NULL, 0 }, mi_cmd_enable_timings},
|
||||
{ "enable-pretty-printing", { NULL, 0 }, mi_cmd_enable_pretty_printing},
|
||||
|
@ -47,7 +47,9 @@ extern mi_cmd_argv_ftype mi_cmd_data_list_register_names;
|
||||
extern mi_cmd_argv_ftype mi_cmd_data_list_register_values;
|
||||
extern mi_cmd_argv_ftype mi_cmd_data_list_changed_registers;
|
||||
extern mi_cmd_argv_ftype mi_cmd_data_read_memory;
|
||||
extern mi_cmd_argv_ftype mi_cmd_data_read_memory_bytes;
|
||||
extern mi_cmd_argv_ftype mi_cmd_data_write_memory;
|
||||
extern mi_cmd_argv_ftype mi_cmd_data_write_memory_bytes;
|
||||
extern mi_cmd_argv_ftype mi_cmd_data_write_register_values;
|
||||
extern mi_cmd_argv_ftype mi_cmd_enable_timings;
|
||||
extern mi_cmd_argv_ftype mi_cmd_env_cd;
|
||||
|
127
gdb/mi/mi-main.c
127
gdb/mi/mi-main.c
@ -1352,9 +1352,9 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
|
||||
|
||||
/* Dispatch memory reads to the topmost target, not the flattened
|
||||
current_target. */
|
||||
nr_bytes = target_read_until_error (current_target.beneath,
|
||||
TARGET_OBJECT_MEMORY, NULL, mbuf,
|
||||
addr, total_bytes);
|
||||
nr_bytes = target_read (current_target.beneath,
|
||||
TARGET_OBJECT_MEMORY, NULL, mbuf,
|
||||
addr, total_bytes);
|
||||
if (nr_bytes <= 0)
|
||||
error ("Unable to read memory.");
|
||||
|
||||
@ -1437,6 +1437,88 @@ mi_cmd_data_read_memory (char *command, char **argv, int argc)
|
||||
do_cleanups (cleanups);
|
||||
}
|
||||
|
||||
void
|
||||
mi_cmd_data_read_memory_bytes (char *command, char **argv, int argc)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_current_arch ();
|
||||
struct cleanup *cleanups;
|
||||
CORE_ADDR addr;
|
||||
LONGEST length;
|
||||
memory_read_result_s *read_result;
|
||||
int ix;
|
||||
VEC(memory_read_result_s) *result;
|
||||
long offset = 0;
|
||||
int optind = 0;
|
||||
char *optarg;
|
||||
enum opt
|
||||
{
|
||||
OFFSET_OPT
|
||||
};
|
||||
static struct mi_opt opts[] =
|
||||
{
|
||||
{"o", OFFSET_OPT, 1},
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
while (1)
|
||||
{
|
||||
int opt = mi_getopt ("mi_cmd_data_read_memory_bytes", argc, argv, opts,
|
||||
&optind, &optarg);
|
||||
if (opt < 0)
|
||||
break;
|
||||
switch ((enum opt) opt)
|
||||
{
|
||||
case OFFSET_OPT:
|
||||
offset = atol (optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (argc != 2)
|
||||
error ("Usage: [ -o OFFSET ] ADDR LENGTH.");
|
||||
|
||||
addr = parse_and_eval_address (argv[0]) + offset;
|
||||
length = atol (argv[1]);
|
||||
|
||||
result = read_memory_robust (current_target.beneath, addr, length);
|
||||
|
||||
cleanups = make_cleanup (free_memory_read_result_vector, result);
|
||||
|
||||
if (VEC_length (memory_read_result_s, result) == 0)
|
||||
error ("Unable to read memory.");
|
||||
|
||||
make_cleanup_ui_out_list_begin_end (uiout, "memory");
|
||||
for (ix = 0;
|
||||
VEC_iterate (memory_read_result_s, result, ix, read_result);
|
||||
++ix)
|
||||
{
|
||||
struct cleanup *t = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
|
||||
char *data, *p;
|
||||
int i;
|
||||
|
||||
ui_out_field_core_addr (uiout, "begin", gdbarch, read_result->begin);
|
||||
ui_out_field_core_addr (uiout, "offset", gdbarch, read_result->begin
|
||||
- addr);
|
||||
ui_out_field_core_addr (uiout, "end", gdbarch, read_result->end);
|
||||
|
||||
data = xmalloc ((read_result->end - read_result->begin) * 2 + 1);
|
||||
|
||||
for (i = 0, p = data;
|
||||
i < (read_result->end - read_result->begin);
|
||||
++i, p += 2)
|
||||
{
|
||||
sprintf (p, "%02x", read_result->data[i]);
|
||||
}
|
||||
ui_out_field_string (uiout, "contents", data);
|
||||
xfree (data);
|
||||
do_cleanups (t);
|
||||
}
|
||||
do_cleanups (cleanups);
|
||||
}
|
||||
|
||||
|
||||
/* DATA-MEMORY-WRITE:
|
||||
|
||||
COLUMN_OFFSET: optional argument. Must be preceeded by '-o'. The
|
||||
@ -1523,6 +1605,44 @@ mi_cmd_data_write_memory (char *command, char **argv, int argc)
|
||||
do_cleanups (old_chain);
|
||||
}
|
||||
|
||||
/* DATA-MEMORY-WRITE-RAW:
|
||||
|
||||
ADDR: start address
|
||||
DATA: string of bytes to write at that address. */
|
||||
void
|
||||
mi_cmd_data_write_memory_bytes (char *command, char **argv, int argc)
|
||||
{
|
||||
CORE_ADDR addr;
|
||||
char *cdata;
|
||||
gdb_byte *data;
|
||||
int len, r, i;
|
||||
struct cleanup *back_to;
|
||||
|
||||
if (argc != 2)
|
||||
error ("Usage: ADDR DATA.");
|
||||
|
||||
addr = parse_and_eval_address (argv[0]);
|
||||
cdata = argv[1];
|
||||
len = strlen (cdata)/2;
|
||||
|
||||
data = xmalloc (len);
|
||||
back_to = make_cleanup (xfree, data);
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
int x;
|
||||
sscanf (cdata + i * 2, "%02x", &x);
|
||||
data[i] = (gdb_byte)x;
|
||||
}
|
||||
|
||||
r = target_write_memory (addr, data, len);
|
||||
if (r != 0)
|
||||
error (_("Could not write memory"));
|
||||
|
||||
do_cleanups (back_to);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mi_cmd_enable_timings (char *command, char **argv, int argc)
|
||||
{
|
||||
@ -1557,6 +1677,7 @@ mi_cmd_list_features (char *command, char **argv, int argc)
|
||||
ui_out_field_string (uiout, NULL, "frozen-varobjs");
|
||||
ui_out_field_string (uiout, NULL, "pending-breakpoints");
|
||||
ui_out_field_string (uiout, NULL, "thread-info");
|
||||
ui_out_field_string (uiout, NULL, "data-read-memory-bytes");
|
||||
|
||||
#if HAVE_PYTHON
|
||||
ui_out_field_string (uiout, NULL, "python");
|
||||
|
247
gdb/target.c
247
gdb/target.c
@ -1792,73 +1792,204 @@ target_read (struct target_ops *ops,
|
||||
return len;
|
||||
}
|
||||
|
||||
LONGEST
|
||||
target_read_until_error (struct target_ops *ops,
|
||||
enum target_object object,
|
||||
const char *annex, gdb_byte *buf,
|
||||
ULONGEST offset, LONGEST len)
|
||||
{
|
||||
LONGEST xfered = 0;
|
||||
/** Assuming that the entire [begin, end) range of memory cannot be read,
|
||||
try to read whatever subrange is possible to read.
|
||||
|
||||
The function results, in RESULT, either zero or one memory block.
|
||||
If there's a readable subrange at the beginning, it is completely
|
||||
read and returned. Any further readable subrange will not be read.
|
||||
Otherwise, if there's a readable subrange at the end, it will be
|
||||
completely read and returned. Any readable subranges before it (obviously,
|
||||
not starting at the beginning), will be ignored. In other cases --
|
||||
either no readable subrange, or readable subrange (s) that is neither
|
||||
at the beginning, or end, nothing is returned.
|
||||
|
||||
The purpose of this function is to handle a read across a boundary of
|
||||
accessible memory in a case when memory map is not available. The above
|
||||
restrictions are fine for this case, but will give incorrect results if
|
||||
the memory is 'patchy'. However, supporting 'patchy' memory would require
|
||||
trying to read every single byte, and it seems unacceptable solution.
|
||||
Explicit memory map is recommended for this case -- and
|
||||
target_read_memory_robust will take care of reading multiple ranges then. */
|
||||
|
||||
static void
|
||||
read_whatever_is_readable (struct target_ops *ops, ULONGEST begin, ULONGEST end,
|
||||
VEC(memory_read_result_s) **result)
|
||||
{
|
||||
gdb_byte *buf = xmalloc (end-begin);
|
||||
ULONGEST current_begin = begin;
|
||||
ULONGEST current_end = end;
|
||||
int forward;
|
||||
memory_read_result_s r;
|
||||
|
||||
/* If we previously failed to read 1 byte, nothing can be done here. */
|
||||
if (end - begin <= 1)
|
||||
return;
|
||||
|
||||
/* Check that either first or the last byte is readable, and give up
|
||||
if not. This heuristic is meant to permit reading accessible memory
|
||||
at the boundary of accessible region. */
|
||||
if (target_read_partial (ops, TARGET_OBJECT_MEMORY, NULL,
|
||||
buf, begin, 1) == 1)
|
||||
{
|
||||
forward = 1;
|
||||
++current_begin;
|
||||
}
|
||||
else if (target_read_partial (ops, TARGET_OBJECT_MEMORY, NULL,
|
||||
buf + (end-begin) - 1, end - 1, 1) == 1)
|
||||
{
|
||||
forward = 0;
|
||||
--current_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Loop invariant is that the [current_begin, current_end) was previously
|
||||
found to be not readable as a whole.
|
||||
|
||||
Note loop condition -- if the range has 1 byte, we can't divide the range
|
||||
so there's no point trying further. */
|
||||
while (current_end - current_begin > 1)
|
||||
{
|
||||
ULONGEST first_half_begin, first_half_end;
|
||||
ULONGEST second_half_begin, second_half_end;
|
||||
LONGEST xfer;
|
||||
|
||||
ULONGEST middle = current_begin + (current_end - current_begin)/2;
|
||||
if (forward)
|
||||
{
|
||||
first_half_begin = current_begin;
|
||||
first_half_end = middle;
|
||||
second_half_begin = middle;
|
||||
second_half_end = current_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_half_begin = middle;
|
||||
first_half_end = current_end;
|
||||
second_half_begin = current_begin;
|
||||
second_half_end = middle;
|
||||
}
|
||||
|
||||
xfer = target_read (ops, TARGET_OBJECT_MEMORY, NULL,
|
||||
buf + (first_half_begin - begin),
|
||||
first_half_begin,
|
||||
first_half_end - first_half_begin);
|
||||
|
||||
if (xfer == first_half_end - first_half_begin)
|
||||
{
|
||||
/* This half reads up fine. So, the error must be in the other half. */
|
||||
current_begin = second_half_begin;
|
||||
current_end = second_half_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This half is not readable. Because we've tried one byte, we
|
||||
know some part of this half if actually redable. Go to the next
|
||||
iteration to divide again and try to read.
|
||||
|
||||
We don't handle the other half, because this function only tries
|
||||
to read a single readable subrange. */
|
||||
current_begin = first_half_begin;
|
||||
current_end = first_half_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (forward)
|
||||
{
|
||||
/* The [begin, current_begin) range has been read. */
|
||||
r.begin = begin;
|
||||
r.end = current_begin;
|
||||
r.data = buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The [current_end, end) range has been read. */
|
||||
LONGEST rlen = end - current_end;
|
||||
r.data = xmalloc (rlen);
|
||||
memcpy (r.data, buf + current_end - begin, rlen);
|
||||
r.begin = current_end;
|
||||
r.end = end;
|
||||
xfree (buf);
|
||||
}
|
||||
VEC_safe_push(memory_read_result_s, (*result), &r);
|
||||
}
|
||||
|
||||
void
|
||||
free_memory_read_result_vector (void *x)
|
||||
{
|
||||
VEC(memory_read_result_s) *v = x;
|
||||
memory_read_result_s *current;
|
||||
int ix;
|
||||
|
||||
for (ix = 0; VEC_iterate (memory_read_result_s, v, ix, current); ++ix)
|
||||
{
|
||||
xfree (current->data);
|
||||
}
|
||||
VEC_free (memory_read_result_s, v);
|
||||
}
|
||||
|
||||
VEC(memory_read_result_s) *
|
||||
read_memory_robust (struct target_ops *ops, ULONGEST offset, LONGEST len)
|
||||
{
|
||||
VEC(memory_read_result_s) *result = 0;
|
||||
|
||||
LONGEST xfered = 0;
|
||||
while (xfered < len)
|
||||
{
|
||||
LONGEST xfer = target_read_partial (ops, object, annex,
|
||||
(gdb_byte *) buf + xfered,
|
||||
offset + xfered, len - xfered);
|
||||
struct mem_region *region = lookup_mem_region (offset + xfered);
|
||||
LONGEST rlen;
|
||||
|
||||
/* Call an observer, notifying them of the xfer progress? */
|
||||
if (xfer == 0)
|
||||
return xfered;
|
||||
if (xfer < 0)
|
||||
/* If there is no explicit region, a fake one should be created. */
|
||||
gdb_assert (region);
|
||||
|
||||
if (region->hi == 0)
|
||||
rlen = len - xfered;
|
||||
else
|
||||
rlen = region->hi - offset;
|
||||
|
||||
if (region->attrib.mode == MEM_NONE || region->attrib.mode == MEM_WO)
|
||||
{
|
||||
/* We've got an error. Try to read in smaller blocks. */
|
||||
ULONGEST start = offset + xfered;
|
||||
ULONGEST remaining = len - xfered;
|
||||
ULONGEST half;
|
||||
|
||||
/* If an attempt was made to read a random memory address,
|
||||
it's likely that the very first byte is not accessible.
|
||||
Try reading the first byte, to avoid doing log N tries
|
||||
below. */
|
||||
xfer = target_read_partial (ops, object, annex,
|
||||
(gdb_byte *) buf + xfered, start, 1);
|
||||
if (xfer <= 0)
|
||||
return xfered;
|
||||
start += 1;
|
||||
remaining -= 1;
|
||||
half = remaining/2;
|
||||
|
||||
while (half > 0)
|
||||
{
|
||||
xfer = target_read_partial (ops, object, annex,
|
||||
(gdb_byte *) buf + xfered,
|
||||
start, half);
|
||||
if (xfer == 0)
|
||||
return xfered;
|
||||
if (xfer < 0)
|
||||
{
|
||||
remaining = half;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully read the first half. So, the
|
||||
error must be in the second half. Adjust start and
|
||||
remaining to point at the second half. */
|
||||
xfered += xfer;
|
||||
start += xfer;
|
||||
remaining -= xfer;
|
||||
}
|
||||
half = remaining/2;
|
||||
}
|
||||
|
||||
return xfered;
|
||||
/* Cannot read this region. Note that we can end up here only
|
||||
if the region is explicitly marked inaccessible, or
|
||||
'inaccessible-by-default' is in effect. */
|
||||
xfered += rlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
LONGEST to_read = min (len - xfered, rlen);
|
||||
gdb_byte *buffer = (gdb_byte *)xmalloc (to_read);
|
||||
|
||||
LONGEST xfer = target_read (ops, TARGET_OBJECT_MEMORY, NULL,
|
||||
(gdb_byte *) buffer,
|
||||
offset + xfered, to_read);
|
||||
/* Call an observer, notifying them of the xfer progress? */
|
||||
if (xfer <= 0)
|
||||
{
|
||||
/* Got an error reading full chunk. See if maybe we can read
|
||||
some subrange. */
|
||||
xfree (buffer);
|
||||
read_whatever_is_readable (ops, offset + xfered, offset + xfered + to_read, &result);
|
||||
xfered += to_read;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct memory_read_result r;
|
||||
r.data = buffer;
|
||||
r.begin = offset + xfered;
|
||||
r.end = r.begin + xfer;
|
||||
VEC_safe_push (memory_read_result_s, result, &r);
|
||||
xfered += xfer;
|
||||
}
|
||||
QUIT;
|
||||
}
|
||||
xfered += xfer;
|
||||
QUIT;
|
||||
}
|
||||
return len;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* An alternative to target_write with progress callbacks. */
|
||||
|
||||
LONGEST
|
||||
|
21
gdb/target.h
21
gdb/target.h
@ -299,10 +299,23 @@ extern LONGEST target_read (struct target_ops *ops,
|
||||
const char *annex, gdb_byte *buf,
|
||||
ULONGEST offset, LONGEST len);
|
||||
|
||||
extern LONGEST target_read_until_error (struct target_ops *ops,
|
||||
enum target_object object,
|
||||
const char *annex, gdb_byte *buf,
|
||||
ULONGEST offset, LONGEST len);
|
||||
struct memory_read_result
|
||||
{
|
||||
/* First address that was read. */
|
||||
ULONGEST begin;
|
||||
/* Past-the-end address. */
|
||||
ULONGEST end;
|
||||
/* The data. */
|
||||
gdb_byte *data;
|
||||
};
|
||||
typedef struct memory_read_result memory_read_result_s;
|
||||
DEF_VEC_O(memory_read_result_s);
|
||||
|
||||
extern void free_memory_read_result_vector (void *);
|
||||
|
||||
extern VEC(memory_read_result_s)* read_memory_robust (struct target_ops *ops,
|
||||
ULONGEST offset,
|
||||
LONGEST len);
|
||||
|
||||
extern LONGEST target_write (struct target_ops *ops,
|
||||
enum target_object object,
|
||||
|
Loading…
Reference in New Issue
Block a user