From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8024 invoked by alias); 13 Aug 2010 13:23:17 -0000 Received: (qmail 7990 invoked by uid 22791); 13 Aug 2010 13:23:10 -0000 X-SWARE-Spam-Status: No, hits=-0.6 required=5.0 tests=AWL,BAYES_50,TW_CP,TW_RG,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 13 Aug 2010 13:23:00 +0000 Received: (qmail 9941 invoked from network); 13 Aug 2010 13:22:57 -0000 Received: from unknown (HELO wind.localnet) (vladimir@127.0.0.2) by mail.codesourcery.com with ESMTPA; 13 Aug 2010 13:22:57 -0000 From: Vladimir Prus To: Eli Zaretskii Subject: Re: Better MI memory commands Date: Fri, 13 Aug 2010 13:23:00 -0000 User-Agent: KMail/1.12.2 (Linux/2.6.31-22-generic-pae; KDE/4.3.2; i686; ; ) Cc: gdb-patches@sources.redhat.com References: <201006251232.55281.vladimir@codesourcery.com> <201008121125.02659.vladimir@codesourcery.com> <83d3tnvk2j.fsf@gnu.org> In-Reply-To: <83d3tnvk2j.fsf@gnu.org> MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_ucUZMxyMlmYsL3j" Message-Id: <201008131722.54934.vladimir@codesourcery.com> Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-08/txt/msg00184.txt.bz2 --Boundary-00=_ucUZMxyMlmYsL3j Content-Type: Text/Plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-length: 3869 On Thursday 12 August 2010 21:04:36 Eli Zaretskii wrote: > > From: Vladimir Prus > > Date: Thu, 12 Aug 2010 11:25:02 +0400 > > Cc: gdb-patches@sources.redhat.com > > > > On Wednesday 11 August 2010 22:00:21 Eli Zaretskii wrote: > > > > > > From: Vladimir Prus > > > > Date: Wed, 11 Aug 2010 16:37:49 +0400 > > > > Cc: gdb-patches@sources.redhat.com > > > > > > > > > > +The output of the command has a result record named @samp{memory}, > > > > > ^^^^^^^^^^^^^^^^^^^ > > > > > Perhaps "is a result record"? > > > > > > > > Nope. "result record" is actually a nonterminal in MI grammar, and output > > > > of a command may have result records but is never a result record itself. > > > > > > > > > And what is the importance of naming > > > > > this record `memory'? why is the name important here? > > > > > > > > Because for frontend to access a result record in a command output, it > > > > has to know its name. > > > > > > Then perhaps > > > > > > 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 ... > > > > This is still not accurate. The output of the command is: > > > > - the character sequence "^done" > > - zero, one, or more result results, separated with spaces. > > > > So, it's still an command output that "has" a result record named "memory" > > as opposed to "result record .. is .. output of the command" > > This is a misunderstanding. In the text I suggested, "record that is > output", the "output" part is a verb, not a noun. (I should have said > "output by the command", though.) IOW, the text says that the command > outputs some stuff, and part of that stuff is the result vector with a > field named "memory". > > Saying "output has the result record" is not good English, because the > result record is part of the output, not some attribute of it. > > I could try to be more accurate, if "that is output by the command" is > not good enough, but please note that our current definition of what > exactly is a "result record" is quite vague. In fact, we don't say > what it is at all. For starters, it talks about "result indications": Ouch. I don't think we have "result indications" anywhere else. > In addition to a number of out-of-band notifications, the response to a > @sc{gdb/mi} command includes one of the following result indications: > > @table @code > @findex ^done > @item "^done" [ "," @var{results} ] > The synchronous operation was successful, @code{@var{results}} are the return > values. > > @item "^running" > @findex ^running > This result record is equivalent to @samp{^done}. Historically, it > was output instead of @samp{^done} if the command has resumed the > target. This behaviour is maintained for backward compatibility, but > all frontends should treat @samp{^done} and @samp{^running} > identically and rely on the @samp{*running} output record to determine > which threads are resumed. > > My reading of this is that ^done, ^running, etc. _are_ examples of > result records. By contrast, you say above that a result record is > everything _after_ these indications. This inconsistency is the main > reason why I deliberately left the text I suggested slightly vague. It looks like the grammar disagrees with me -- it say result record is indeed the entire output, which has 'results'. > I'm open to other suggestions, but if we want to be rigorous, we > should be more consistent than we are now regarding what exactly is a > result record. Yeah, this is rather confusing, so I'll use your wording (with 'by') I've checked in the below to CVS. Thanks, -- Vladimir Prus CodeSourcery vladimir@codesourcery.com (650) 331-3385 x722 --Boundary-00=_ucUZMxyMlmYsL3j Content-Type: text/x-patch; charset="UTF-8"; name="bytes.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="bytes.diff" Content-length: 20469 commit c03302295114d6efffd77b6342315b4040e10cac Author: Vladimir Prus Date: Thu Jun 17 20:23:17 2010 +0400 Easier and more stubborn MI memory read commands. gdb/ * 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. gdb/doc * gdb.texinfo (GDB/MI Data Manipulation): Document -data-read-memory-raw and -data-write-memory-raw. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index cbd636f..93008cb 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -26895,6 +26895,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 @@ -27006,6 +27008,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 @@ -28344,6 +28468,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 diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c index 8441e17..a6a884f 100644 --- a/gdb/mi/mi-cmds.c +++ b/gdb/mi/mi-cmds.c @@ -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}, diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h index 5954aef..b357de6 100644 --- a/gdb/mi/mi-cmds.h +++ b/gdb/mi/mi-cmds.h @@ -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; diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 85a3f99..c91c860 100644 --- a/gdb/mi/mi-main.c +++ b/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"); diff --git a/gdb/target.c b/gdb/target.c index 7aa77e6..cf01b6c 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -1751,73 +1751,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) +/** 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) { - LONGEST xfered = 0; + 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); + /* 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) - 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; + /* 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; } - - return xfered; + 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 diff --git a/gdb/target.h b/gdb/target.h index 870a1eb..e0a63ca 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -292,10 +292,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, --Boundary-00=_ucUZMxyMlmYsL3j--