+ 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;
+